Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp

Issue 1328283005: Add support for multiple text decorations with same line positioning (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Rebase Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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"
11 #include "core/editing/markers/RenderedDocumentMarker.h" 11 #include "core/editing/markers/RenderedDocumentMarker.h"
12 #include "core/frame/LocalFrame.h" 12 #include "core/frame/LocalFrame.h"
13 #include "core/layout/LayoutBlock.h" 13 #include "core/layout/LayoutBlock.h"
14 #include "core/layout/LayoutTextCombine.h" 14 #include "core/layout/LayoutTextCombine.h"
15 #include "core/layout/LayoutTheme.h" 15 #include "core/layout/LayoutTheme.h"
16 #include "core/layout/api/LineLayoutBox.h" 16 #include "core/layout/api/LineLayoutBox.h"
17 #include "core/layout/api/LineLayoutText.h" 17 #include "core/layout/api/LineLayoutText.h"
18 #include "core/layout/line/InlineTextBox.h" 18 #include "core/layout/line/InlineTextBox.h"
19 #include "core/paint/BoxPainter.h" 19 #include "core/paint/BoxPainter.h"
20 #include "core/paint/LineLayoutPaintShim.h" 20 #include "core/paint/LineLayoutPaintShim.h"
21 #include "core/paint/PaintInfo.h" 21 #include "core/paint/PaintInfo.h"
22 #include "core/paint/TextPainter.h" 22 #include "core/paint/TextPainter.h"
23 #include "core/style/AppliedTextDecoration.h"
23 #include "platform/graphics/GraphicsContextStateSaver.h" 24 #include "platform/graphics/GraphicsContextStateSaver.h"
24 #include "platform/graphics/paint/DrawingRecorder.h" 25 #include "platform/graphics/paint/DrawingRecorder.h"
25 #include "wtf/Optional.h" 26 #include "wtf/Optional.h"
26 27
27 namespace blink { 28 namespace blink {
28 29
29 typedef WTF::HashMap<const InlineTextBox*, TextBlobPtr> InlineTextBoxBlobCacheMa p; 30 typedef WTF::HashMap<const InlineTextBox*, TextBlobPtr> InlineTextBoxBlobCacheMa p;
30 static InlineTextBoxBlobCacheMap* gTextBlobCache; 31 static InlineTextBoxBlobCacheMap* gTextBlobCache;
31 32
32 static const int misspellingLineThickness = 3; 33 static const int misspellingLineThickness = 3;
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 if ((paintSelectedTextOnly || paintSelectedTextSeparately) && selectionStart < selectionEnd) { 225 if ((paintSelectedTextOnly || paintSelectedTextSeparately) && selectionStart < selectionEnd) {
225 // paint only the text that is selected 226 // paint only the text that is selected
226 bool textBlobIsCacheable = selectionStart == 0 && selectionEnd == length ; 227 bool textBlobIsCacheable = selectionStart == 0 && selectionEnd == length ;
227 TextBlobPtr* cachedTextBlob = 0; 228 TextBlobPtr* cachedTextBlob = 0;
228 if (textBlobIsCacheable) 229 if (textBlobIsCacheable)
229 cachedTextBlob = addToTextBlobCache(m_inlineTextBox); 230 cachedTextBlob = addToTextBlobCache(m_inlineTextBox);
230 textPainter.paint(selectionStart, selectionEnd, length, selectionStyle, cachedTextBlob); 231 textPainter.paint(selectionStart, selectionEnd, length, selectionStyle, cachedTextBlob);
231 } 232 }
232 233
233 // Paint decorations 234 // Paint decorations
234 TextDecoration textDecorations = styleToUse.textDecorationsInEffect(); 235 if (styleToUse.textDecorationsInEffect() != TextDecorationNone && !paintSele ctedTextOnly) {
235 if (textDecorations != TextDecorationNone && !paintSelectedTextOnly) {
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 paintDecorations(paintInfo, boxOrigin, styleToUse.appliedTextDecorations ());
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(context, boxOrigin, styleToUse, font, false);
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 }
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 if (offset > 0) 543 if (offset > 0)
544 return inlineTextBox->logicalHeight() + gap + offset; 544 return inlineTextBox->logicalHeight() + gap + offset;
545 return inlineTextBox->logicalHeight() + gap; 545 return inlineTextBox->logicalHeight() + gap;
546 } 546 }
547 } 547 }
548 548
549 ASSERT_NOT_REACHED(); 549 ASSERT_NOT_REACHED();
550 return fontMetrics.ascent() + gap; 550 return fontMetrics.ascent() + gap;
551 } 551 }
552 552
553 static bool shouldSetDecorationAntialias(TextDecorationStyle decorationStyle) 553 static bool shouldSetDecorationAntialias(const Vector<AppliedTextDecoration>& de corations)
554 { 554 {
555 return decorationStyle == TextDecorationStyleDotted || decorationStyle == Te xtDecorationStyleDashed; 555 for (const AppliedTextDecoration& decoration : decorations) {
556 } 556 TextDecorationStyle decorationStyle = decoration.style();
557 557 if (decorationStyle == TextDecorationStyleDotted || decorationStyle == T extDecorationStyleDashed)
558 static bool shouldSetDecorationAntialias(TextDecorationStyle underline, TextDeco rationStyle overline, TextDecorationStyle linethrough) 558 return true;
559 { 559 }
560 return shouldSetDecorationAntialias(underline) || shouldSetDecorationAntiali as(overline) || shouldSetDecorationAntialias(linethrough); 560 return false;
561 } 561 }
562 562
563 static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorati onStyle) 563 static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorati onStyle)
564 { 564 {
565 StrokeStyle strokeStyle = SolidStroke; 565 StrokeStyle strokeStyle = SolidStroke;
566 switch (decorationStyle) { 566 switch (decorationStyle) {
567 case TextDecorationStyleSolid: 567 case TextDecorationStyleSolid:
568 strokeStyle = SolidStroke; 568 strokeStyle = SolidStroke;
569 break; 569 break;
570 case TextDecorationStyleDouble: 570 case TextDecorationStyleDouble:
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 controlPoint2.setX(x + step); 699 controlPoint2.setX(x + step);
700 x += 2 * step; 700 x += 2 * step;
701 path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yA xis)); 701 path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yA xis));
702 } 702 }
703 } 703 }
704 704
705 context.setShouldAntialias(true); 705 context.setShouldAntialias(true);
706 context.strokePath(path); 706 context.strokePath(path);
707 } 707 }
708 708
709 static void paintAppliedDecoration(GraphicsContext& context, FloatPoint start, f loat width, float doubleOffset, int wavyOffsetFactor, 709 static void paintAppliedDecoration(GraphicsContext* context, FloatPoint start, f loat width, float doubleOffset, int wavyOffsetFactor,
710 LayoutObject::AppliedTextDecoration decoration, float thickness, bool antial iasDecoration, bool isPrinting) 710 AppliedTextDecoration decoration, float thickness, bool antialiasDecoration, bool isPrinting)
711 { 711 {
712 context.setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style)); 712 context.setStrokeStyle(textDecorationStyleToStrokeStyle(decoration.style())) ;
713 context.setStrokeColor(decoration.color); 713 context.setStrokeColor(decoration.color());
714 714
715 switch (decoration.style) { 715 switch (decoration.style()) {
716 case TextDecorationStyleWavy: 716 case TextDecorationStyleWavy:
717 strokeWavyTextDecoration(context, start + FloatPoint(0, doubleOffset * w avyOffsetFactor), start + FloatPoint(width, doubleOffset * wavyOffsetFactor), th ickness); 717 strokeWavyTextDecoration(context, start + FloatPoint(0, doubleOffset * w avyOffsetFactor), start + FloatPoint(width, doubleOffset * wavyOffsetFactor), th ickness);
718 break; 718 break;
719 case TextDecorationStyleDotted: 719 case TextDecorationStyleDotted:
720 case TextDecorationStyleDashed: 720 case TextDecorationStyleDashed:
721 context.setShouldAntialias(antialiasDecoration); 721 context.setShouldAntialias(antialiasDecoration);
722 // Fall through 722 // Fall through
723 default: 723 default:
724 context.drawLineForText(FloatPoint(start), width, isPrinting); 724 context.drawLineForText(FloatPoint(start), width, isPrinting);
725 725
726 if (decoration.style == TextDecorationStyleDouble) 726 if (decoration.style() == TextDecorationStyleDouble)
727 context.drawLineForText(start + FloatPoint(0, doubleOffset), width, isPrinting); 727 context.drawLineForText(start + FloatPoint(0, doubleOffset), width, isPrinting);
728 } 728 }
729 } 729 }
730 730
731 void InlineTextBoxPainter::paintDecoration(const PaintInfo& paintInfo, const Lay outPoint& boxOrigin, TextDecoration deco) 731 void InlineTextBoxPainter::paintDecorations(const PaintInfo& paintInfo, const La youtPoint& boxOrigin, const Vector<AppliedTextDecoration>& decorations)
732 { 732 {
733 if (m_inlineTextBox.truncation() == cFullTruncation) 733 if (m_inlineTextBox.truncation() == cFullTruncation)
734 return; 734 return;
735 735
736 GraphicsContext& context = paintInfo.context; 736 GraphicsContext& context = paintInfo.context;
737 GraphicsContextStateSaver stateSaver(context); 737 GraphicsContextStateSaver stateSaver(context);
738 738
739 LayoutPoint localOrigin(boxOrigin); 739 LayoutPoint localOrigin(boxOrigin);
740 740
741 LayoutUnit width = m_inlineTextBox.logicalWidth(); 741 LayoutUnit width = m_inlineTextBox.logicalWidth();
742 if (m_inlineTextBox.truncation() != cNoTruncation) { 742 if (m_inlineTextBox.truncation() != cNoTruncation) {
743 width = m_inlineTextBox.lineLayoutItem().width(m_inlineTextBox.start(), m_inlineTextBox.truncation(), m_inlineTextBox.textPos(), m_inlineTextBox.isLeftT oRightDirection() ? LTR : RTL, m_inlineTextBox.isFirstLineStyle()); 743 width = m_inlineTextBox.lineLayoutItem().width(m_inlineTextBox.start(), m_inlineTextBox.truncation(), m_inlineTextBox.textPos(), m_inlineTextBox.isLeftT oRightDirection() ? LTR : RTL, m_inlineTextBox.isFirstLineStyle());
744 if (!m_inlineTextBox.isLeftToRightDirection()) 744 if (!m_inlineTextBox.isLeftToRightDirection())
745 localOrigin.move(m_inlineTextBox.logicalWidth() - width, 0); 745 localOrigin.move(m_inlineTextBox.logicalWidth() - width, 0);
746 } 746 }
747 747
748 // Get the text decoration colors.
749 LayoutObject::AppliedTextDecoration underline, overline, linethrough;
750 LayoutObject& textBoxLayoutObject = *LineLayoutPaintShim::layoutObjectFrom(m _inlineTextBox.lineLayoutItem());
751 textBoxLayoutObject.getTextDecorations(deco, underline, overline, linethroug h, true);
752 if (m_inlineTextBox.isFirstLineStyle())
753 textBoxLayoutObject.getTextDecorations(deco, underline, overline, lineth rough, true, true);
754
755 // Use a special function for underlines to get the positioning exactly righ t. 748 // Use a special function for underlines to get the positioning exactly righ t.
756 bool isPrinting = paintInfo.isPrinting(); 749 bool isPrinting = paintInfo.isPrinting();
757 750
751 LayoutObject& textBoxLayoutObject = *LineLayoutPaintShim::layoutObjectFrom(m _inlineTextBox.lineLayoutItem());
758 const ComputedStyle& styleToUse = textBoxLayoutObject.styleRef(m_inlineTextB ox.isFirstLineStyle()); 752 const ComputedStyle& styleToUse = textBoxLayoutObject.styleRef(m_inlineTextB ox.isFirstLineStyle());
759 float baseline = styleToUse.fontMetrics().ascent(); 753 float baseline = styleToUse.fontMetrics().ascent();
760 754
761 // Set the thick of the line to be 10% (or something else ?)of the computed font size and not less than 1px. 755 // Set the thick of the line to be 10% (or something else ?)of the computed font size and not less than 1px.
762 // Using computedFontSize should take care of zoom as well. 756 // Using computedFontSize should take care of zoom as well.
763 757
764 // Update Underline thickness, in case we have Faulty Font Metrics calculati ng underline thickness by old method. 758 // Update Underline thickness, in case we have Faulty Font Metrics calculati ng underline thickness by old method.
765 float textDecorationThickness = styleToUse.fontMetrics().underlineThickness( ); 759 float textDecorationThickness = styleToUse.fontMetrics().underlineThickness( );
766 int fontHeightInt = (int)(styleToUse.fontMetrics().floatHeight() + 0.5); 760 int fontHeightInt = (int)(styleToUse.fontMetrics().floatHeight() + 0.5);
767 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fontHei ghtInt >> 1))) 761 if ((textDecorationThickness == 0.f) || (textDecorationThickness >= (fontHei ghtInt >> 1)))
768 textDecorationThickness = std::max(1.f, styleToUse.computedFontSize() / 10.f); 762 textDecorationThickness = std::max(1.f, styleToUse.computedFontSize() / 10.f);
769 763
770 context.setStrokeThickness(textDecorationThickness); 764 context.setStrokeThickness(textDecorationThickness);
771 765
772 bool antialiasDecoration = shouldSetDecorationAntialias(overline.style, unde rline.style, linethrough.style); 766 bool antialiasDecoration = shouldSetDecorationAntialias(decorations);
773 767
774 // Offset between lines - always non-zero, so lines never cross each other. 768 // Offset between lines - always non-zero, so lines never cross each other.
775 float doubleOffset = textDecorationThickness + 1.f; 769 float doubleOffset = textDecorationThickness + 1.f;
776 770
777 if (deco & TextDecorationUnderline) { 771 for (const AppliedTextDecoration& decoration : decorations) {
778 const int underlineOffset = computeUnderlineOffset(styleToUse.textUnderl inePosition(), styleToUse.fontMetrics(), &m_inlineTextBox, textDecorationThickne ss); 772 TextDecoration lines = decoration.lines();
779 paintAppliedDecoration(context, FloatPoint(localOrigin) + FloatPoint(0, underlineOffset), width.toFloat(), doubleOffset, 1, underline, textDecorationThi ckness, antialiasDecoration, isPrinting); 773 if (lines & TextDecorationUnderline) {
780 } 774 const int underlineOffset = computeUnderlineOffset(styleToUse.textUn derlinePosition(), styleToUse.fontMetrics(), &m_inlineTextBox, textDecorationThi ckness);
781 if (deco & TextDecorationOverline) { 775 paintAppliedDecoration(context, FloatPoint(localOrigin) + FloatPoint (0, underlineOffset), width.toFloat(), doubleOffset, 1, decoration, textDecorati onThickness, antialiasDecoration, isPrinting);
782 paintAppliedDecoration(context, FloatPoint(localOrigin), width.toFloat() , -doubleOffset, 1, overline, textDecorationThickness, antialiasDecoration, isPr inting); 776 }
783 } 777 if (lines & TextDecorationOverline) {
784 if (deco & TextDecorationLineThrough) { 778 paintAppliedDecoration(context, FloatPoint(localOrigin), width.toFlo at(), -doubleOffset, 1, decoration, textDecorationThickness, antialiasDecoration , isPrinting);
785 const float lineThroughOffset = 2 * baseline / 3; 779 }
786 paintAppliedDecoration(context, FloatPoint(localOrigin) + FloatPoint(0, lineThroughOffset), width.toFloat(), doubleOffset, 0, linethrough, textDecoratio nThickness, antialiasDecoration, isPrinting); 780 if (lines & TextDecorationLineThrough) {
781 const float lineThroughOffset = 2 * baseline / 3;
782 paintAppliedDecoration(context, FloatPoint(localOrigin) + FloatPoint (0, lineThroughOffset), width.toFloat(), doubleOffset, 0, decoration, textDecora tionThickness, antialiasDecoration, isPrinting);
783 }
787 } 784 }
788 } 785 }
789 786
790 void InlineTextBoxPainter::paintCompositionUnderline(GraphicsContext& context, c onst LayoutPoint& boxOrigin, const CompositionUnderline& underline) 787 void InlineTextBoxPainter::paintCompositionUnderline(GraphicsContext& context, c onst LayoutPoint& boxOrigin, const CompositionUnderline& underline)
791 { 788 {
792 if (underline.color == Color::transparent) 789 if (underline.color == Color::transparent)
793 return; 790 return;
794 791
795 if (m_inlineTextBox.truncation() == cFullTruncation) 792 if (m_inlineTextBox.truncation() == cFullTruncation)
796 return; 793 return;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
863 LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetri cs().ascent()); 860 LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetri cs().ascent());
864 TextPainter textPainter(context, font, run, textOrigin, boxRect, m_i nlineTextBox.isHorizontal()); 861 TextPainter textPainter(context, font, run, textOrigin, boxRect, m_i nlineTextBox.isHorizontal());
865 862
866 textPainter.paint(sPos, ePos, length, textStyle, 0); 863 textPainter.paint(sPos, ePos, length, textStyle, 0);
867 } 864 }
868 } 865 }
869 } 866 }
870 867
871 868
872 } // namespace blink 869 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698