ebfdec274aa82e12eefded8568c0befe2331a1c2
[WebKit-https.git] / Source / WebCore / rendering / TextPaintStyle.cpp
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "TextPaintStyle.h"
28
29 #include "FocusController.h"
30 #include "Frame.h"
31 #include "GraphicsContext.h"
32 #include "Page.h"
33 #include "PaintInfo.h"
34 #include "RenderStyle.h"
35 #include "RenderText.h"
36 #include "RenderTheme.h"
37 #include "RenderView.h"
38 #include "Settings.h"
39
40 namespace WebCore {
41
42 TextPaintStyle::TextPaintStyle(const Color& color)
43     : fillColor(color)
44     , strokeColor(color)
45 {
46 }
47
48 bool TextPaintStyle::operator==(const TextPaintStyle& other) const
49 {
50     return fillColor == other.fillColor && strokeColor == other.strokeColor && emphasisMarkColor == other.emphasisMarkColor
51         && strokeWidth == other.strokeWidth && paintOrder == other.paintOrder && lineJoin == other.lineJoin
52 #if ENABLE(LETTERPRESS)
53         && useLetterpressEffect == other.useLetterpressEffect
54 #endif
55         && lineCap == other.lineCap && miterLimit == other.miterLimit;
56 }
57
58 bool textColorIsLegibleAgainstBackgroundColor(const Color& textColor, const Color& backgroundColor)
59 {
60     // Semi-arbitrarily chose 65025 (255^2) value here after a few tests.
61     return differenceSquared(textColor, backgroundColor) > 65025;
62 }
63
64 static Color adjustColorForVisibilityOnBackground(const Color& textColor, const Color& backgroundColor)
65 {
66     if (textColorIsLegibleAgainstBackgroundColor(textColor, backgroundColor))
67         return textColor;
68
69     int distanceFromWhite = differenceSquared(textColor, Color::white);
70     int distanceFromBlack = differenceSquared(textColor, Color::black);
71     if (distanceFromWhite < distanceFromBlack)
72         return textColor.dark();
73
74     return textColor.light();
75 }
76
77 TextPaintStyle computeTextPaintStyle(const Frame& frame, const RenderStyle& lineStyle, const PaintInfo& paintInfo)
78 {
79     TextPaintStyle paintStyle;
80
81 #if ENABLE(LETTERPRESS)
82     paintStyle.useLetterpressEffect = lineStyle.textDecorationsInEffect() & TextDecorationLetterpress;
83 #endif
84     auto viewportSize = frame.view() ? frame.view()->size() : IntSize();
85     paintStyle.strokeWidth = lineStyle.computedStrokeWidth(viewportSize);
86     paintStyle.paintOrder = lineStyle.paintOrder();
87     paintStyle.lineJoin = lineStyle.joinStyle();
88     paintStyle.lineCap = lineStyle.capStyle();
89     paintStyle.miterLimit = lineStyle.strokeMiterLimit();
90     
91     if (paintInfo.forceTextColor()) {
92         paintStyle.fillColor = paintInfo.forcedTextColor();
93         paintStyle.strokeColor = paintInfo.forcedTextColor();
94         paintStyle.emphasisMarkColor = paintInfo.forcedTextColor();
95         return paintStyle;
96     }
97
98     if (lineStyle.insideDefaultButton()) {
99         Page* page = frame.page();
100         if (page && page->focusController().isActive()) {
101             OptionSet<StyleColor::Options> options;
102             if (page->useSystemAppearance())
103                 options |= StyleColor::Options::UseSystemAppearance;
104             paintStyle.fillColor = RenderTheme::singleton().systemColor(CSSValueActivebuttontext, options);
105             return paintStyle;
106         }
107     }
108
109     paintStyle.fillColor = lineStyle.visitedDependentColor(CSSPropertyWebkitTextFillColor);
110
111     bool forceBackgroundToWhite = false;
112     if (frame.document() && frame.document()->printing()) {
113         if (lineStyle.printColorAdjust() == PrintColorAdjustEconomy)
114             forceBackgroundToWhite = true;
115         if (frame.settings().shouldPrintBackgrounds())
116             forceBackgroundToWhite = false;
117     }
118
119     // Make the text fill color legible against a white background
120     if (forceBackgroundToWhite)
121         paintStyle.fillColor = adjustColorForVisibilityOnBackground(paintStyle.fillColor, Color::white);
122
123     paintStyle.strokeColor = lineStyle.computedStrokeColor();
124
125     // Make the text stroke color legible against a white background
126     if (forceBackgroundToWhite)
127         paintStyle.strokeColor = adjustColorForVisibilityOnBackground(paintStyle.strokeColor, Color::white);
128
129     paintStyle.emphasisMarkColor = lineStyle.visitedDependentColor(CSSPropertyWebkitTextEmphasisColor);
130
131     // Make the text stroke color legible against a white background
132     if (forceBackgroundToWhite)
133         paintStyle.emphasisMarkColor = adjustColorForVisibilityOnBackground(paintStyle.emphasisMarkColor, Color::white);
134
135     return paintStyle;
136 }
137
138 TextPaintStyle computeTextSelectionPaintStyle(const TextPaintStyle& textPaintStyle, const RenderText& renderer, const RenderStyle& lineStyle, const PaintInfo& paintInfo, std::optional<ShadowData>& selectionShadow)
139 {
140     TextPaintStyle selectionPaintStyle = textPaintStyle;
141
142 #if ENABLE(TEXT_SELECTION)
143     Color foreground = paintInfo.forceTextColor() ? paintInfo.forcedTextColor() : renderer.selectionForegroundColor();
144     if (foreground.isValid() && foreground != selectionPaintStyle.fillColor)
145         selectionPaintStyle.fillColor = foreground;
146
147     Color emphasisMarkForeground = paintInfo.forceTextColor() ? paintInfo.forcedTextColor() : renderer.selectionEmphasisMarkColor();
148     if (emphasisMarkForeground.isValid() && emphasisMarkForeground != selectionPaintStyle.emphasisMarkColor)
149         selectionPaintStyle.emphasisMarkColor = emphasisMarkForeground;
150
151     if (auto pseudoStyle = renderer.selectionPseudoStyle()) {
152         selectionShadow = ShadowData::clone(paintInfo.forceTextColor() ? nullptr : pseudoStyle->textShadow());
153         auto viewportSize = renderer.frame().view() ? renderer.frame().view()->size() : IntSize();
154         float strokeWidth = pseudoStyle->computedStrokeWidth(viewportSize);
155         if (strokeWidth != selectionPaintStyle.strokeWidth)
156             selectionPaintStyle.strokeWidth = strokeWidth;
157
158         Color stroke = paintInfo.forceTextColor() ? paintInfo.forcedTextColor() : pseudoStyle->computedStrokeColor();
159         if (stroke != selectionPaintStyle.strokeColor)
160             selectionPaintStyle.strokeColor = stroke;
161     } else
162         selectionShadow = ShadowData::clone(paintInfo.forceTextColor() ? nullptr : lineStyle.textShadow());
163 #else
164     UNUSED_PARAM(renderer);
165     UNUSED_PARAM(lineStyle);
166     UNUSED_PARAM(paintInfo);
167     selectionShadow = ShadowData::clone(paintInfo.forceTextColor() ? nullptr : lineStyle.textShadow());
168 #endif
169     return selectionPaintStyle;
170 }
171
172 void updateGraphicsContext(GraphicsContext& context, const TextPaintStyle& paintStyle, FillColorType fillColorType)
173 {
174     TextDrawingModeFlags mode = context.textDrawingMode();
175     TextDrawingModeFlags newMode = mode;
176 #if ENABLE(LETTERPRESS)
177     if (paintStyle.useLetterpressEffect)
178         newMode |= TextModeLetterpress;
179     else
180         newMode &= ~TextModeLetterpress;
181 #endif
182     if (paintStyle.strokeWidth > 0 && paintStyle.strokeColor.isVisible())
183         newMode |= TextModeStroke;
184     if (mode != newMode) {
185         context.setTextDrawingMode(newMode);
186         mode = newMode;
187     }
188
189     Color fillColor = fillColorType == UseEmphasisMarkColor ? paintStyle.emphasisMarkColor : paintStyle.fillColor;
190     if (mode & TextModeFill && (fillColor != context.fillColor()))
191         context.setFillColor(fillColor);
192
193     if (mode & TextModeStroke) {
194         if (paintStyle.strokeColor != context.strokeColor())
195             context.setStrokeColor(paintStyle.strokeColor);
196         if (paintStyle.strokeWidth != context.strokeThickness())
197             context.setStrokeThickness(paintStyle.strokeWidth);
198         context.setLineJoin(paintStyle.lineJoin);
199         context.setLineCap(paintStyle.lineCap);
200         if (paintStyle.lineJoin == MiterJoin)
201             context.setMiterLimit(paintStyle.miterLimit);
202     }
203 }
204
205 }