author | Michael Ventnor <mventnor@mozilla.com> |
Fri, 01 Jul 2011 16:43:11 +1000 | |
changeset 72117 | 2fba916e056cdb24bd569a6b8ab9ea69b90c7c25 |
parent 72116 | 592403064072fe729609a03d4d4eed7c47e16fff |
child 72118 | e8023ac96fb770f73baeb3a985b64388f7a2c184 |
push id | 20656 |
push user | mventnor@mozilla.com |
push date | Fri, 01 Jul 2011 06:43:51 +0000 |
treeherder | mozilla-central@2fba916e056c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc |
milestone | 7.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
|
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2884,16 +2884,71 @@ nsLayoutUtils::GetStringWidth(const nsIF direction, presContext, *aContext); } } #endif // IBMBIDI aContext->SetTextRunRTL(PR_FALSE); return aContext->GetWidth(aString, aLength); } +/* static */ void +nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame, + nsRenderingContext* aContext, + const nsRect& aTextRect, + const nsRect& aDirtyRect, + const nscolor& aForegroundColor, + TextShadowCallback aCallback, + void* aCallbackData) +{ + const nsStyleText* textStyle = aFrame->GetStyleText(); + if (!textStyle->mTextShadow) + return; + + // Text shadow happens with the last value being painted at the back, + // ie. it is painted first. + gfxContext* aDestCtx = aContext->ThebesContext(); + for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) { + nsCSSShadowItem* shadowDetails = textStyle->mTextShadow->ShadowAt(i - 1); + nsPoint shadowOffset(shadowDetails->mXOffset, + shadowDetails->mYOffset); + nscoord blurRadius = NS_MAX(shadowDetails->mRadius, 0); + + nsRect shadowRect(aTextRect); + shadowRect.MoveBy(shadowOffset); + + nsPresContext* presCtx = aFrame->PresContext(); + nsContextBoxBlur contextBoxBlur; + gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius, + presCtx->AppUnitsPerDevPixel(), + aDestCtx, aDirtyRect, nsnull); + if (!shadowContext) + continue; + + nscolor shadowColor; + if (shadowDetails->mHasColor) + shadowColor = shadowDetails->mColor; + else + shadowColor = aForegroundColor; + + // Conjure an nsRenderingContext from a gfxContext for drawing the text + nsRefPtr<nsRenderingContext> renderingContext = new nsRenderingContext(); + renderingContext->Init(presCtx->DeviceContext(), shadowContext); + + aDestCtx->Save(); + aDestCtx->NewPath(); + aDestCtx->SetColor(gfxRGBA(shadowColor)); + + // The callback will draw whatever we want to blur as a shadow. + aCallback(renderingContext, shadowOffset, shadowColor, aCallbackData); + + contextBoxBlur.DoPaint(); + aDestCtx->Restore(); + } +} + /* static */ nscoord nsLayoutUtils::GetCenteredFontBaseline(nsFontMetrics* aFontMetrics, nscoord aLineHeight) { nscoord fontAscent = aFontMetrics->MaxAscent(); nscoord fontHeight = aFontMetrics->MaxHeight(); nscoord leading = aLineHeight - fontHeight;
--- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -942,16 +942,33 @@ public: PRUint8 aDirection = NS_STYLE_DIRECTION_INHERIT); static nscoord GetStringWidth(const nsIFrame* aFrame, nsRenderingContext* aContext, const PRUnichar* aString, PRInt32 aLength); /** + * Helper function for drawing text-shadow. The callback's job + * is to draw whatever needs to be blurred onto the given context. + */ + typedef void (* TextShadowCallback)(nsRenderingContext* aCtx, + nsPoint aShadowOffset, + const nscolor& aShadowColor, + void* aData); + + static void PaintTextShadow(const nsIFrame* aFrame, + nsRenderingContext* aContext, + const nsRect& aTextRect, + const nsRect& aDirtyRect, + const nscolor& aForegroundColor, + TextShadowCallback aCallback, + void* aCallbackData); + + /** * Gets the baseline to vertically center text from a font within a * line of specified height. * * Returns the baseline position relative to the top of the line. */ static nscoord GetCenteredFontBaseline(nsFontMetrics* aFontMetrics, nscoord aLineHeight);
--- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -16,16 +16,17 @@ * The Original Code is an implementation of CSS3 text-overflow. * * The Initial Developer of the Original Code is the Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Mats Palmgren <matspal@gmail.com> (original author) + * Michael Ventnor <m.ventnor@gmail.com> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your @@ -199,38 +200,68 @@ public: MOZ_COUNT_CTOR(nsDisplayTextOverflowMarker); } #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayTextOverflowMarker() { MOZ_COUNT_DTOR(nsDisplayTextOverflowMarker); } #endif virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - return mRect; + nsRect shadowRect = + nsLayoutUtils::GetTextShadowRectsUnion(mRect, mFrame); + return mRect.Union(shadowRect); } virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx); + void PaintTextToContext(nsRenderingContext* aCtx, + nsPoint aOffsetFromRect); NS_DISPLAY_DECL_NAME("TextOverflow", TYPE_TEXT_OVERFLOW) private: nsRect mRect; // in reference frame coordinates const nsString mString; // the marker text nscoord mAscent; // baseline for the marker text in mRect }; +static void +PaintTextShadowCallback(nsRenderingContext* aCtx, + nsPoint aShadowOffset, + const nscolor& aShadowColor, + void* aData) +{ + reinterpret_cast<nsDisplayTextOverflowMarker*>(aData)-> + PaintTextToContext(aCtx, aShadowOffset); +} + void nsDisplayTextOverflowMarker::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { + nscolor foregroundColor = nsLayoutUtils::GetTextColor(mFrame); + + // Paint the text-shadows for the overflow marker + nsLayoutUtils::PaintTextShadow(mFrame, aCtx, mRect, mVisibleRect, + foregroundColor, PaintTextShadowCallback, + (void*)this); + + aCtx->SetColor(foregroundColor); + PaintTextToContext(aCtx, nsPoint(0, 0)); +} + +void +nsDisplayTextOverflowMarker::PaintTextToContext(nsRenderingContext* aCtx, + nsPoint aOffsetFromRect) +{ nsStyleContext* sc = mFrame->GetStyleContext(); nsLayoutUtils::SetFontFromStyle(aCtx, sc); - aCtx->SetColor(nsLayoutUtils::GetTextColor(mFrame)); + nsPoint baselinePt = mRect.TopLeft(); baselinePt.y += mAscent; - nsLayoutUtils::DrawString(mFrame, aCtx, mString.get(), mString.Length(), - baselinePt); + + nsLayoutUtils::DrawString(mFrame, aCtx, mString.get(), + mString.Length(), baselinePt + aOffsetFromRect); } /* static */ TextOverflow* TextOverflow::WillProcessLines(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists, nsIFrame* aBlockFrame) { if (!CanHaveTextOverflow(aBuilder, aBlockFrame)) {
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/marker-shadow-notref.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/licenses/publicdomain/ +--> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<style type="text/css"> +@font-face { + font-family: DejaVuSansMono; + src: url(../fonts/DejaVuSansMono.woff); +} + +div { + font-family: DejaVuSansMono; + width: 60px; + overflow: hidden; + white-space: nowrap; + font-size: 14px; + text-overflow: "..."; +} +</style> +</head> +<body> +<div> + + a</div> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/layout/reftests/text-overflow/marker-shadow.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/licenses/publicdomain/ + + Test: Marker should have text-shadow applied to it +--> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<style type="text/css"> +@font-face { + font-family: DejaVuSansMono; + src: url(../fonts/DejaVuSansMono.woff); +} + +div { + font-family: DejaVuSansMono; + width: 60px; + overflow: hidden; + white-space: nowrap; + font-size: 14px; + text-overflow: "..."; + text-shadow: 0px 2px 2px red; +} +</style> +</head> +<body> +<div> + + a</div> +</body> +</html>
--- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -8,8 +8,9 @@ HTTP(..) == anonymous-block.html anonymo HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html HTTP(..) == visibility-hidden.html visibility-hidden-ref.html HTTP(..) == block-padding.html block-padding-ref.html HTTP(..) == quirks-decorations.html quirks-decorations-ref.html HTTP(..) == quirks-line-height.html quirks-line-height-ref.html HTTP(..) == standards-decorations.html standards-decorations-ref.html HTTP(..) == standards-line-height.html standards-line-height-ref.html HTTP(..) == selection.html selection-ref.html +HTTP(..) != marker-shadow.html marker-shadow-notref.html
--- a/layout/xul/base/src/nsTextBoxFrame.cpp +++ b/layout/xul/base/src/nsTextBoxFrame.cpp @@ -342,27 +342,56 @@ public: nsRenderingContext* aCtx); virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder); NS_DISPLAY_DECL_NAME("XULTextBox", TYPE_XUL_TEXT_BOX) virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder); virtual void DisableComponentAlpha() { mDisableSubpixelAA = PR_TRUE; } + void PaintTextWithOffset(nsRenderingContext* aCtx, + nsPoint aOffset); + PRPackedBool mDisableSubpixelAA; }; +static void +PaintTextShadowCallback(nsRenderingContext* aCtx, + nsPoint aShadowOffset, + const nscolor& aShadowColor, + void* aData) +{ + reinterpret_cast<nsDisplayXULTextBox*>(aData)-> + PaintTextWithOffset(aCtx, aShadowOffset); +} + void nsDisplayXULTextBox::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { gfxContextAutoDisableSubpixelAntialiasing disable(aCtx->ThebesContext(), mDisableSubpixelAA); + + // Paint the text shadow before doing any foreground stuff + nsRect drawRect = static_cast<nsTextBoxFrame*>(mFrame)->mTextDrawRect; + nsLayoutUtils::PaintTextShadow(mFrame, aCtx, + drawRect, mVisibleRect, + mFrame->GetStyleColor()->mColor, + PaintTextShadowCallback, + (void*)this); + + PaintTextWithOffset(aCtx, nsPoint(0, 0)); +} + +void +nsDisplayXULTextBox::PaintTextWithOffset(nsRenderingContext* aCtx, + nsPoint aOffset) +{ static_cast<nsTextBoxFrame*>(mFrame)-> - PaintTitle(*aCtx, mVisibleRect, ToReferenceFrame()); + PaintTitle(*aCtx, mVisibleRect, ToReferenceFrame() + aOffset); } nsRect nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder) { return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); } nsRect @@ -390,33 +419,17 @@ nsTextBoxFrame::BuildDisplayList(nsDispl void nsTextBoxFrame::PaintTitle(nsRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsPoint aPt) { if (mTitle.IsEmpty()) return; - nsRect textRect = mTextDrawRect + aPt; - - // Paint the text shadow before doing any foreground stuff - const nsStyleText* textStyle = GetStyleText(); - if (textStyle->mTextShadow) { - // Text shadow happens with the last value being painted at the back, - // ie. it is painted first. - for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) { - PaintOneShadow(aRenderingContext.ThebesContext(), - textRect, - textStyle->mTextShadow->ShadowAt(i - 1), - GetStyleColor()->mColor, - aDirtyRect); - } - } - - DrawText(aRenderingContext, textRect, nsnull); + DrawText(aRenderingContext, mTextDrawRect + aPt, nsnull); } void nsTextBoxFrame::DrawText(nsRenderingContext& aRenderingContext, const nsRect& aTextRect, const nscolor* aOverrideColor) { nsPresContext* presContext = PresContext(); @@ -604,59 +617,16 @@ nsTextBoxFrame::DrawText(nsRenderingCont gfxFloat sizePixel = presContext->AppUnitsToGfxUnits(size); nsCSSRendering::PaintDecorationLine(ctx, strikeColor, pt, gfxSize(width, sizePixel), ascentPixel, offsetPixel, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, strikeStyle); } } -void nsTextBoxFrame::PaintOneShadow(gfxContext* aCtx, - const nsRect& aTextRect, - nsCSSShadowItem* aShadowDetails, - const nscolor& aForegroundColor, - const nsRect& aDirtyRect) { - nsPoint shadowOffset(aShadowDetails->mXOffset, - aShadowDetails->mYOffset); - nscoord blurRadius = NS_MAX(aShadowDetails->mRadius, 0); - - nsRect shadowRect(aTextRect); - shadowRect.MoveBy(shadowOffset); - - nsContextBoxBlur contextBoxBlur; - gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius, - PresContext()->AppUnitsPerDevPixel(), - aCtx, aDirtyRect, nsnull); - - if (!shadowContext) - return; - - nscolor shadowColor; - if (aShadowDetails->mHasColor) - shadowColor = aShadowDetails->mColor; - else - shadowColor = aForegroundColor; - - // Conjure an nsRenderingContext from a gfxContext for DrawText - nsRefPtr<nsRenderingContext> renderingContext = new nsRenderingContext(); - renderingContext->Init(PresContext()->DeviceContext(), shadowContext); - - aCtx->Save(); - aCtx->NewPath(); - aCtx->SetColor(gfxRGBA(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. - DrawText(*renderingContext, shadowRect, &shadowColor); - contextBoxBlur.DoPaint(); - aCtx->Restore(); -} - void nsTextBoxFrame::CalculateUnderline(nsRenderingContext& aRenderingContext) { if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) { // Calculate all fields of mAccessKeyInfo which // are the same for both BiDi and non-BiDi frames. const PRUnichar *titleString = mCroppedTitle.get(); aRenderingContext.SetTextRunRTL(PR_FALSE);
--- a/layout/xul/base/src/nsTextBoxFrame.h +++ b/layout/xul/base/src/nsTextBoxFrame.h @@ -89,16 +89,17 @@ public: nsPoint aPt); nsRect GetComponentAlphaBounds(); virtual PRBool ComputesOwnOverflowArea(); protected: friend class nsAsyncAccesskeyUpdate; + friend class nsDisplayXULTextBox; // Should be called only by nsAsyncAccesskeyUpdate. // Returns PR_TRUE if accesskey was updated. PRBool UpdateAccesskey(nsWeakFrame& aWeakThis); void UpdateAccessTitle(); void UpdateAccessIndex(); // REVIEW: SORRY! Couldn't resist devirtualizing these void LayoutTitle(nsPresContext* aPresContext, @@ -129,22 +130,16 @@ private: PRBool AlwaysAppendAccessKey(); PRBool InsertSeparatorBeforeAccessKey(); void DrawText(nsRenderingContext& aRenderingContext, const nsRect& aTextRect, const nscolor* aOverrideColor); - void PaintOneShadow(gfxContext * aCtx, - const nsRect& aTextRect, - nsCSSShadowItem* aShadowDetails, - const nscolor& aForegroundColor, - const nsRect& aDirtyRect); - nsString mTitle; nsString mCroppedTitle; nsString mAccessKey; nsSize mTextSize; nsRect mTextDrawRect; nsAccessKeyInfo* mAccessKeyInfo; CroppingStyle mCropType;