Bug 1399310 - (Part 1) Make `nsTextFrame::DrawTextRunAndDecorations` draw only in the range of the text. r=jfkthame
authorKuoE0 <kuoe0.tw@gmail.com>
Wed, 27 Sep 2017 16:50:15 +0800
changeset 443551 0564a1d6d2d6ae8bbb00afcfb4fa289211854d64
parent 443550 046aa4f8f7583671dc3c682e544a20e84eaf5478
child 443552 fb90190ba5b1d880c743f90b7634397c8c3abe9b
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1399310
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1399310 - (Part 1) Make `nsTextFrame::DrawTextRunAndDecorations` draw only in the range of the text. r=jfkthame We create a clip region with the text length to make the decoration line would be only drawn in the area. This allows the decoration line would not be drawn multiple times when the text is being selected. MozReview-Commit-ID: 4gjawk71eSu
layout/generic/nsTextFrame.cpp
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -7265,29 +7265,67 @@ nsTextFrame::DrawTextRunAndDecorations(R
       bCoord = (frameBStart - dec.mBaselineOffset) / app;
 
       params.color = dec.mColor;
       params.offset = metrics.*lineOffset;
       params.style = dec.mStyle;
       PaintDecorationLine(params);
     };
 
+    // We create a clip region in order to draw the decoration lines only in the
+    // range of the text. Restricting the draw area prevents the decoration lines
+    // to be drawn multiple times when a part of the text is selected.
+
+    // We skip clipping for the following cases:
+    // - drawing the whole text
+    // - having different orientation of the text and the writing-mode, such as
+    //   "text-combine-upright" (Bug 1408825)
+    bool skipClipping = aRange.Length() == mTextRun->GetLength() ||
+                        verticalDec != verticalRun;
+
+    gfxRect clipRect;
+    if (!skipClipping) {
+      // Get the inline-size according to the specified range.
+      gfxFloat clipLength = mTextRun->GetAdvanceWidth(aRange, aParams.provider);
+
+      clipRect.width = verticalDec ? frameSize.width : clipLength / app;
+      clipRect.height = verticalDec ? clipLength / app : frameSize.height;
+
+      const bool isInlineReversed = mTextRun->IsInlineReversed();
+      if (verticalDec) {
+        clipRect.y = (isInlineReversed ? aTextBaselinePt.y - clipLength
+                                       : aTextBaselinePt.y) / app;
+      } else {
+        clipRect.x = (isInlineReversed ? aTextBaselinePt.x - clipLength
+                                       : aTextBaselinePt.x) / app;
+      }
+
+      clipRect.Round();
+      params.context->Clip(clipRect);
+    }
+
     // Underlines
     params.decoration = NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
     for (const LineDecoration& dec : Reversed(aDecorations.mUnderlines)) {
       paintDecorationLine(dec, &Metrics::underlineSize,
                           &Metrics::underlineOffset);
     }
 
     // Overlines
     params.decoration = NS_STYLE_TEXT_DECORATION_LINE_OVERLINE;
     for (const LineDecoration& dec : Reversed(aDecorations.mOverlines)) {
       paintDecorationLine(dec, &Metrics::underlineSize, &Metrics::maxAscent);
     }
 
+    // Some glyphs and emphasis marks may extend outside the region, so we reset
+    // the clip region here. For an example, italic glyphs.
+    if (!skipClipping) {
+      params.context->PopClip();
+    }
+
     {
       gfxContextMatrixAutoSaveRestore unscaledRestorer;
       if (scaledRestorer.HasMatrix()) {
         unscaledRestorer.SetContext(aParams.context);
         aParams.context->SetMatrix(scaledRestorer.Matrix());
       }
 
       // CSS 2.1 mandates that text be painted after over/underlines,
@@ -7295,22 +7333,31 @@ nsTextFrame::DrawTextRunAndDecorations(R
       DrawTextRun(aRange, aTextBaselinePt, aParams);
     }
 
     // Emphasis marks
     DrawEmphasisMarks(aParams.context, wm,
                       aTextBaselinePt, aParams.framePt, aRange,
                       aParams.decorationOverrideColor, aParams.provider);
 
+    // Re-apply the clip region when the line-through is being drawn.
+    if (!skipClipping) {
+      params.context->Clip(clipRect);
+    }
+
     // Line-throughs
     params.decoration = NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
     for (const LineDecoration& dec : Reversed(aDecorations.mStrikes)) {
       paintDecorationLine(dec, &Metrics::strikeoutSize,
                           &Metrics::strikeoutOffset);
     }
+
+    if (!skipClipping) {
+      params.context->PopClip();
+    }
 }
 
 void
 nsTextFrame::DrawText(Range aRange, const gfx::Point& aTextBaselinePt,
                       const DrawTextParams& aParams)
 {
   TextDecorations decorations;
   GetTextDecorations(aParams.textStyle->PresContext(),