Bug 759568 - Part 3. Render text-selection beneath background image; r=jfkthame
☠☠ backed out by b59e99ea6dad ☠ ☠
authorCJKu <cku@mozilla.com>
Thu, 14 Apr 2016 12:45:38 +0800
changeset 331089 e9fc67d8b0fad9fbd3288611395fd9b5fd484c9c
parent 331088 6a2e62e8c861e742c5023a189df7ca98045f18ef
child 331090 2d26ad2b9a09207f5b437e8d93813dd4d342820b
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs759568
milestone48.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 759568 - Part 3. Render text-selection beneath background image; r=jfkthame MozReview-Commit-ID: 3VUGqyJOX8Q
layout/generic/nsTextFrame.cpp
layout/generic/nsTextFrame.h
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -93,16 +93,26 @@
 #ifdef DrawText
 #undef DrawText
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
+void
+nsTextFrame::DrawPathCallbacks::NotifySelectionBackgroundNeedsFill(
+                                                    const Rect& aBackgroundRect,
+                                                    nscolor aColor,
+                                                    DrawTarget& aDrawTarget)
+{
+  ColorPattern color(ToDeviceColor(aColor));
+  aDrawTarget.FillRect(aBackgroundRect, color);
+}
+
 struct TabWidth {
   TabWidth(uint32_t aOffset, uint32_t aWidth)
     : mOffset(aOffset), mWidth(float(aWidth))
   { }
 
   uint32_t mOffset; // DOM offset relative to the current frame's offset.
   float    mWidth;  // extra space to be added at this position (in app units)
 };
@@ -5878,17 +5888,16 @@ nsTextFrame::PaintOneShadow(const PaintS
     shadowColor = aShadowDetails->mColor;
     decorationOverrideColor = &shadowColor;
   } else {
     shadowColor = aParams.foregroundColor;
     decorationOverrideColor = nullptr;
   }
 
   aParams.context->Save();
-  aParams.context->NewPath();
   aParams.context->SetColor(Color::FromABGR(shadowColor));
 
   // Draw the text onto our alpha-only surface to capture the alpha values.
   // Remember that the box blur context has a device offset on it, so we don't need to
   // translate any coordinates to fit on the surface.
   gfxFloat advanceWidth;
   nsTextPaintStyle textPaintStyle(this);
   DrawTextParams params(shadowContext);
@@ -6033,17 +6042,17 @@ nsTextFrame::PaintTextWithSelectionColor
     gfxPoint textBaselinePt = vertical ?
       gfxPoint(aParams.textBaselinePt.x, aParams.framePt.y + iOffset) :
       gfxPoint(aParams.framePt.x + iOffset, aParams.textBaselinePt.y);
 
     // Determine what shadow, if any, to draw - either from textStyle
     // or from the ::-moz-selection pseudo-class if specified there
     nsCSSShadowArray* shadow = textStyle->GetTextShadow();
     GetSelectionTextShadow(this, type, *aParams.textPaintStyle, &shadow);
-    if (shadow) {
+    if (shadow && !aParams.callbacks) {
       nscoord startEdge = iOffset;
       if (mTextRun->IsInlineReversed()) {
         startEdge -= hyphenWidth +
           mTextRun->GetAdvanceWidth(range, aParams.provider);
       }
       shadowParams.range = range;
       shadowParams.textBaselinePt = textBaselinePt;
       shadowParams.foregroundColor = foreground;
@@ -6437,16 +6446,49 @@ nsTextFrame::PaintShadows(nsCSSShadowArr
   }
 
   for (uint32_t i = aShadow->Length(); i > 0; --i) {
     PaintOneShadow(aParams, aShadow->ShadowAt(i - 1),
                    shadowMetrics.mBoundingBox, blurFlags);
   }
 }
 
+static bool
+ShouldDrawSelection(const nsIFrame* aFrame,
+                    const nsTextFrame::PaintTextParams& aParams)
+{
+  // Normal text-with-selection rendering sequence is:
+  //   * Paint background > Paint text-selection-color > Paint text
+  // When we have an parent frame with background-clip-text style, rendering
+  // sequence changes to:
+  //   * Paint text-selection-color > Paint background > Paint text
+  //
+  // If there is a parent frame has background-clip:text style,
+  // text-selection-color should be drawn with the background of that parent
+  // frame, so we should not draw it again while painting text frames.
+  //
+  // "aParams.callbacks != nullptr": it means we are currently painting
+  // background. We should paint text-selection-color.
+  // "aParams.callbacks == nullptr": it means we are currently painting text
+  // frame itself. We should not paint text-selection-color.
+  if (!aFrame || aParams.callbacks) {
+    return true;
+  }
+
+  const nsStyleBackground* bg = aFrame->StyleContext()->StyleBackground();
+  const nsStyleImageLayers& layers = bg->mImage;
+  NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, layers) {
+    if (layers.mLayers[i].mClip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
+      return false;
+    }
+  }
+
+  return ShouldDrawSelection(aFrame->GetParent(), aParams);
+}
+
 void
 nsTextFrame::PaintText(const PaintTextParams& aParams,
                        const nsCharClipDisplayItem& aItem,
                        float aOpacity /* = 1.0f */)
 {
   // Don't pass in the rendering context here, because we need a
   // *reference* context and rendering context might have some transform
   // in it
@@ -6500,17 +6542,18 @@ nsTextFrame::PaintText(const PaintTextPa
     textBaselinePt.x += reversed ? -snappedEndEdge : snappedStartEdge;
   }
   nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedStartEdge,
                                              snappedEndEdge);
   nsTextPaintStyle textPaintStyle(this);
   textPaintStyle.SetResolveColors(!aParams.callbacks);
 
   // Fork off to the (slower) paint-with-selection path if necessary.
-  if (aItem.mIsFrameSelected.value()) {
+  if (aItem.mIsFrameSelected.value() &&
+      ShouldDrawSelection(this->GetParent(), aParams)) {
     MOZ_ASSERT(aOpacity == 1.0f, "We don't support opacity with selections!");
     gfxSkipCharsIterator tmp(provider.GetStart());
     Range contentRange(
       uint32_t(tmp.ConvertSkippedToOriginal(startOffset)),
       uint32_t(tmp.ConvertSkippedToOriginal(startOffset + maxLength)));
     PaintTextSelectionParams params(aParams);
     params.textBaselinePt = textBaselinePt;
     params.provider = &provider;
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -344,17 +344,17 @@ public:
     }
 
     /**
      * Called to have the selection highlight drawn before the text is drawn
      * over the top.
      */
     virtual void NotifySelectionBackgroundNeedsFill(const Rect& aBackgroundRect,
                                                     nscolor aColor,
-                                                    DrawTarget& aDrawTarget) { }
+                                                    DrawTarget& aDrawTarget);
 
     /**
      * Called before (for under/over-line) or after (for line-through) the text
      * is drawn to have a text decoration line drawn.
      */
     virtual void PaintDecorationLine(Rect aPath, nscolor aColor) { }
 
     /**