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 "core/paint/InlineTextBoxPainter.h" | 5 #include "core/paint/InlineTextBoxPainter.h" |
6 | 6 |
7 #include "core/editing/CompositionUnderline.h" | 7 #include "core/editing/CompositionUnderline.h" |
8 #include "core/editing/Editor.h" | 8 #include "core/editing/Editor.h" |
9 #include "core/editing/markers/DocumentMarkerController.h" | 9 #include "core/editing/markers/DocumentMarkerController.h" |
10 #include "core/frame/LocalFrame.h" | 10 #include "core/frame/LocalFrame.h" |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 bool isPrinting = paintInfo.isPrinting(); | 89 bool isPrinting = paintInfo.isPrinting(); |
90 | 90 |
91 // Determine whether or not we're selected. | 91 // Determine whether or not we're selected. |
92 bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && | 92 bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && |
93 m_inlineTextBox.getSelectionState() != SelectionNone; | 93 m_inlineTextBox.getSelectionState() != SelectionNone; |
94 if (!haveSelection && paintInfo.phase == PaintPhaseSelection) { | 94 if (!haveSelection && paintInfo.phase == PaintPhaseSelection) { |
95 // When only painting the selection, don't bother to paint if there is none. | 95 // When only painting the selection, don't bother to paint if there is none. |
96 return; | 96 return; |
97 } | 97 } |
98 | 98 |
99 // The text clip phase already has a LayoutObjectDrawingRecorder. Text clips a
re initiated only in BoxPainter::paintFillLayer, | 99 // The text clip phase already has a LayoutObjectDrawingRecorder. Text clips |
100 // which is already within a LayoutObjectDrawingRecorder. | 100 // are initiated only in BoxPainter::paintFillLayer, which is already within a |
| 101 // LayoutObjectDrawingRecorder. |
101 Optional<DrawingRecorder> drawingRecorder; | 102 Optional<DrawingRecorder> drawingRecorder; |
102 if (paintInfo.phase != PaintPhaseTextClip) { | 103 if (paintInfo.phase != PaintPhaseTextClip) { |
103 if (DrawingRecorder::useCachedDrawingIfPossible( | 104 if (DrawingRecorder::useCachedDrawingIfPossible( |
104 paintInfo.context, m_inlineTextBox, | 105 paintInfo.context, m_inlineTextBox, |
105 DisplayItem::paintPhaseToDrawingType(paintInfo.phase))) | 106 DisplayItem::paintPhaseToDrawingType(paintInfo.phase))) |
106 return; | 107 return; |
107 LayoutRect paintRect(logicalVisualOverflow); | 108 LayoutRect paintRect(logicalVisualOverflow); |
108 m_inlineTextBox.logicalRectToPhysicalRect(paintRect); | 109 m_inlineTextBox.logicalRectToPhysicalRect(paintRect); |
109 if (paintInfo.phase != PaintPhaseSelection && | 110 if (paintInfo.phase != PaintPhaseSelection && |
110 (haveSelection || paintsMarkerHighlights(inlineLayoutObject()))) | 111 (haveSelection || paintsMarkerHighlights(inlineLayoutObject()))) |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 bool paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection); | 182 bool paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection); |
182 bool paintSelectedTextSeparately = | 183 bool paintSelectedTextSeparately = |
183 !paintSelectedTextOnly && textStyle != selectionStyle; | 184 !paintSelectedTextOnly && textStyle != selectionStyle; |
184 | 185 |
185 // Set our font. | 186 // Set our font. |
186 const Font& font = styleToUse.font(); | 187 const Font& font = styleToUse.font(); |
187 | 188 |
188 LayoutPoint textOrigin(boxOrigin.x(), | 189 LayoutPoint textOrigin(boxOrigin.x(), |
189 boxOrigin.y() + font.getFontMetrics().ascent()); | 190 boxOrigin.y() + font.getFontMetrics().ascent()); |
190 | 191 |
191 // 1. Paint backgrounds behind text if needed. Examples of such backgrounds in
clude selection | 192 // 1. Paint backgrounds behind text if needed. Examples of such backgrounds |
192 // and composition highlights. | 193 // include selection and composition highlights. |
193 if (paintInfo.phase != PaintPhaseSelection && | 194 if (paintInfo.phase != PaintPhaseSelection && |
194 paintInfo.phase != PaintPhaseTextClip && !isPrinting) { | 195 paintInfo.phase != PaintPhaseTextClip && !isPrinting) { |
195 paintDocumentMarkers(paintInfo, boxOrigin, styleToUse, font, | 196 paintDocumentMarkers(paintInfo, boxOrigin, styleToUse, font, |
196 DocumentMarkerPaintPhase::Background); | 197 DocumentMarkerPaintPhase::Background); |
197 | 198 |
198 const LayoutObject& textBoxLayoutObject = inlineLayoutObject(); | 199 const LayoutObject& textBoxLayoutObject = inlineLayoutObject(); |
199 if (haveSelection && !paintsCompositionMarkers(textBoxLayoutObject)) { | 200 if (haveSelection && !paintsCompositionMarkers(textBoxLayoutObject)) { |
200 if (combinedText) | 201 if (combinedText) |
201 paintSelection<InlineTextBoxPainter::PaintOptions::CombinedText>( | 202 paintSelection<InlineTextBoxPainter::PaintOptions::CombinedText>( |
202 context, boxRect, styleToUse, font, selectionStyle.fillColor, | 203 context, boxRect, styleToUse, font, selectionStyle.fillColor, |
203 combinedText); | 204 combinedText); |
204 else | 205 else |
205 paintSelection<InlineTextBoxPainter::PaintOptions::Normal>( | 206 paintSelection<InlineTextBoxPainter::PaintOptions::Normal>( |
206 context, boxRect, styleToUse, font, selectionStyle.fillColor); | 207 context, boxRect, styleToUse, font, selectionStyle.fillColor); |
207 } | 208 } |
208 } | 209 } |
209 | 210 |
210 // 2. Now paint the foreground, including text and decorations like underline/
overline (in quirks mode only). | 211 // 2. Now paint the foreground, including text and decorations like |
| 212 // underline/overline (in quirks mode only). |
211 int selectionStart = 0; | 213 int selectionStart = 0; |
212 int selectionEnd = 0; | 214 int selectionEnd = 0; |
213 if (paintSelectedTextOnly || paintSelectedTextSeparately) | 215 if (paintSelectedTextOnly || paintSelectedTextSeparately) |
214 m_inlineTextBox.selectionStartEnd(selectionStart, selectionEnd); | 216 m_inlineTextBox.selectionStartEnd(selectionStart, selectionEnd); |
215 | 217 |
216 bool respectHyphen = | 218 bool respectHyphen = |
217 selectionEnd == static_cast<int>(m_inlineTextBox.len()) && | 219 selectionEnd == static_cast<int>(m_inlineTextBox.len()) && |
218 m_inlineTextBox.hasHyphen(); | 220 m_inlineTextBox.hasHyphen(); |
219 if (respectHyphen) | 221 if (respectHyphen) |
220 selectionEnd = textRun.length(); | 222 selectionEnd = textRun.length(); |
(...skipping 16 matching lines...) Expand all Loading... |
237 if (combinedText) | 239 if (combinedText) |
238 textPainter.setCombinedText(combinedText); | 240 textPainter.setCombinedText(combinedText); |
239 | 241 |
240 if (!paintSelectedTextOnly) { | 242 if (!paintSelectedTextOnly) { |
241 int startOffset = 0; | 243 int startOffset = 0; |
242 int endOffset = length; | 244 int endOffset = length; |
243 if (paintSelectedTextSeparately && selectionStart < selectionEnd) { | 245 if (paintSelectedTextSeparately && selectionStart < selectionEnd) { |
244 startOffset = selectionEnd; | 246 startOffset = selectionEnd; |
245 endOffset = selectionStart; | 247 endOffset = selectionStart; |
246 } | 248 } |
247 // Where the text and its flow have opposite directions then our offset into
the text given by |truncation| is at | 249 // Where the text and its flow have opposite directions then our offset into |
248 // the start of the part that will be visible. | 250 // the text given by |truncation| is at the start of the part that will be |
| 251 // visible. |
249 if (m_inlineTextBox.truncation() != cNoTruncation && | 252 if (m_inlineTextBox.truncation() != cNoTruncation && |
250 m_inlineTextBox.getLineLayoutItem() | 253 m_inlineTextBox.getLineLayoutItem() |
251 .containingBlock() | 254 .containingBlock() |
252 .style() | 255 .style() |
253 ->isLeftToRightDirection() != | 256 ->isLeftToRightDirection() != |
254 m_inlineTextBox.isLeftToRightDirection()) { | 257 m_inlineTextBox.isLeftToRightDirection()) { |
255 startOffset = m_inlineTextBox.truncation(); | 258 startOffset = m_inlineTextBox.truncation(); |
256 endOffset = textRun.length(); | 259 endOffset = textRun.length(); |
257 } | 260 } |
258 | 261 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 return; | 398 return; |
396 | 399 |
397 DCHECK(m_inlineTextBox.truncation() != cFullTruncation); | 400 DCHECK(m_inlineTextBox.truncation() != cFullTruncation); |
398 DCHECK(m_inlineTextBox.len()); | 401 DCHECK(m_inlineTextBox.len()); |
399 | 402 |
400 DocumentMarkerVector markers = | 403 DocumentMarkerVector markers = |
401 m_inlineTextBox.getLineLayoutItem().document().markers().markersFor( | 404 m_inlineTextBox.getLineLayoutItem().document().markers().markersFor( |
402 m_inlineTextBox.getLineLayoutItem().node()); | 405 m_inlineTextBox.getLineLayoutItem().node()); |
403 DocumentMarkerVector::const_iterator markerIt = markers.begin(); | 406 DocumentMarkerVector::const_iterator markerIt = markers.begin(); |
404 | 407 |
405 // Give any document markers that touch this run a chance to draw before the t
ext has been drawn. | 408 // Give any document markers that touch this run a chance to draw before the |
406 // Note end() points at the last char, not one past it like endOffset and rang
es do. | 409 // text has been drawn. Note end() points at the last char, not one past it |
| 410 // like endOffset and ranges do. |
407 for (; markerIt != markers.end(); ++markerIt) { | 411 for (; markerIt != markers.end(); ++markerIt) { |
408 DocumentMarker* marker = *markerIt; | 412 DocumentMarker* marker = *markerIt; |
409 | 413 |
410 // Paint either the background markers or the foreground markers, but not bo
th | 414 // Paint either the background markers or the foreground markers, but not |
| 415 // both. |
411 switch (marker->type()) { | 416 switch (marker->type()) { |
412 case DocumentMarker::Grammar: | 417 case DocumentMarker::Grammar: |
413 case DocumentMarker::Spelling: | 418 case DocumentMarker::Spelling: |
414 if (markerPaintPhase == DocumentMarkerPaintPhase::Background) | 419 if (markerPaintPhase == DocumentMarkerPaintPhase::Background) |
415 continue; | 420 continue; |
416 break; | 421 break; |
417 case DocumentMarker::TextMatch: | 422 case DocumentMarker::TextMatch: |
418 case DocumentMarker::Composition: | 423 case DocumentMarker::Composition: |
419 break; | 424 break; |
420 default: | 425 default: |
421 continue; | 426 continue; |
422 } | 427 } |
423 | 428 |
424 if (marker->endOffset() <= m_inlineTextBox.start()) { | 429 if (marker->endOffset() <= m_inlineTextBox.start()) { |
425 // marker is completely before this run. This might be a marker that sits
before the | 430 // marker is completely before this run. This might be a marker that sits |
426 // first run we draw, or markers that were within runs we skipped due to t
runcation. | 431 // before the first run we draw, or markers that were within runs we |
| 432 // skipped due to truncation. |
427 continue; | 433 continue; |
428 } | 434 } |
429 if (marker->startOffset() > m_inlineTextBox.end()) { | 435 if (marker->startOffset() > m_inlineTextBox.end()) { |
430 // marker is completely after this run, bail. A later run will paint it. | 436 // marker is completely after this run, bail. A later run will paint it. |
431 break; | 437 break; |
432 } | 438 } |
433 | 439 |
434 // marker intersects this run. Paint it. | 440 // marker intersects this run. Paint it. |
435 switch (marker->type()) { | 441 switch (marker->type()) { |
436 case DocumentMarker::Spelling: | 442 case DocumentMarker::Spelling: |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 LayoutPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY); | 536 LayoutPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY); |
531 TextRun run = m_inlineTextBox.constructTextRun(style); | 537 TextRun run = m_inlineTextBox.constructTextRun(style); |
532 | 538 |
533 // FIXME: Convert the document markers to float rects. | 539 // FIXME: Convert the document markers to float rects. |
534 IntRect markerRect = enclosingIntRect(font.selectionRectForText( | 540 IntRect markerRect = enclosingIntRect(font.selectionRectForText( |
535 run, FloatPoint(startPoint), selHeight, startPosition, endPosition)); | 541 run, FloatPoint(startPoint), selHeight, startPosition, endPosition)); |
536 start = markerRect.x() - startPoint.x(); | 542 start = markerRect.x() - startPoint.x(); |
537 width = LayoutUnit(markerRect.width()); | 543 width = LayoutUnit(markerRect.width()); |
538 } | 544 } |
539 | 545 |
540 // IMPORTANT: The misspelling underline is not considered when calculating the
text bounds, so we have to | 546 // IMPORTANT: The misspelling underline is not considered when calculating the |
541 // make sure to fit within those bounds. This means the top pixel(s) of the u
nderline will overlap the | 547 // text bounds, so we have to make sure to fit within those bounds. This |
542 // bottom pixel(s) of the glyphs in smaller font sizes. The alternatives are
to increase the line spacing (bad!!) | 548 // means the top pixel(s) of the underline will overlap the bottom pixel(s) of |
543 // or decrease the underline thickness. The overlap is actually the most usef
ul, and matches what AppKit does. | 549 // the glyphs in smaller font sizes. The alternatives are to increase the |
544 // So, we generally place the underline at the bottom of the text, but in larg
er fonts that's not so good so | 550 // line spacing (bad!!) or decrease the underline thickness. The overlap is |
545 // we pin to two pixels under the baseline. | 551 // actually the most useful, and matches what AppKit does. So, we generally |
| 552 // place the underline at the bottom of the text, but in larger fonts that's |
| 553 // not so good so we pin to two pixels under the baseline. |
546 int lineThickness = misspellingLineThickness; | 554 int lineThickness = misspellingLineThickness; |
547 int baseline = m_inlineTextBox.getLineLayoutItem() | 555 int baseline = m_inlineTextBox.getLineLayoutItem() |
548 .style(m_inlineTextBox.isFirstLineStyle()) | 556 .style(m_inlineTextBox.isFirstLineStyle()) |
549 ->getFontMetrics() | 557 ->getFontMetrics() |
550 .ascent(); | 558 .ascent(); |
551 int descent = (m_inlineTextBox.logicalHeight() - baseline).toInt(); | 559 int descent = (m_inlineTextBox.logicalHeight() - baseline).toInt(); |
552 int underlineOffset; | 560 int underlineOffset; |
553 if (descent <= (lineThickness + 2)) { | 561 if (descent <= (lineThickness + 2)) { |
554 // Place the underline at the very bottom of the text in small/medium fonts. | 562 // Place the underline at the very bottom of the text in small/medium fonts. |
555 underlineOffset = (m_inlineTextBox.logicalHeight() - lineThickness).toInt(); | 563 underlineOffset = (m_inlineTextBox.logicalHeight() - lineThickness).toInt(); |
556 } else { | 564 } else { |
557 // In larger fonts, though, place the underline up near the baseline to prev
ent a big gap. | 565 // In larger fonts, though, place the underline up near the baseline to |
| 566 // prevent a big gap. |
558 underlineOffset = baseline + 2; | 567 underlineOffset = baseline + 2; |
559 } | 568 } |
560 context.drawLineForDocumentMarker( | 569 context.drawLineForDocumentMarker( |
561 FloatPoint((boxOrigin.x() + start).toFloat(), | 570 FloatPoint((boxOrigin.x() + start).toFloat(), |
562 (boxOrigin.y() + underlineOffset).toFloat()), | 571 (boxOrigin.y() + underlineOffset).toFloat()), |
563 width.toFloat(), lineStyleForMarkerType(marker->type())); | 572 width.toFloat(), lineStyleForMarkerType(marker->type())); |
564 } | 573 } |
565 | 574 |
566 template <InlineTextBoxPainter::PaintOptions options> | 575 template <InlineTextBoxPainter::PaintOptions options> |
567 void InlineTextBoxPainter::paintSelection(GraphicsContext& context, | 576 void InlineTextBoxPainter::paintSelection(GraphicsContext& context, |
568 const LayoutRect& boxRect, | 577 const LayoutRect& boxRect, |
569 const ComputedStyle& style, | 578 const ComputedStyle& style, |
570 const Font& font, | 579 const Font& font, |
571 Color textColor, | 580 Color textColor, |
572 LayoutTextCombine* combinedText) { | 581 LayoutTextCombine* combinedText) { |
573 // See if we have a selection to paint at all. | 582 // See if we have a selection to paint at all. |
574 int sPos, ePos; | 583 int sPos, ePos; |
575 m_inlineTextBox.selectionStartEnd(sPos, ePos); | 584 m_inlineTextBox.selectionStartEnd(sPos, ePos); |
576 if (sPos >= ePos) | 585 if (sPos >= ePos) |
577 return; | 586 return; |
578 | 587 |
579 Color c = m_inlineTextBox.getLineLayoutItem().selectionBackgroundColor(); | 588 Color c = m_inlineTextBox.getLineLayoutItem().selectionBackgroundColor(); |
580 if (!c.alpha()) | 589 if (!c.alpha()) |
581 return; | 590 return; |
582 | 591 |
583 // If the text color ends up being the same as the selection background, inver
t the selection | 592 // If the text color ends up being the same as the selection background, |
584 // background. | 593 // invert the selection background. |
585 if (textColor == c) | 594 if (textColor == c) |
586 c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); | 595 c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); |
587 | 596 |
588 // If the text is truncated, let the thing being painted in the truncation | 597 // If the text is truncated, let the thing being painted in the truncation |
589 // draw its own highlight. | 598 // draw its own highlight. |
590 unsigned start = m_inlineTextBox.start(); | 599 unsigned start = m_inlineTextBox.start(); |
591 int length = m_inlineTextBox.len(); | 600 int length = m_inlineTextBox.len(); |
592 bool ltr = m_inlineTextBox.isLeftToRightDirection(); | 601 bool ltr = m_inlineTextBox.isLeftToRightDirection(); |
593 bool flowIsLTR = | 602 bool flowIsLTR = |
594 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection(); | 603 m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection(); |
(...skipping 13 matching lines...) Expand all Loading... |
608 style, string, m_inlineTextBox.getLineLayoutItem().textLength() - | 617 style, string, m_inlineTextBox.getLineLayoutItem().textLength() - |
609 m_inlineTextBox.start(), | 618 m_inlineTextBox.start(), |
610 respectHyphen ? &charactersWithHyphen : 0); | 619 respectHyphen ? &charactersWithHyphen : 0); |
611 if (respectHyphen) | 620 if (respectHyphen) |
612 ePos = textRun.length(); | 621 ePos = textRun.length(); |
613 | 622 |
614 GraphicsContextStateSaver stateSaver(context); | 623 GraphicsContextStateSaver stateSaver(context); |
615 | 624 |
616 if (options == InlineTextBoxPainter::PaintOptions::CombinedText) { | 625 if (options == InlineTextBoxPainter::PaintOptions::CombinedText) { |
617 ASSERT(combinedText); | 626 ASSERT(combinedText); |
618 // We can't use the height of m_inlineTextBox because LayoutTextCombine's in
lineTextBox is horizontal within vertical flow | 627 // We can't use the height of m_inlineTextBox because LayoutTextCombine's |
| 628 // inlineTextBox is horizontal within vertical flow |
619 combinedText->transformToInlineCoordinates(context, boxRect, true); | 629 combinedText->transformToInlineCoordinates(context, boxRect, true); |
620 context.drawHighlightForText(font, textRun, FloatPoint(boxRect.location()), | 630 context.drawHighlightForText(font, textRun, FloatPoint(boxRect.location()), |
621 boxRect.height().toInt(), c, sPos, ePos); | 631 boxRect.height().toInt(), c, sPos, ePos); |
622 return; | 632 return; |
623 } | 633 } |
624 | 634 |
625 LayoutUnit selectionBottom = m_inlineTextBox.root().selectionBottom(); | 635 LayoutUnit selectionBottom = m_inlineTextBox.root().selectionBottom(); |
626 LayoutUnit selectionTop = m_inlineTextBox.root().selectionTop(); | 636 LayoutUnit selectionTop = m_inlineTextBox.root().selectionTop(); |
627 | 637 |
628 int deltaY = roundToInt( | 638 int deltaY = roundToInt( |
629 m_inlineTextBox.getLineLayoutItem().style()->isFlippedLinesWritingMode() | 639 m_inlineTextBox.getLineLayoutItem().style()->isFlippedLinesWritingMode() |
630 ? selectionBottom - m_inlineTextBox.logicalBottom() | 640 ? selectionBottom - m_inlineTextBox.logicalBottom() |
631 : m_inlineTextBox.logicalTop() - selectionTop); | 641 : m_inlineTextBox.logicalTop() - selectionTop); |
632 int selHeight = std::max(0, roundToInt(selectionBottom - selectionTop)); | 642 int selHeight = std::max(0, roundToInt(selectionBottom - selectionTop)); |
633 | 643 |
634 FloatPoint localOrigin(boxRect.x().toFloat(), | 644 FloatPoint localOrigin(boxRect.x().toFloat(), |
635 (boxRect.y() - deltaY).toFloat()); | 645 (boxRect.y() - deltaY).toFloat()); |
636 LayoutRect selectionRect = LayoutRect( | 646 LayoutRect selectionRect = LayoutRect( |
637 font.selectionRectForText(textRun, localOrigin, selHeight, sPos, ePos)); | 647 font.selectionRectForText(textRun, localOrigin, selHeight, sPos, ePos)); |
638 if (m_inlineTextBox.hasWrappedSelectionNewline() | 648 if (m_inlineTextBox.hasWrappedSelectionNewline() |
639 // For line breaks, just painting a selection where the line break itself
is rendered is sufficient. | 649 // For line breaks, just painting a selection where the line break itself |
| 650 // is rendered is sufficient. |
640 && !m_inlineTextBox.isLineBreak()) | 651 && !m_inlineTextBox.isLineBreak()) |
641 expandToIncludeNewlineForSelection(selectionRect); | 652 expandToIncludeNewlineForSelection(selectionRect); |
642 | 653 |
643 // Line breaks report themselves as having zero width for layout purposes, | 654 // Line breaks report themselves as having zero width for layout purposes, |
644 // and so will end up positioned at (0, 0), even though we paint their | 655 // and so will end up positioned at (0, 0), even though we paint their |
645 // selection highlight with character width. For RTL then, we have to | 656 // selection highlight with character width. For RTL then, we have to |
646 // explicitly shift the selection rect over to paint in the right location. | 657 // explicitly shift the selection rect over to paint in the right location. |
647 if (!m_inlineTextBox.isLeftToRightDirection() && | 658 if (!m_inlineTextBox.isLeftToRightDirection() && |
648 m_inlineTextBox.isLineBreak()) | 659 m_inlineTextBox.isLineBreak()) |
649 selectionRect.move(-selectionRect.width(), LayoutUnit()); | 660 selectionRect.move(-selectionRect.width(), LayoutUnit()); |
(...skipping 19 matching lines...) Expand all Loading... |
669 const FontMetrics& fontMetrics, | 680 const FontMetrics& fontMetrics, |
670 const InlineTextBox* inlineTextBox, | 681 const InlineTextBox* inlineTextBox, |
671 const float textDecorationThickness) { | 682 const float textDecorationThickness) { |
672 // Compute the gap between the font and the underline. Use at least one | 683 // Compute the gap between the font and the underline. Use at least one |
673 // pixel gap, if underline is thick then use a bigger gap. | 684 // pixel gap, if underline is thick then use a bigger gap. |
674 int gap = 0; | 685 int gap = 0; |
675 | 686 |
676 // Underline position of zero means draw underline on Baseline Position, | 687 // Underline position of zero means draw underline on Baseline Position, |
677 // in Blink we need at least 1-pixel gap to adding following check. | 688 // in Blink we need at least 1-pixel gap to adding following check. |
678 // Positive underline Position means underline should be drawn above baselin e | 689 // Positive underline Position means underline should be drawn above baselin e |
679 // and negative value means drawing below baseline, negating the value as in B
link | 690 // and negative value means drawing below baseline, negating the value as in |
680 // downward Y-increases. | 691 // Blink downward Y-increases. |
681 | 692 |
682 if (fontMetrics.underlinePosition()) | 693 if (fontMetrics.underlinePosition()) |
683 gap = -fontMetrics.underlinePosition(); | 694 gap = -fontMetrics.underlinePosition(); |
684 else | 695 else |
685 gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f)); | 696 gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f)); |
686 | 697 |
687 // FIXME: We support only horizontal text for now. | 698 // FIXME: We support only horizontal text for now. |
688 switch (underlinePosition) { | 699 switch (underlinePosition) { |
689 case TextUnderlinePositionAuto: | 700 case TextUnderlinePositionAuto: |
690 return fontMetrics.ascent() + | 701 return fontMetrics.ascent() + |
691 gap; // Position underline near the alphabetic baseline. | 702 gap; // Position underline near the alphabetic baseline. |
692 case TextUnderlinePositionUnder: { | 703 case TextUnderlinePositionUnder: { |
693 // Position underline relative to the under edge of the lowest element's c
ontent box. | 704 // Position underline relative to the under edge of the lowest element's |
| 705 // content box. |
694 const LayoutUnit offset = | 706 const LayoutUnit offset = |
695 inlineTextBox->root().maxLogicalTop() - inlineTextBox->logicalTop(); | 707 inlineTextBox->root().maxLogicalTop() - inlineTextBox->logicalTop(); |
696 if (offset > 0) | 708 if (offset > 0) |
697 return (inlineTextBox->logicalHeight() + gap + offset).toInt(); | 709 return (inlineTextBox->logicalHeight() + gap + offset).toInt(); |
698 return (inlineTextBox->logicalHeight() + gap).toInt(); | 710 return (inlineTextBox->logicalHeight() + gap).toInt(); |
699 } | 711 } |
700 } | 712 } |
701 | 713 |
702 ASSERT_NOT_REACHED(); | 714 ASSERT_NOT_REACHED(); |
703 return fontMetrics.ascent() + gap; | 715 return fontMetrics.ascent() + gap; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 // Each Bezier curve starts at the same pixel that the previous one | 765 // Each Bezier curve starts at the same pixel that the previous one |
754 // ended. We need to subtract (stepCount - 1) pixels when calculating the | 766 // ended. We need to subtract (stepCount - 1) pixels when calculating the |
755 // length covered to account for that. | 767 // length covered to account for that. |
756 float uncoveredLength = length - (stepCount * step - (stepCount - 1)); | 768 float uncoveredLength = length - (stepCount * step - (stepCount - 1)); |
757 float adjustment = uncoveredLength / stepCount; | 769 float adjustment = uncoveredLength / stepCount; |
758 step += adjustment; | 770 step += adjustment; |
759 controlPointDistance += adjustment; | 771 controlPointDistance += adjustment; |
760 } | 772 } |
761 | 773 |
762 /* | 774 /* |
763 * Draw one cubic Bezier curve and repeat the same pattern long the the decorati
on's axis. | 775 * Draw one cubic Bezier curve and repeat the same pattern long the the |
764 * The start point (p1), controlPoint1, controlPoint2 and end point (p2) of the
Bezier curve | 776 * decoration's axis. The start point (p1), controlPoint1, controlPoint2 and |
765 * form a diamond shape: | 777 * end point (p2) of the Bezier curve form a diamond shape: |
766 * | 778 * |
767 * step | 779 * step |
768 * |-----------| | 780 * |-----------| |
769 * | 781 * |
770 * controlPoint1 | 782 * controlPoint1 |
771 * + | 783 * + |
772 * | 784 * |
773 * | 785 * |
774 * . . | 786 * . . |
775 * . . | 787 * . . |
(...skipping 14 matching lines...) Expand all Loading... |
790 FloatPoint p1, | 802 FloatPoint p1, |
791 FloatPoint p2, | 803 FloatPoint p2, |
792 float strokeThickness) { | 804 float strokeThickness) { |
793 context.adjustLineToPixelBoundaries(p1, p2, strokeThickness, | 805 context.adjustLineToPixelBoundaries(p1, p2, strokeThickness, |
794 context.getStrokeStyle()); | 806 context.getStrokeStyle()); |
795 | 807 |
796 Path path; | 808 Path path; |
797 path.moveTo(p1); | 809 path.moveTo(p1); |
798 | 810 |
799 // Distance between decoration's axis and Bezier curve's control points. | 811 // Distance between decoration's axis and Bezier curve's control points. |
800 // The height of the curve is based on this distance. Use a minimum of 6 pixel
s distance since | 812 // The height of the curve is based on this distance. Use a minimum of 6 |
801 // the actual curve passes approximately at half of that distance, that is 3 p
ixels. | 813 // pixels distance since the actual curve passes approximately at half of that |
802 // The minimum height of the curve is also approximately 3 pixels. Increases t
he curve's height | 814 // distance, that is 3 pixels. The minimum height of the curve is also |
| 815 // approximately 3 pixels. Increases the curve's height |
803 // as strockThickness increases to make the curve looks better. | 816 // as strockThickness increases to make the curve looks better. |
804 float controlPointDistance = 3 * std::max<float>(2, strokeThickness); | 817 float controlPointDistance = 3 * std::max<float>(2, strokeThickness); |
805 | 818 |
806 // Increment used to form the diamond shape between start point (p1), control | 819 // Increment used to form the diamond shape between start point (p1), control |
807 // points and end point (p2) along the axis of the decoration. Makes the | 820 // points and end point (p2) along the axis of the decoration. Makes the |
808 // curve wider as strockThickness increases to make the curve looks better. | 821 // curve wider as strockThickness increases to make the curve looks better. |
809 float step = 2 * std::max<float>(2, strokeThickness); | 822 float step = 2 * std::max<float>(2, strokeThickness); |
810 | 823 |
811 bool isVerticalLine = (p1.x() == p2.x()); | 824 bool isVerticalLine = (p1.x() == p2.x()); |
812 | 825 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
935 textBoxLayoutObject.getTextDecorations(deco, underline, overline, | 948 textBoxLayoutObject.getTextDecorations(deco, underline, overline, |
936 linethrough, true, true); | 949 linethrough, true, true); |
937 | 950 |
938 // Use a special function for underlines to get the positioning exactly right. | 951 // Use a special function for underlines to get the positioning exactly right. |
939 bool isPrinting = paintInfo.isPrinting(); | 952 bool isPrinting = paintInfo.isPrinting(); |
940 | 953 |
941 const ComputedStyle& styleToUse = | 954 const ComputedStyle& styleToUse = |
942 textBoxLayoutObject.styleRef(m_inlineTextBox.isFirstLineStyle()); | 955 textBoxLayoutObject.styleRef(m_inlineTextBox.isFirstLineStyle()); |
943 float baseline = styleToUse.getFontMetrics().ascent(); | 956 float baseline = styleToUse.getFontMetrics().ascent(); |
944 | 957 |
945 // Set the thick of the line to be 10% (or something else ?)of the computed fo
nt size and not less than 1px. | 958 // Set the thick of the line to be 10% (or something else ?)of the computed |
946 // Using computedFontSize should take care of zoom as well. | 959 // font size and not less than 1px. Using computedFontSize should take care |
| 960 // of zoom as well. |
947 | 961 |
948 // Update Underline thickness, in case we have Faulty Font Metrics calculating
underline thickness by old method. | 962 // Update Underline thickness, in case we have Faulty Font Metrics calculating |
| 963 // underline thickness by old method. |
949 float textDecorationThickness = | 964 float textDecorationThickness = |
950 styleToUse.getFontMetrics().underlineThickness(); | 965 styleToUse.getFontMetrics().underlineThickness(); |
951 int fontHeightInt = (int)(styleToUse.getFontMetrics().floatHeight() + 0.5); | 966 int fontHeightInt = (int)(styleToUse.getFontMetrics().floatHeight() + 0.5); |
952 if ((textDecorationThickness == 0.f) || | 967 if ((textDecorationThickness == 0.f) || |
953 (textDecorationThickness >= (fontHeightInt >> 1))) | 968 (textDecorationThickness >= (fontHeightInt >> 1))) |
954 textDecorationThickness = | 969 textDecorationThickness = |
955 std::max(1.f, styleToUse.computedFontSize() / 10.f); | 970 std::max(1.f, styleToUse.computedFontSize() / 10.f); |
956 | 971 |
957 context.setStrokeThickness(textDecorationThickness); | 972 context.setStrokeThickness(textDecorationThickness); |
958 | 973 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1019 } else { | 1034 } else { |
1020 unsigned paintFrom = ltr == flowIsLTR ? paintStart : paintEnd; | 1035 unsigned paintFrom = ltr == flowIsLTR ? paintStart : paintEnd; |
1021 unsigned paintLength = | 1036 unsigned paintLength = |
1022 ltr == flowIsLTR | 1037 ltr == flowIsLTR |
1023 ? paintEnd - paintStart | 1038 ? paintEnd - paintStart |
1024 : m_inlineTextBox.start() + m_inlineTextBox.len() - paintEnd; | 1039 : m_inlineTextBox.start() + m_inlineTextBox.len() - paintEnd; |
1025 width = m_inlineTextBox.getLineLayoutItem().width( | 1040 width = m_inlineTextBox.getLineLayoutItem().width( |
1026 paintFrom, paintLength, LayoutUnit(m_inlineTextBox.textPos() + start), | 1041 paintFrom, paintLength, LayoutUnit(m_inlineTextBox.textPos() + start), |
1027 flowIsLTR ? LTR : RTL, m_inlineTextBox.isFirstLineStyle()); | 1042 flowIsLTR ? LTR : RTL, m_inlineTextBox.isFirstLineStyle()); |
1028 } | 1043 } |
1029 // In RTL mode, start and width are computed from the right end of the text bo
x: | 1044 // In RTL mode, start and width are computed from the right end of the text |
1030 // starting at |logicalWidth| - |start| and continuing left by |width| to | 1045 // box: starting at |logicalWidth| - |start| and continuing left by |width| to |
1031 // |logicalWidth| - |start| - |width|. We will draw that line, but | 1046 // |logicalWidth| - |start| - |width|. We will draw that line, but backwards: |
1032 // backwards: |logicalWidth| - |start| - |width| to |logicalWidth| - |start|. | 1047 // |logicalWidth| - |start| - |width| to |logicalWidth| - |start|. |
1033 if (!flowIsLTR) | 1048 if (!flowIsLTR) |
1034 start = m_inlineTextBox.logicalWidth().toFloat() - width - start; | 1049 start = m_inlineTextBox.logicalWidth().toFloat() - width - start; |
1035 | 1050 |
1036 // Thick marked text underlines are 2px thick as long as there is room for the
2px line under the baseline. | 1051 // Thick marked text underlines are 2px thick as long as there is room for the |
1037 // All other marked text underlines are 1px thick. | 1052 // 2px line under the baseline. All other marked text underlines are 1px |
1038 // If there's not enough space the underline will touch or overlap characters. | 1053 // thick. If there's not enough space the underline will touch or overlap |
| 1054 // characters. |
1039 int lineThickness = 1; | 1055 int lineThickness = 1; |
1040 int baseline = m_inlineTextBox.getLineLayoutItem() | 1056 int baseline = m_inlineTextBox.getLineLayoutItem() |
1041 .style(m_inlineTextBox.isFirstLineStyle()) | 1057 .style(m_inlineTextBox.isFirstLineStyle()) |
1042 ->getFontMetrics() | 1058 ->getFontMetrics() |
1043 .ascent(); | 1059 .ascent(); |
1044 if (underline.thick() && m_inlineTextBox.logicalHeight() - baseline >= 2) | 1060 if (underline.thick() && m_inlineTextBox.logicalHeight() - baseline >= 2) |
1045 lineThickness = 2; | 1061 lineThickness = 2; |
1046 | 1062 |
1047 // We need to have some space between underlines of subsequent clauses, becaus
e some input methods do not use different underline styles for those. | 1063 // We need to have some space between underlines of subsequent clauses, |
1048 // We make each line shorter, which has a harmless side effect of shortening t
he first and last clauses, too. | 1064 // because some input methods do not use different underline styles for those. |
| 1065 // We make each line shorter, which has a harmless side effect of shortening |
| 1066 // the first and last clauses, too. |
1049 start += 1; | 1067 start += 1; |
1050 width -= 2; | 1068 width -= 2; |
1051 | 1069 |
1052 context.setStrokeColor(underline.color()); | 1070 context.setStrokeColor(underline.color()); |
1053 context.setStrokeThickness(lineThickness); | 1071 context.setStrokeThickness(lineThickness); |
1054 context.drawLineForText( | 1072 context.drawLineForText( |
1055 FloatPoint( | 1073 FloatPoint( |
1056 boxOrigin.x() + start, | 1074 boxOrigin.x() + start, |
1057 (boxOrigin.y() + m_inlineTextBox.logicalHeight() - lineThickness) | 1075 (boxOrigin.y() + m_inlineTextBox.logicalHeight() - lineThickness) |
1058 .toFloat()), | 1076 .toFloat()), |
1059 width, m_inlineTextBox.getLineLayoutItem().document().printing()); | 1077 width, m_inlineTextBox.getLineLayoutItem().document().printing()); |
1060 } | 1078 } |
1061 | 1079 |
1062 void InlineTextBoxPainter::paintTextMatchMarkerForeground( | 1080 void InlineTextBoxPainter::paintTextMatchMarkerForeground( |
1063 const PaintInfo& paintInfo, | 1081 const PaintInfo& paintInfo, |
1064 const LayoutPoint& boxOrigin, | 1082 const LayoutPoint& boxOrigin, |
1065 DocumentMarker* marker, | 1083 DocumentMarker* marker, |
1066 const ComputedStyle& style, | 1084 const ComputedStyle& style, |
1067 const Font& font) { | 1085 const Font& font) { |
1068 if (!inlineLayoutObject().frame()->editor().markedTextMatchesAreHighlighted()) | 1086 if (!inlineLayoutObject().frame()->editor().markedTextMatchesAreHighlighted()) |
1069 return; | 1087 return; |
1070 | 1088 |
1071 // TODO(ramya.v): Extract this into a helper function and share many copies of
this code. | 1089 // TODO(ramya.v): Extract this into a helper function and share many copies of |
| 1090 // this code. |
1072 int sPos = | 1091 int sPos = |
1073 std::max(marker->startOffset() - m_inlineTextBox.start(), (unsigned)0); | 1092 std::max(marker->startOffset() - m_inlineTextBox.start(), (unsigned)0); |
1074 int ePos = std::min(marker->endOffset() - m_inlineTextBox.start(), | 1093 int ePos = std::min(marker->endOffset() - m_inlineTextBox.start(), |
1075 m_inlineTextBox.len()); | 1094 m_inlineTextBox.len()); |
1076 TextRun run = m_inlineTextBox.constructTextRun(style); | 1095 TextRun run = m_inlineTextBox.constructTextRun(style); |
1077 | 1096 |
1078 Color textColor = | 1097 Color textColor = |
1079 LayoutTheme::theme().platformTextSearchColor(marker->activeMatch()); | 1098 LayoutTheme::theme().platformTextSearchColor(marker->activeMatch()); |
1080 if (style.visitedDependentColor(CSSPropertyColor) == textColor) | 1099 if (style.visitedDependentColor(CSSPropertyColor) == textColor) |
1081 return; | 1100 return; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1119 GraphicsContextStateSaver stateSaver(context); | 1138 GraphicsContextStateSaver stateSaver(context); |
1120 | 1139 |
1121 LayoutRect boxRect(boxOrigin, LayoutSize(m_inlineTextBox.logicalWidth(), | 1140 LayoutRect boxRect(boxOrigin, LayoutSize(m_inlineTextBox.logicalWidth(), |
1122 m_inlineTextBox.logicalHeight())); | 1141 m_inlineTextBox.logicalHeight())); |
1123 context.clip(FloatRect(boxRect)); | 1142 context.clip(FloatRect(boxRect)); |
1124 context.drawHighlightForText(font, run, FloatPoint(boxOrigin), | 1143 context.drawHighlightForText(font, run, FloatPoint(boxOrigin), |
1125 boxRect.height().toInt(), color, sPos, ePos); | 1144 boxRect.height().toInt(), color, sPos, ePos); |
1126 } | 1145 } |
1127 | 1146 |
1128 } // namespace blink | 1147 } // namespace blink |
OLD | NEW |