OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "core/paint/InlineTextBoxPainter.h" | 6 #include "core/paint/InlineTextBoxPainter.h" |
7 | 7 |
8 #include "core/editing/CompositionUnderline.h" | 8 #include "core/editing/CompositionUnderline.h" |
9 #include "core/editing/Editor.h" | 9 #include "core/editing/Editor.h" |
10 #include "core/editing/markers/DocumentMarkerController.h" | 10 #include "core/editing/markers/DocumentMarkerController.h" |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 bool paintSelectedTextSeparately = !paintSelectedTextOnly && textStyle != se
lectionStyle; | 149 bool paintSelectedTextSeparately = !paintSelectedTextOnly && textStyle != se
lectionStyle; |
150 | 150 |
151 // Set our font. | 151 // Set our font. |
152 const Font& font = styleToUse.font(); | 152 const Font& font = styleToUse.font(); |
153 | 153 |
154 LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().asc
ent()); | 154 LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().asc
ent()); |
155 | 155 |
156 // 1. Paint backgrounds behind text if needed. Examples of such backgrounds
include selection | 156 // 1. Paint backgrounds behind text if needed. Examples of such backgrounds
include selection |
157 // and composition highlights. | 157 // and composition highlights. |
158 if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseT
extClip && !isPrinting) { | 158 if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseT
extClip && !isPrinting) { |
159 paintDocumentMarkers(context, boxOrigin, styleToUse, font, true); | 159 paintDocumentMarkers(paintInfo, boxOrigin, styleToUse, font, DocumentMar
kerPaintPhase::Background); |
160 | 160 |
161 if (haveSelection && !paintsCompositionMarkers(textBoxLayoutObject)) { | 161 if (haveSelection && !paintsCompositionMarkers(textBoxLayoutObject)) { |
162 if (combinedText) | 162 if (combinedText) |
163 paintSelection<InlineTextBoxPainter::PaintOptions::CombinedText>
(context, boxRect, styleToUse, font, selectionStyle.fillColor, combinedText); | 163 paintSelection<InlineTextBoxPainter::PaintOptions::CombinedText>
(context, boxRect, styleToUse, font, selectionStyle.fillColor, combinedText); |
164 else | 164 else |
165 paintSelection<InlineTextBoxPainter::PaintOptions::Normal>(conte
xt, boxRect, styleToUse, font, selectionStyle.fillColor); | 165 paintSelection<InlineTextBoxPainter::PaintOptions::Normal>(conte
xt, boxRect, styleToUse, font, selectionStyle.fillColor); |
166 } | 166 } |
167 } | 167 } |
168 | 168 |
169 // 2. Now paint the foreground, including text and decorations like underlin
e/overline (in quirks mode only). | 169 // 2. Now paint the foreground, including text and decorations like underlin
e/overline (in quirks mode only). |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 GraphicsContextStateSaver stateSaver(context, false); | 236 GraphicsContextStateSaver stateSaver(context, false); |
237 TextPainter::updateGraphicsContext(context, textStyle, m_inlineTextBox.i
sHorizontal(), stateSaver); | 237 TextPainter::updateGraphicsContext(context, textStyle, m_inlineTextBox.i
sHorizontal(), stateSaver); |
238 if (combinedText) | 238 if (combinedText) |
239 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockw
ise)); | 239 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockw
ise)); |
240 paintDecoration(paintInfo, boxOrigin, textDecorations); | 240 paintDecoration(paintInfo, boxOrigin, textDecorations); |
241 if (combinedText) | 241 if (combinedText) |
242 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Counte
rclockwise)); | 242 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Counte
rclockwise)); |
243 } | 243 } |
244 | 244 |
245 if (paintInfo.phase == PaintPhaseForeground) | 245 if (paintInfo.phase == PaintPhaseForeground) |
246 paintDocumentMarkers(context, boxOrigin, styleToUse, font, false); | 246 paintDocumentMarkers(paintInfo, boxOrigin, styleToUse, font, DocumentMar
kerPaintPhase::Foreground); |
247 | 247 |
248 if (shouldRotate) | 248 if (shouldRotate) |
249 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Counterclo
ckwise)); | 249 context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Counterclo
ckwise)); |
250 } | 250 } |
251 | 251 |
252 bool InlineTextBoxPainter::shouldPaintTextBox(const PaintInfo& paintInfo) | 252 bool InlineTextBoxPainter::shouldPaintTextBox(const PaintInfo& paintInfo) |
253 { | 253 { |
254 // When painting selection, we want to include a highlight when the | 254 // When painting selection, we want to include a highlight when the |
255 // selection spans line breaks. In other cases such as invisible elements | 255 // selection spans line breaks. In other cases such as invisible elements |
256 // or those with no text that are not line breaks, we can skip painting | 256 // or those with no text that are not line breaks, we can skip painting |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 int ePos = std::min(endPos - static_cast<int>(m_inlineTextBox.start()), stat
ic_cast<int>(m_inlineTextBox.len())); | 291 int ePos = std::min(endPos - static_cast<int>(m_inlineTextBox.start()), stat
ic_cast<int>(m_inlineTextBox.len())); |
292 if (sPos >= ePos) | 292 if (sPos >= ePos) |
293 return; | 293 return; |
294 | 294 |
295 int deltaY = m_inlineTextBox.lineLayoutItem().style()->isFlippedLinesWriting
Mode() ? m_inlineTextBox.root().selectionBottom() - m_inlineTextBox.logicalBotto
m() : m_inlineTextBox.logicalTop() - m_inlineTextBox.root().selectionTop(); | 295 int deltaY = m_inlineTextBox.lineLayoutItem().style()->isFlippedLinesWriting
Mode() ? m_inlineTextBox.root().selectionBottom() - m_inlineTextBox.logicalBotto
m() : m_inlineTextBox.logicalTop() - m_inlineTextBox.root().selectionTop(); |
296 int selHeight = m_inlineTextBox.root().selectionHeight(); | 296 int selHeight = m_inlineTextBox.root().selectionHeight(); |
297 FloatPoint localOrigin(boxOrigin.x().toFloat(), boxOrigin.y().toFloat() - de
ltaY); | 297 FloatPoint localOrigin(boxOrigin.x().toFloat(), boxOrigin.y().toFloat() - de
ltaY); |
298 context.drawHighlightForText(font, m_inlineTextBox.constructTextRun(style, f
ont), localOrigin, selHeight, backgroundColor, sPos, ePos); | 298 context.drawHighlightForText(font, m_inlineTextBox.constructTextRun(style, f
ont), localOrigin, selHeight, backgroundColor, sPos, ePos); |
299 } | 299 } |
300 | 300 |
301 void InlineTextBoxPainter::paintDocumentMarkers(GraphicsContext& context, const
LayoutPoint& boxOrigin, const ComputedStyle& style, const Font& font, bool backg
round) | 301 void InlineTextBoxPainter::paintDocumentMarkers(const PaintInfo& paintInfo, cons
t LayoutPoint& boxOrigin, const ComputedStyle& style, const Font& font, Document
MarkerPaintPhase markerPaintPhase) |
302 { | 302 { |
303 if (!m_inlineTextBox.lineLayoutItem().node()) | 303 if (!m_inlineTextBox.lineLayoutItem().node()) |
304 return; | 304 return; |
305 | 305 |
306 DocumentMarkerVector markers = m_inlineTextBox.lineLayoutItem().document().m
arkers().markersFor(m_inlineTextBox.lineLayoutItem().node()); | 306 DocumentMarkerVector markers = m_inlineTextBox.lineLayoutItem().document().m
arkers().markersFor(m_inlineTextBox.lineLayoutItem().node()); |
307 DocumentMarkerVector::const_iterator markerIt = markers.begin(); | 307 DocumentMarkerVector::const_iterator markerIt = markers.begin(); |
308 | 308 |
309 // Give any document markers that touch this run a chance to draw before the
text has been drawn. | 309 // Give any document markers that touch this run a chance to draw before the
text has been drawn. |
310 // Note end() points at the last char, not one past it like endOffset and ra
nges do. | 310 // Note end() points at the last char, not one past it like endOffset and ra
nges do. |
311 for ( ; markerIt != markers.end(); ++markerIt) { | 311 for ( ; markerIt != markers.end(); ++markerIt) { |
312 DocumentMarker* marker = *markerIt; | 312 DocumentMarker* marker = *markerIt; |
313 | 313 |
314 // Paint either the background markers or the foreground markers, but no
t both | 314 // Paint either the background markers or the foreground markers, but no
t both |
315 switch (marker->type()) { | 315 switch (marker->type()) { |
316 case DocumentMarker::Grammar: | 316 case DocumentMarker::Grammar: |
317 case DocumentMarker::Spelling: | 317 case DocumentMarker::Spelling: |
318 if (background) | 318 if (markerPaintPhase == DocumentMarkerPaintPhase::Background) |
319 continue; | 319 continue; |
320 break; | 320 break; |
321 case DocumentMarker::TextMatch: | 321 case DocumentMarker::TextMatch: |
322 if (!background) | |
323 continue; | |
324 break; | |
325 case DocumentMarker::Composition: | 322 case DocumentMarker::Composition: |
326 break; | 323 break; |
327 default: | 324 default: |
328 continue; | 325 continue; |
329 } | 326 } |
330 | 327 |
331 if (marker->endOffset() <= m_inlineTextBox.start()) { | 328 if (marker->endOffset() <= m_inlineTextBox.start()) { |
332 // marker is completely before this run. This might be a marker tha
t sits before the | 329 // marker is completely before this run. This might be a marker tha
t sits before the |
333 // first run we draw, or markers that were within runs we skipped du
e to truncation. | 330 // first run we draw, or markers that were within runs we skipped du
e to truncation. |
334 continue; | 331 continue; |
335 } | 332 } |
336 if (marker->startOffset() > m_inlineTextBox.end()) { | 333 if (marker->startOffset() > m_inlineTextBox.end()) { |
337 // marker is completely after this run, bail. A later run will pain
t it. | 334 // marker is completely after this run, bail. A later run will pain
t it. |
338 break; | 335 break; |
339 } | 336 } |
340 | 337 |
341 // marker intersects this run. Paint it. | 338 // marker intersects this run. Paint it. |
342 switch (marker->type()) { | 339 switch (marker->type()) { |
343 case DocumentMarker::Spelling: | 340 case DocumentMarker::Spelling: |
344 m_inlineTextBox.paintDocumentMarker(context, boxOrigin, marker, styl
e, font, false); | 341 m_inlineTextBox.paintDocumentMarker(paintInfo.context, boxOrigin, ma
rker, style, font, false); |
345 break; | 342 break; |
346 case DocumentMarker::Grammar: | 343 case DocumentMarker::Grammar: |
347 m_inlineTextBox.paintDocumentMarker(context, boxOrigin, marker, styl
e, font, true); | 344 m_inlineTextBox.paintDocumentMarker(paintInfo.context, boxOrigin, ma
rker, style, font, true); |
348 break; | 345 break; |
349 case DocumentMarker::TextMatch: | 346 case DocumentMarker::TextMatch: |
350 m_inlineTextBox.paintTextMatchMarker(context, boxOrigin, marker, sty
le, font); | 347 if (markerPaintPhase == DocumentMarkerPaintPhase::Background) |
| 348 m_inlineTextBox.paintTextMatchMarkerBackground(paintInfo, boxOri
gin, marker, style, font); |
| 349 else |
| 350 m_inlineTextBox.paintTextMatchMarkerForeground(paintInfo, boxOri
gin, marker, style, font); |
351 break; | 351 break; |
352 case DocumentMarker::Composition: | 352 case DocumentMarker::Composition: |
353 { | 353 { |
354 CompositionUnderline underline(marker->startOffset(), marker->en
dOffset(), marker->underlineColor(), marker->thick(), marker->backgroundColor())
; | 354 CompositionUnderline underline(marker->startOffset(), marker->en
dOffset(), marker->underlineColor(), marker->thick(), marker->backgroundColor())
; |
355 if (background) | 355 if (markerPaintPhase == DocumentMarkerPaintPhase::Background) |
356 paintSingleCompositionBackgroundRun(context, boxOrigin, styl
e, font, underline.backgroundColor, underlinePaintStart(underline), underlinePai
ntEnd(underline)); | 356 paintSingleCompositionBackgroundRun(paintInfo.context, boxOr
igin, style, font, underline.backgroundColor, underlinePaintStart(underline), un
derlinePaintEnd(underline)); |
357 else | 357 else |
358 paintCompositionUnderline(context, boxOrigin, underline); | 358 paintCompositionUnderline(paintInfo.context, boxOrigin, unde
rline); |
359 } | 359 } |
360 break; | 360 break; |
361 default: | 361 default: |
362 ASSERT_NOT_REACHED(); | 362 ASSERT_NOT_REACHED(); |
363 } | 363 } |
364 } | 364 } |
365 } | 365 } |
366 | 366 |
367 static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentM
arker::MarkerType markerType) | 367 static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentM
arker::MarkerType markerType) |
368 { | 368 { |
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 // We need to have some space between underlines of subsequent clauses, beca
use some input methods do not use different underline styles for those. | 823 // We need to have some space between underlines of subsequent clauses, beca
use some input methods do not use different underline styles for those. |
824 // We make each line shorter, which has a harmless side effect of shortening
the first and last clauses, too. | 824 // We make each line shorter, which has a harmless side effect of shortening
the first and last clauses, too. |
825 start += 1; | 825 start += 1; |
826 width -= 2; | 826 width -= 2; |
827 | 827 |
828 context.setStrokeColor(underline.color); | 828 context.setStrokeColor(underline.color); |
829 context.setStrokeThickness(lineThickness); | 829 context.setStrokeThickness(lineThickness); |
830 context.drawLineForText(FloatPoint(boxOrigin.x() + start, (boxOrigin.y() + m
_inlineTextBox.logicalHeight() - lineThickness).toFloat()), width, m_inlineTextB
ox.lineLayoutItem().document().printing()); | 830 context.drawLineForText(FloatPoint(boxOrigin.x() + start, (boxOrigin.y() + m
_inlineTextBox.logicalHeight() - lineThickness).toFloat()), width, m_inlineTextB
ox.lineLayoutItem().document().printing()); |
831 } | 831 } |
832 | 832 |
833 void InlineTextBoxPainter::paintTextMatchMarker(GraphicsContext& context, const
LayoutPoint& boxOrigin, DocumentMarker* marker, const ComputedStyle& style, cons
t Font& font) | 833 void InlineTextBoxPainter::paintTextMatchMarkerForeground(const PaintInfo& paint
Info, const LayoutPoint& boxOrigin, DocumentMarker* marker, const ComputedStyle&
style, const Font& font) |
834 { | 834 { |
| 835 if (!LineLayoutPaintShim::layoutObjectFrom(m_inlineTextBox.lineLayoutItem())
->frame()->editor().markedTextMatchesAreHighlighted()) |
| 836 return; |
| 837 |
| 838 // TODO(ramya.v): Extract this into a helper function and share many copies
of this code. |
| 839 int sPos = std::max(marker->startOffset() - m_inlineTextBox.start(), (unsign
ed)0); |
| 840 int ePos = std::min(marker->endOffset() - m_inlineTextBox.start(), m_inlineT
extBox.len()); |
| 841 TextRun run = m_inlineTextBox.constructTextRun(style, font); |
| 842 |
| 843 Color textColor = LayoutTheme::theme().platformTextSearchColor(marker->activ
eMatch()); |
| 844 if (style.visitedDependentColor(CSSPropertyColor) == textColor) |
| 845 return; |
| 846 TextPainter::Style textStyle; |
| 847 textStyle.currentColor = textStyle.fillColor = textStyle.strokeColor = textS
tyle.emphasisMarkColor = textColor; |
| 848 textStyle.strokeWidth = style.textStrokeWidth(); |
| 849 textStyle.shadow = 0; |
| 850 |
| 851 LayoutRect boxRect(boxOrigin, LayoutSize(m_inlineTextBox.logicalWidth(), m_i
nlineTextBox.logicalHeight())); |
| 852 LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().asc
ent()); |
| 853 TextPainter textPainter(paintInfo.context, font, run, textOrigin, boxRect, m
_inlineTextBox.isHorizontal()); |
| 854 |
| 855 textPainter.paint(sPos, ePos, m_inlineTextBox.len(), textStyle, 0); |
| 856 } |
| 857 |
| 858 void InlineTextBoxPainter::paintTextMatchMarkerBackground(const PaintInfo& paint
Info, const LayoutPoint& boxOrigin, DocumentMarker* marker, const ComputedStyle&
style, const Font& font) |
| 859 { |
| 860 if (!LineLayoutPaintShim::layoutObjectFrom(m_inlineTextBox.lineLayoutItem())
->frame()->editor().markedTextMatchesAreHighlighted()) |
| 861 return; |
| 862 |
835 // Use same y positioning and height as for selection, so that when the sele
ction and this highlight are on | 863 // Use same y positioning and height as for selection, so that when the sele
ction and this highlight are on |
836 // the same word there are no pieces sticking out. | 864 // the same word there are no pieces sticking out. |
837 int deltaY = m_inlineTextBox.lineLayoutItem().style()->isFlippedLinesWriting
Mode() ? m_inlineTextBox.root().selectionBottom() - m_inlineTextBox.logicalBotto
m() : m_inlineTextBox.logicalTop() - m_inlineTextBox.root().selectionTop(); | 865 int deltaY = m_inlineTextBox.lineLayoutItem().style()->isFlippedLinesWriting
Mode() ? m_inlineTextBox.root().selectionBottom() - m_inlineTextBox.logicalBotto
m() : m_inlineTextBox.logicalTop() - m_inlineTextBox.root().selectionTop(); |
838 int selHeight = m_inlineTextBox.root().selectionHeight(); | 866 int selHeight = m_inlineTextBox.root().selectionHeight(); |
839 | 867 |
840 int sPos = std::max(marker->startOffset() - m_inlineTextBox.start(), (unsign
ed)0); | 868 int sPos = std::max(marker->startOffset() - m_inlineTextBox.start(), (unsign
ed)0); |
841 int ePos = std::min(marker->endOffset() - m_inlineTextBox.start(), m_inlineT
extBox.len()); | 869 int ePos = std::min(marker->endOffset() - m_inlineTextBox.start(), m_inlineT
extBox.len()); |
842 TextRun run = m_inlineTextBox.constructTextRun(style, font); | 870 TextRun run = m_inlineTextBox.constructTextRun(style, font); |
843 | 871 |
844 // Optionally highlight the text | 872 Color color = LayoutTheme::theme().platformTextSearchHighlightColor(marker->
activeMatch()); |
845 if (LineLayoutPaintShim::layoutObjectFrom(m_inlineTextBox.lineLayoutItem())-
>frame()->editor().markedTextMatchesAreHighlighted()) { | 873 GraphicsContext& context = paintInfo.context; |
846 Color color = marker->activeMatch() ? | 874 GraphicsContextStateSaver stateSaver(context); |
847 LayoutTheme::theme().platformActiveTextSearchHighlightColor() : | 875 context.clip(FloatRect(boxOrigin.x().toFloat(), (boxOrigin.y() - deltaY).toF
loat(), m_inlineTextBox.logicalWidth().toFloat(), selHeight)); |
848 LayoutTheme::theme().platformInactiveTextSearchHighlightColor(); | 876 context.drawHighlightForText(font, run, FloatPoint(boxOrigin.x().toFloat(),
(boxOrigin.y() - deltaY).toFloat()), selHeight, color, sPos, ePos); |
849 GraphicsContextStateSaver stateSaver(context); | |
850 context.clip(FloatRect(boxOrigin.x().toFloat(), (boxOrigin.y() - deltaY)
.toFloat(), m_inlineTextBox.logicalWidth().toFloat(), selHeight)); | |
851 context.drawHighlightForText(font, run, FloatPoint(boxOrigin.x().toFloat
(), (boxOrigin.y() - deltaY).toFloat()), selHeight, color, sPos, ePos); | |
852 | |
853 // Also Highlight the text with color:transparent | |
854 if (style.visitedDependentColor(CSSPropertyColor) == Color::transparent)
{ | |
855 int length = m_inlineTextBox.len(); | |
856 TextPainter::Style textStyle; | |
857 // When we use the text as a clip, we only care about the alpha, thu
s we make all the colors black. | |
858 textStyle.currentColor = textStyle.fillColor = textStyle.strokeColor
= textStyle.emphasisMarkColor = Color::black; | |
859 textStyle.strokeWidth = style.textStrokeWidth(); | |
860 textStyle.shadow = 0; | |
861 | |
862 LayoutRect boxRect(boxOrigin, LayoutSize(m_inlineTextBox.logicalWidt
h(), m_inlineTextBox.logicalHeight())); | |
863 LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetri
cs().ascent()); | |
864 TextPainter textPainter(context, font, run, textOrigin, boxRect, m_i
nlineTextBox.isHorizontal()); | |
865 | |
866 textPainter.paint(sPos, ePos, length, textStyle, 0); | |
867 } | |
868 } | |
869 } | 877 } |
870 | 878 |
871 | 879 |
872 } // namespace blink | 880 } // namespace blink |
OLD | NEW |