Bug 759568 - Part 3. Render text-selection beneath background image;
MozReview-Commit-ID: IZvMfZYqmnZ
--- 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)
};
@@ -5917,17 +5927,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);
@@ -6072,17 +6081,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;
@@ -6476,16 +6485,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
@@ -6539,17 +6581,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) { }
/**