Implement text-shadow for the text-overflow marker text (ellipsis) r=roc

This commit is contained in:
Michael Ventnor 2011-07-01 16:43:11 +10:00
Родитель 53962f854b
Коммит 62ab64069b
8 изменённых файлов: 203 добавлений и 71 удалений

Просмотреть файл

@ -2889,6 +2889,61 @@ nsLayoutUtils::GetStringWidth(const nsIFrame* aFrame,
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)

Просмотреть файл

@ -946,6 +946,23 @@ public:
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.

Просмотреть файл

@ -21,6 +21,7 @@
*
* 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
@ -204,10 +205,14 @@ public:
}
#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
@ -215,17 +220,43 @@ private:
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*

Просмотреть файл

@ -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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;a</div>
</body>
</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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;a</div>
</body>
</html>

Просмотреть файл

@ -13,3 +13,4 @@ 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

Просмотреть файл

@ -347,17 +347,46 @@ public:
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
@ -395,23 +424,7 @@ nsTextBoxFrame::PaintTitle(nsRenderingContext& aRenderingContext,
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
@ -609,49 +622,6 @@ nsTextBoxFrame::DrawText(nsRenderingContext& aRenderingContext,
}
}
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)
{

Просмотреть файл

@ -94,6 +94,7 @@ public:
protected:
friend class nsAsyncAccesskeyUpdate;
friend class nsDisplayXULTextBox;
// Should be called only by nsAsyncAccesskeyUpdate.
// Returns PR_TRUE if accesskey was updated.
PRBool UpdateAccesskey(nsWeakFrame& aWeakThis);
@ -134,12 +135,6 @@ private:
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;