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 "Frame.h" 30#include "GraphicsContext.h" 31#include "PaintInfo.h" 32#include "RenderStyle.h" 33#include "RenderText.h" 34#include "RenderView.h" 35#include "Settings.h" 36 37namespace WebCore { 38 39TextPaintStyle::TextPaintStyle(ColorSpace colorSpace) 40 : colorSpace(colorSpace) 41 , strokeWidth(0) 42#if ENABLE(LETTERPRESS) 43 , useLetterpressEffect(false) 44#endif 45{ 46} 47 48TextPaintStyle::TextPaintStyle(Color color, ColorSpace colorSpace) 49 : colorSpace(colorSpace) 50 , fillColor(color) 51 , strokeColor(color) 52 , strokeWidth(0) 53#if ENABLE(LETTERPRESS) 54 , useLetterpressEffect(false) 55#endif 56{ 57} 58 59static Color adjustColorForVisibilityOnBackground(Color textColor, Color backgroundColor) 60{ 61 int d = differenceSquared(textColor, backgroundColor); 62 // Semi-arbitrarily chose 65025 (255^2) value here after a few tests. 63 if (d > 65025) 64 return textColor; 65 66 int distanceFromWhite = differenceSquared(textColor, Color::white); 67 int distanceFromBlack = differenceSquared(textColor, Color::black); 68 if (distanceFromWhite < distanceFromBlack) 69 return textColor.dark(); 70 71 return textColor.light(); 72} 73 74TextPaintStyle computeTextPaintStyle(const RenderText& renderer, const RenderStyle& lineStyle, const PaintInfo& paintInfo) 75{ 76 TextPaintStyle paintStyle(lineStyle.colorSpace()); 77 78#if ENABLE(LETTERPRESS) 79 paintStyle.useLetterpressEffect = lineStyle.textDecorationsInEffect() & TextDecorationLetterpress; 80#endif 81 paintStyle.strokeWidth = lineStyle.textStrokeWidth(); 82 83 if (paintInfo.forceBlackText()) { 84 paintStyle.fillColor = Color::black; 85 paintStyle.strokeColor = Color::black; 86 paintStyle.emphasisMarkColor = Color::black; 87 return paintStyle; 88 } 89 paintStyle.fillColor = lineStyle.visitedDependentColor(CSSPropertyWebkitTextFillColor); 90 91 bool forceBackgroundToWhite = false; 92 if (renderer.document().printing()) { 93 if (lineStyle.printColorAdjust() == PrintColorAdjustEconomy) 94 forceBackgroundToWhite = true; 95 if (renderer.frame().settings().shouldPrintBackgrounds()) 96 forceBackgroundToWhite = false; 97 } 98 99 // Make the text fill color legible against a white background 100 if (forceBackgroundToWhite) 101 paintStyle.fillColor = adjustColorForVisibilityOnBackground(paintStyle.fillColor, Color::white); 102 103 paintStyle.strokeColor = lineStyle.visitedDependentColor(CSSPropertyWebkitTextStrokeColor); 104 105 // Make the text stroke color legible against a white background 106 if (forceBackgroundToWhite) 107 paintStyle.strokeColor = adjustColorForVisibilityOnBackground(paintStyle.strokeColor, Color::white); 108 109 paintStyle.emphasisMarkColor = lineStyle.visitedDependentColor(CSSPropertyWebkitTextEmphasisColor); 110 111 // Make the text stroke color legible against a white background 112 if (forceBackgroundToWhite) 113 paintStyle.emphasisMarkColor = adjustColorForVisibilityOnBackground(paintStyle.emphasisMarkColor, Color::white); 114 115 return paintStyle; 116} 117 118TextPaintStyle computeTextSelectionPaintStyle(const TextPaintStyle& textPaintStyle, const RenderText& renderer, const RenderStyle& lineStyle, const PaintInfo& paintInfo, bool& paintSelectedTextOnly, bool& paintSelectedTextSeparately, const ShadowData*& selectionShadow) 119{ 120 paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection); 121 paintSelectedTextSeparately = false; 122 selectionShadow = paintInfo.forceBlackText() ? nullptr : lineStyle.textShadow(); 123 124 TextPaintStyle selectionPaintStyle = textPaintStyle; 125 126#if ENABLE(TEXT_SELECTION) 127 Color foreground = paintInfo.forceBlackText() ? Color::black : renderer.selectionForegroundColor(); 128 if (foreground.isValid() && foreground != selectionPaintStyle.fillColor) { 129 if (!paintSelectedTextOnly) 130 paintSelectedTextSeparately = true; 131 selectionPaintStyle.fillColor = foreground; 132 } 133 134 Color emphasisMarkForeground = paintInfo.forceBlackText() ? Color::black : renderer.selectionEmphasisMarkColor(); 135 if (emphasisMarkForeground.isValid() && emphasisMarkForeground != selectionPaintStyle.emphasisMarkColor) { 136 if (!paintSelectedTextOnly) 137 paintSelectedTextSeparately = true; 138 selectionPaintStyle.emphasisMarkColor = emphasisMarkForeground; 139 } 140 141 if (RenderStyle* pseudoStyle = renderer.getCachedPseudoStyle(SELECTION)) { 142 const ShadowData* shadow = paintInfo.forceBlackText() ? 0 : pseudoStyle->textShadow(); 143 if (shadow != selectionShadow) { 144 if (!paintSelectedTextOnly) 145 paintSelectedTextSeparately = true; 146 selectionShadow = shadow; 147 } 148 149 float strokeWidth = pseudoStyle->textStrokeWidth(); 150 if (strokeWidth != selectionPaintStyle.strokeWidth) { 151 if (!paintSelectedTextOnly) 152 paintSelectedTextSeparately = true; 153 selectionPaintStyle.strokeWidth = strokeWidth; 154 } 155 156 Color stroke = paintInfo.forceBlackText() ? Color::black : pseudoStyle->visitedDependentColor(CSSPropertyWebkitTextStrokeColor); 157 if (stroke != selectionPaintStyle.strokeColor) { 158 if (!paintSelectedTextOnly) 159 paintSelectedTextSeparately = true; 160 selectionPaintStyle.strokeColor = stroke; 161 } 162 } 163#else 164 UNUSED_PARAM(renderer); 165 UNUSED_PARAM(lineStyle); 166 UNUSED_PARAM(paintInfo); 167#endif 168 return selectionPaintStyle; 169} 170 171void updateGraphicsContext(GraphicsContext& context, const TextPaintStyle& paintStyle, FillColorType fillColorType) 172{ 173 TextDrawingModeFlags mode = context.textDrawingMode(); 174 TextDrawingModeFlags newMode = mode; 175#if ENABLE(LETTERPRESS) 176 if (paintStyle.useLetterpressEffect) 177 newMode |= TextModeLetterpress; 178 else 179 newMode &= ~TextModeLetterpress; 180#endif 181 if (paintStyle.strokeWidth > 0) 182 newMode |= TextModeStroke; 183 if (mode != newMode) { 184 context.setTextDrawingMode(newMode); 185 mode = newMode; 186 } 187 188 Color fillColor = fillColorType == UseEmphasisMarkColor ? paintStyle.emphasisMarkColor : paintStyle.fillColor; 189 if (mode & TextModeFill && (fillColor != context.fillColor() || paintStyle.colorSpace != context.fillColorSpace())) 190 context.setFillColor(fillColor, paintStyle.colorSpace); 191 192 if (mode & TextModeStroke) { 193 if (paintStyle.strokeColor != context.strokeColor()) 194 context.setStrokeColor(paintStyle.strokeColor, paintStyle.colorSpace); 195 if (paintStyle.strokeWidth != context.strokeThickness()) 196 context.setStrokeThickness(paintStyle.strokeWidth); 197 } 198} 199 200} 201