Bug 392785 overflowed underline sometimes is not repainted at scrolling r+sr=roc, b1.9=dbaron

This commit is contained in:
masayuki@d-toybox.com 2007-12-02 22:51:57 -08:00
Родитель 365fb40b8c
Коммит 7fc09046f2
13 изменённых файлов: 363 добавлений и 125 удалений

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

@ -168,10 +168,10 @@ const PRUint8 kUseAltDCFor_CREATERC_PAINT = 0x04; // Use when creating Renderin
const PRUint8 kUseAltDCFor_SURFACE_DIM = 0x08; // Use it for getting the Surface Dimensions
#endif
// 4dd372b6-ef19-4995-a7ac-ba3efd3f656f
// 92a1e76c-adbd-441e-aae6-243d6004e0ee
#define NS_IDEVICE_CONTEXT_IID \
{ 0x4dd372b6, 0xef19, 0x4995, \
{ 0xa7, 0xac, 0xba, 0x3e, 0xfd, 0x3f, 0x65, 0x6f } }
{ 0x92a1e76c, 0xadbd, 0x441e, \
{ 0xaa, 0xe6, 0x24, 0x3d, 0x60, 0x4, 0xe0, 0xee } }
//a cross platform way of specifying a native palette handle
typedef void * nsPalette;
@ -295,7 +295,14 @@ public:
PRInt32 AppUnitsPerDevPixel() const { return mAppUnitsPerDevPixel; }
/**
* Convert app units to device pixels which is used in gfx/thebes.
* Convert device pixels which is used for gfx/thebes to nearest (rounded)
* app units
*/
nscoord GfxUnitsToAppUnits(gfxFloat aGfxUnits) const
{ return nscoord(NS_round(aGfxUnits * AppUnitsPerDevPixel())); }
/**
* Convert app units to device pixels which is used for gfx/thebes.
*/
gfxFloat AppUnitsToGfxUnits(nscoord aAppUnits) const
{ return gfxFloat(aAppUnits) / AppUnitsPerDevPixel(); }

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

@ -4352,24 +4352,26 @@ nsCSSRendering::PaintDecorationLine(gfxContext* aGfxContext,
const gfxSize& aLineSize,
const gfxFloat aAscent,
const gfxFloat aOffset,
const gfxFloat aPreferredHeight,
const PRUint8 aDecoration,
const PRUint8 aStyle,
const PRBool aIsRTL)
{
if (aLineSize.width <= 0 || aLineSize.height <= 0 ||
aStyle == NS_STYLE_BORDER_STYLE_NONE)
gfxRect rect =
GetTextDecorationRectInternal(aPt, aLineSize, aAscent, aOffset,
aDecoration, aStyle);
if (rect.IsEmpty())
return;
gfxFloat lineHeight = PR_MAX(NS_round(aLineSize.height), 1.0);
PRBool contextIsSaved = PR_FALSE;
gfxFloat totalHeight = aLineSize.height;
switch (aStyle) {
case NS_STYLE_BORDER_STYLE_SOLID:
case NS_STYLE_BORDER_STYLE_DOUBLE:
break;
case NS_STYLE_BORDER_STYLE_DASHED: {
aGfxContext->Save();
contextIsSaved = PR_TRUE;
gfxFloat dashWidth = aLineSize.height * DOT_LENGTH * DASH_LENGTH;
gfxFloat dashWidth = lineHeight * DOT_LENGTH * DASH_LENGTH;
gfxFloat dash[2] = { dashWidth, dashWidth };
aGfxContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
aGfxContext->SetDash(dash, 2, 0.0);
@ -4378,9 +4380,9 @@ nsCSSRendering::PaintDecorationLine(gfxContext* aGfxContext,
case NS_STYLE_BORDER_STYLE_DOTTED: {
aGfxContext->Save();
contextIsSaved = PR_TRUE;
gfxFloat dashWidth = aLineSize.height * DOT_LENGTH;
gfxFloat dashWidth = lineHeight * DOT_LENGTH;
gfxFloat dash[2];
if (aLineSize.height > 2.0) {
if (lineHeight > 2.0) {
dash[0] = 0.0;
dash[1] = dashWidth * 2.0;
aGfxContext->SetLineCap(gfxContext::LINE_CAP_ROUND);
@ -4391,74 +4393,41 @@ nsCSSRendering::PaintDecorationLine(gfxContext* aGfxContext,
aGfxContext->SetDash(dash, 2, 0.0);
break;
}
case NS_STYLE_BORDER_STYLE_DOUBLE:
totalHeight *= 3.0;
break;
default:
NS_ERROR("Invalid style value!");
return;
}
gfxFloat offset = aOffset;
switch (aDecoration) {
case NS_STYLE_TEXT_DECORATION_UNDERLINE:
break;
case NS_STYLE_TEXT_DECORATION_OVERLINE:
// The offset includes the preferred size, we should remove it
offset += aPreferredHeight;
// the bottom of the decoration line should be aligned to the top of the
// text.
offset -= totalHeight;
break;
case NS_STYLE_TEXT_DECORATION_LINE_THROUGH: {
// The offset includes the preferred size, we should remove it
offset += aPreferredHeight;
// the middle of the decoration line should be aligned to the middle of
// the original strike out offset.
offset -= PR_MAX(aPreferredHeight, (totalHeight / 2.0));
break;
}
default:
NS_ERROR("Invalid decoration value!");
if (contextIsSaved)
aGfxContext->Restore();
return;
}
// round to device pixels for suppressing the AA.
gfxFloat x = NS_round(aPt.x);
gfxFloat y = NS_round(aPt.y + aAscent) - NS_round(offset);
gfxFloat width = NS_round(aLineSize.width);
gfxFloat height = NS_round(aLineSize.height);
// The y position should be set to the middle of the line.
y += height / 2;
rect.pos.y += lineHeight / 2;
aGfxContext->SetColor(gfxRGBA(aColor));
aGfxContext->SetLineWidth(height);
aGfxContext->SetLineWidth(lineHeight);
switch (aStyle) {
case NS_STYLE_BORDER_STYLE_SOLID:
aGfxContext->NewPath();
aGfxContext->MoveTo(gfxPoint(x, y));
aGfxContext->LineTo(gfxPoint(x + width, y));
aGfxContext->MoveTo(rect.TopLeft());
aGfxContext->LineTo(rect.TopRight());
aGfxContext->Stroke();
break;
case NS_STYLE_BORDER_STYLE_DOUBLE:
aGfxContext->NewPath();
aGfxContext->MoveTo(gfxPoint(x, y));
aGfxContext->LineTo(gfxPoint(x + width, y));
aGfxContext->MoveTo(gfxPoint(x, y + height * 2.0));
aGfxContext->LineTo(gfxPoint(x + width, y + height * 2.0));
aGfxContext->MoveTo(rect.TopLeft());
aGfxContext->LineTo(rect.TopRight());
rect.size.height -= lineHeight;
aGfxContext->MoveTo(rect.BottomLeft());
aGfxContext->LineTo(rect.BottomRight());
aGfxContext->Stroke();
break;
case NS_STYLE_BORDER_STYLE_DOTTED:
case NS_STYLE_BORDER_STYLE_DASHED:
aGfxContext->NewPath();
if (aIsRTL) {
aGfxContext->MoveTo(gfxPoint(x + width, y));
aGfxContext->LineTo(gfxPoint(x, y));
aGfxContext->MoveTo(rect.TopRight());
aGfxContext->LineTo(rect.TopLeft());
} else {
aGfxContext->MoveTo(gfxPoint(x, y));
aGfxContext->LineTo(gfxPoint(x + width, y));
aGfxContext->MoveTo(rect.TopLeft());
aGfxContext->LineTo(rect.TopRight());
}
aGfxContext->Stroke();
aGfxContext->Restore();
@ -4470,3 +4439,70 @@ nsCSSRendering::PaintDecorationLine(gfxContext* aGfxContext,
}
NS_ASSERTION(!contextIsSaved, "The gfxContext has been saved, but not restored!");
}
nsRect
nsCSSRendering::GetTextDecorationRect(nsPresContext* aPresContext,
const gfxSize& aLineSize,
const gfxFloat aAscent,
const gfxFloat aOffset,
const PRUint8 aDecoration,
const PRUint8 aStyle)
{
NS_ASSERTION(aPresContext, "aPresContext is null");
gfxRect rect =
GetTextDecorationRectInternal(gfxPoint(0, 0), aLineSize, aAscent, aOffset,
aDecoration, aStyle);
// The rect values are already rounded to nearest device pixels.
nsRect r;
r.x = aPresContext->GfxUnitsToAppUnits(rect.X());
r.y = aPresContext->GfxUnitsToAppUnits(rect.Y());
r.width = aPresContext->GfxUnitsToAppUnits(rect.Width());
r.height = aPresContext->GfxUnitsToAppUnits(rect.Height());
return r;
}
gfxRect
nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
const gfxSize& aLineSize,
const gfxFloat aAscent,
const gfxFloat aOffset,
const PRUint8 aDecoration,
const PRUint8 aStyle)
{
gfxRect r;
r.pos.x = NS_round(aPt.x);
r.size.width = NS_round(aLineSize.width);
gfxFloat basesize = NS_round(aLineSize.height);
basesize = PR_MAX(basesize, 1.0);
r.size.height = basesize;
if (aStyle == NS_STYLE_BORDER_STYLE_DOUBLE) {
gfxFloat gap = NS_round(basesize / 2.0);
gap = PR_MAX(gap, 1.0);
r.size.height = basesize * 2.0 + gap;
} else {
r.size.height = basesize;
}
gfxFloat baseline = NS_round(aPt.y + aAscent);
gfxFloat offset = 0;
switch (aDecoration) {
case NS_STYLE_TEXT_DECORATION_UNDERLINE:
offset = NS_round(aOffset);
break;
case NS_STYLE_TEXT_DECORATION_OVERLINE:
offset = NS_round(aOffset - basesize + r.Height());
break;
case NS_STYLE_TEXT_DECORATION_LINE_THROUGH: {
gfxFloat extra = NS_round(r.Height() / 2.0);
extra = PR_MAX(extra, basesize);
offset = NS_round(aOffset - basesize + extra);
break;
}
default:
NS_ERROR("Invalid decoration value!");
}
r.pos.y = baseline - NS_round(offset);
return r;
}

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

@ -41,6 +41,7 @@
#define nsCSSRendering_h___
#include "nsIRenderingContext.h"
#include "nsStyleConsts.h"
#include "gfxContext.h"
struct nsPoint;
class nsStyleContext;
@ -201,8 +202,8 @@ public:
/**
* Function for painting the decoration lines for the text.
* NOTE: aPt, aLineSize, aAscent, aOffset and aPreferredHeight are non-rounded
* device pixels, not app units.
* NOTE: aPt, aLineSize, aAscent and aOffset are non-rounded device pixels,
* not app units.
* input:
* @param aGfxContext
* @param aColor the color of the decoration line
@ -213,8 +214,6 @@ public:
* @param aOffset the offset of the decoration line from
* the baseline of the text (if the value is
* positive, the line is lifted up)
* @param aPreferredHeight the preferred size of the decoration line by
* the font of the text
* @param aDecoration which line will be painted. The value can be
* NS_STYLE_TEXT_DECORATION_UNDERLINE or
* NS_STYLE_TEXT_DECORATION_OVERLINE or
@ -223,8 +222,7 @@ public:
* can be NS_STYLE_BORDER_STYLE_SOLID or
* NS_STYLE_BORDER_STYLE_DOTTED or
* NS_STYLE_BORDER_STYLE_DASHED or
* NS_STYLE_BORDER_STYLE_DOUBLE or
* NS_STYLE_BORDER_STYLE_NONE.
* NS_STYLE_BORDER_STYLE_DOUBLE.
* @param aIsRTL when the text is RTL, it is true.
*/
static void PaintDecorationLine(gfxContext* aGfxContext,
@ -233,11 +231,42 @@ public:
const gfxSize& aLineSize,
const gfxFloat aAscent,
const gfxFloat aOffset,
const gfxFloat aPreferredSize,
const PRUint8 aDecoration,
const PRUint8 aStyle,
const PRBool aIsRTL);
/**
* Function for getting the decoration line rect for the text.
* NOTE: aLineSize, aAscent and aOffset are non-rounded device pixels,
* not app units.
* input:
* @param aPresContext
* @param aLineSize the width and the height of the decoration
* line
* @param aAscent the ascent of the text
* @param aOffset the offset of the decoration line from
* the baseline of the text (if the value is
* positive, the line is lifted up)
* @param aDecoration which line will be painted. The value can be
* NS_STYLE_TEXT_DECORATION_UNDERLINE or
* NS_STYLE_TEXT_DECORATION_OVERLINE or
* NS_STYLE_TEXT_DECORATION_LINE_THROUGH.
* @param aStyle the style of the decoration line. The value
* can be NS_STYLE_BORDER_STYLE_SOLID or
* NS_STYLE_BORDER_STYLE_DOTTED or
* NS_STYLE_BORDER_STYLE_DASHED or
* NS_STYLE_BORDER_STYLE_DOUBLE.
* output:
* @return the decoration line rect for the input,
* the each values are app units.
*/
static nsRect GetTextDecorationRect(nsPresContext* aPresContext,
const gfxSize& aLineSize,
const gfxFloat aAscent,
const gfxFloat aOffset,
const PRUint8 aDecoration,
const PRUint8 aStyle);
protected:
static void PaintBackgroundColor(nsPresContext* aPresContext,
@ -271,6 +300,12 @@ protected:
PRInt32 aNumPoints,
nsRect* aGap);
static gfxRect GetTextDecorationRectInternal(const gfxPoint& aPt,
const gfxSize& aLineSize,
const gfxFloat aAscent,
const gfxFloat aOffset,
const PRUint8 aDecoration,
const PRUint8 aStyle);
};

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

@ -509,6 +509,10 @@ public:
{ return NSAppUnitsToIntPixels(aAppUnits,
mDeviceContext->AppUnitsPerDevPixel()); }
// If there is a remainder, it is rounded to nearest app units.
nscoord GfxUnitsToAppUnits(gfxFloat aGfxUnits) const
{ return mDeviceContext->GfxUnitsToAppUnits(aGfxUnits); }
gfxFloat AppUnitsToGfxUnits(nscoord aAppUnits) const
{ return mDeviceContext->AppUnitsToGfxUnits(aAppUnits); }

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

@ -4001,6 +4001,16 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
nsRect combinedArea;
aLineLayout.RelativePositionFrames(combinedArea); // XXXldb This returned width as -15, 2001-06-12, Bugzilla
if (aState.mPresContext->CompatibilityMode() != eCompatibility_NavQuirks) {
PRUint8 decorations;
nscolor underColor, overColor, strikeColor;
GetTextDecorations(aState.mPresContext, PR_TRUE, decorations,
underColor, overColor, strikeColor);
if (decorations) {
nsLineLayout::CombineTextDecorations(aState.mPresContext, decorations,
this, combinedArea);
}
}
aLine->SetCombinedArea(combinedArea);
if (addedBullet) {
aLineLayout.RemoveBulletFrame(mBullet);
@ -5875,7 +5885,6 @@ nsBlockFrame::PaintTextDecorationLine(nsIRenderingContext& aRenderingContext,
ctx, aColor, pt, size,
PresContext()->AppUnitsToGfxUnits(aLine->GetAscent()),
PresContext()->AppUnitsToGfxUnits(aOffset),
PresContext()->AppUnitsToGfxUnits(aSize),
aDecoration, NS_STYLE_BORDER_STYLE_SOLID, isRTL);
}
}

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

@ -85,6 +85,7 @@ public:
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
const nsRect& aDirtyRect);
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
NS_DISPLAY_DECL_NAME("TextDecoration")
private:
nsLineBox* mLine;
@ -122,6 +123,12 @@ nsDisplayTextDecoration::Paint(nsDisplayListBuilder* aBuilder,
}
}
nsRect
nsDisplayTextDecoration::GetBounds(nsDisplayListBuilder* aBuilder)
{
return mFrame->GetOverflowRect() + aBuilder->ToReferenceFrame(mFrame);
}
nsresult
nsHTMLContainerFrame::DisplayTextDecorations(nsDisplayListBuilder* aBuilder,
nsDisplayList* aBelowTextDecorations,
@ -188,7 +195,7 @@ nsHTMLContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
static PRBool
HasTextFrameDescendantOrInFlow(nsPresContext* aPresContext, nsIFrame* aFrame);
HasTextFrameDescendantOrInFlow(nsIFrame* aFrame);
/*virtual*/ void
nsHTMLContainerFrame::PaintTextDecorationLine(
@ -221,7 +228,6 @@ nsHTMLContainerFrame::PaintTextDecorationLine(
nsCSSRendering::PaintDecorationLine(
ctx, aColor, pt, size, PresContext()->AppUnitsToGfxUnits(aAscent),
PresContext()->AppUnitsToGfxUnits(aOffset),
PresContext()->AppUnitsToGfxUnits(aSize),
aDecoration, NS_STYLE_BORDER_STYLE_SOLID, isRTL);
}
@ -297,14 +303,14 @@ nsHTMLContainerFrame::GetTextDecorations(nsPresContext* aPresContext,
if (aDecorations) {
// If this frame contains no text, we're required to ignore this property
if (!HasTextFrameDescendantOrInFlow(aPresContext, this)) {
if (!HasTextFrameDescendantOrInFlow(this)) {
aDecorations = NS_STYLE_TEXT_DECORATION_NONE;
}
}
}
static PRBool
HasTextFrameDescendant(nsPresContext* aPresContext, nsIFrame* aParent)
HasTextFrameDescendant(nsIFrame* aParent)
{
for (nsIFrame* kid = aParent->GetFirstChild(nsnull); kid;
kid = kid->GetNextSibling())
@ -317,7 +323,7 @@ HasTextFrameDescendant(nsPresContext* aPresContext, nsIFrame* aParent)
return PR_TRUE;
}
}
if (HasTextFrameDescendant(aPresContext, kid)) {
if (HasTextFrameDescendant(kid)) {
return PR_TRUE;
}
}
@ -325,10 +331,10 @@ HasTextFrameDescendant(nsPresContext* aPresContext, nsIFrame* aParent)
}
static PRBool
HasTextFrameDescendantOrInFlow(nsPresContext* aPresContext, nsIFrame* aFrame)
HasTextFrameDescendantOrInFlow(nsIFrame* aFrame)
{
for (nsIFrame *f = aFrame->GetFirstInFlow(); f; f = f->GetNextInFlow()) {
if (HasTextFrameDescendant(aPresContext, f))
if (HasTextFrameDescendant(f))
return PR_TRUE;
}
return PR_FALSE;

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

@ -568,8 +568,7 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
// affect our height.
fm->GetMaxAscent(aMetrics.ascent);
fm->GetHeight(aMetrics.height);
// Include the text-decoration lines to the height.
// Currently, only underline is overflowable.
// Include the text-decoration lines to the height for readable.
nscoord offset, size;
fm->GetUnderline(offset, size);
nscoord ascentAndUnderline =
@ -586,7 +585,7 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
aReflowState.mComputedBorderPadding.bottom;
// For now our overflow area is zero. The real value will be
// computed during vertical alignment of the line we are on.
// computed in |nsLineLayout::RelativePositionFrames|.
aMetrics.mOverflowArea.SetRect(0, 0, 0, 0);
#ifdef NOISY_FINAL_SIZE

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

@ -66,6 +66,7 @@
#include "nsBidiUtils.h"
#include "nsLayoutUtils.h"
#include "nsTextFrame.h"
#include "nsCSSRendering.h"
#ifdef DEBUG
#undef NOISY_HORIZONTAL_ALIGN
@ -2624,6 +2625,8 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
combinedAreaResult.height = mFinalLineHeight;
}
PRBool isStandardsMode =
mPresContext->CompatibilityMode() != eCompatibility_NavQuirks;
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
nsPoint origin = nsPoint(pfd->mBounds.x, pfd->mBounds.y);
nsIFrame* frame = pfd->mFrame;
@ -2652,6 +2655,15 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
// <b>x</b> and <b>y</b> which were computed above.
nsRect r;
if (pfd->mSpan) {
if (isStandardsMode) {
// Combine the text decoration area for inline elements of standards
// mode
PRUint8 decorations = frame->GetStyleTextReset()->mTextDecoration;
if (decorations) {
nsLineLayout::CombineTextDecorations(mPresContext, decorations,
frame, pfd->mSpan->mFrame->mCombinedArea);
}
}
// Compute a new combined area for the child span before
// aggregating it into our combined area.
RelativePositionFrames(pfd->mSpan, r);
@ -2695,3 +2707,60 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
}
aCombinedArea = combinedAreaResult;
}
void
nsLineLayout::CombineTextDecorations(nsPresContext* aPresContext,
PRUint8 aDecorations,
nsIFrame* aFrame,
nsRect& aCombinedArea,
nscoord aAscentOverride,
float aUnderlineSizeRatio)
{
if (!(aDecorations & (NS_STYLE_TEXT_DECORATION_UNDERLINE |
NS_STYLE_TEXT_DECORATION_OVERLINE |
NS_STYLE_TEXT_DECORATION_LINE_THROUGH)))
return;
nsCOMPtr<nsIFontMetrics> fm;
nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
if (aAscentOverride == 0)
fm->GetMaxAscent(aAscentOverride);
gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(aAscentOverride);
nsRect decorationArea;
if (aDecorations & (NS_STYLE_TEXT_DECORATION_UNDERLINE |
NS_STYLE_TEXT_DECORATION_OVERLINE)) {
nscoord offsetCoord, sizeCoord;
fm->GetUnderline(offsetCoord, sizeCoord);
gfxSize size(aPresContext->AppUnitsToGfxUnits(aCombinedArea.width),
aPresContext->AppUnitsToGfxUnits(sizeCoord));
if (aDecorations & NS_STYLE_TEXT_DECORATION_OVERLINE) {
decorationArea =
nsCSSRendering::GetTextDecorationRect(aPresContext, size, ascent,
ascent, NS_STYLE_TEXT_DECORATION_OVERLINE,
NS_STYLE_BORDER_STYLE_SOLID);
aCombinedArea.UnionRect(aCombinedArea, decorationArea);
}
if (aDecorations & NS_STYLE_TEXT_DECORATION_UNDERLINE) {
aUnderlineSizeRatio = PR_MAX(aUnderlineSizeRatio, 1.0);
size.height *= aUnderlineSizeRatio;
gfxFloat offset = aPresContext->AppUnitsToGfxUnits(offsetCoord);
decorationArea =
nsCSSRendering::GetTextDecorationRect(aPresContext, size, ascent,
offset, NS_STYLE_TEXT_DECORATION_UNDERLINE,
NS_STYLE_BORDER_STYLE_SOLID);
aCombinedArea.UnionRect(aCombinedArea, decorationArea);
}
}
if (aDecorations & NS_STYLE_TEXT_DECORATION_LINE_THROUGH) {
nscoord offsetCoord, sizeCoord;
fm->GetStrikeout(offsetCoord, sizeCoord);
gfxSize size(aPresContext->AppUnitsToGfxUnits(aCombinedArea.width),
aPresContext->AppUnitsToGfxUnits(sizeCoord));
gfxFloat offset = aPresContext->AppUnitsToGfxUnits(offsetCoord);
decorationArea =
nsCSSRendering::GetTextDecorationRect(aPresContext, size, ascent,
offset, NS_STYLE_TEXT_DECORATION_LINE_THROUGH,
NS_STYLE_BORDER_STYLE_SOLID);
aCombinedArea.UnionRect(aCombinedArea, decorationArea);
}
}

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

@ -132,6 +132,12 @@ public:
*/
void RelativePositionFrames(nsRect& aCombinedArea);
static void CombineTextDecorations(nsPresContext* aPresContext,
PRUint8 aDecorations,
nsIFrame* aFrame,
nsRect& aCombinedArea,
nscoord aAscentOverride = 0,
float aUnderlineSizeRatio = 1.0f);
//----------------------------------------
// Supporting methods and data for flags

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

@ -359,6 +359,38 @@ protected:
PRBool isRTLChars,
PRBool isOddLevel,
PRBool isBidiSystem);
void UnionTextDecorationOverflow(nsPresContext* aPresContext,
const gfxTextRun::Metrics& aTextMetrics,
nsRect* aOverflowRect);
struct TextDecorations {
PRUint8 mDecorations;
nscolor mOverColor;
nscolor mUnderColor;
nscolor mStrikeColor;
TextDecorations() :
mDecorations(0), mOverColor(NS_RGB(0, 0, 0)),
mUnderColor(NS_RGB(0, 0, 0)), mStrikeColor(NS_RGB(0, 0, 0))
{ }
PRBool HasDecorationlines() {
return !!(mDecorations & (NS_STYLE_TEXT_DECORATION_UNDERLINE |
NS_STYLE_TEXT_DECORATION_OVERLINE |
NS_STYLE_TEXT_DECORATION_LINE_THROUGH));
}
PRBool HasUnderline() {
return !!(mDecorations & NS_STYLE_TEXT_DECORATION_UNDERLINE);
}
PRBool HasOverline() {
return !!(mDecorations & NS_STYLE_TEXT_DECORATION_OVERLINE);
}
PRBool HasStrikeout() {
return !!(mDecorations & NS_STYLE_TEXT_DECORATION_LINE_THROUGH);
}
};
TextDecorations GetTextDecorations(nsPresContext* aPresContext);
};
#endif

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

@ -3546,39 +3546,35 @@ FillClippedRect(gfxContext* aCtx, nsPresContext* aPresContext,
aCtx->Fill();
}
void
nsTextFrame::PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
nsTextPaintStyle& aTextPaintStyle,
PropertyProvider& aProvider)
nsTextFrame::TextDecorations
nsTextFrame::GetTextDecorations(nsPresContext* aPresContext)
{
TextDecorations decorations;
// Quirks mode text decoration are rendered by children; see bug 1777
// In non-quirks mode, nsHTMLContainer::Paint and nsBlockFrame::Paint
// does the painting of text decorations.
if (eCompatibility_NavQuirks != aTextPaintStyle.PresContext()->CompatibilityMode())
return;
if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode())
return decorations;
PRBool useOverride = PR_FALSE;
nscolor overrideColor;
PRUint8 decorations = NS_STYLE_TEXT_DECORATION_NONE;
// A mask of all possible decorations.
PRUint8 decorMask = NS_STYLE_TEXT_DECORATION_UNDERLINE |
NS_STYLE_TEXT_DECORATION_OVERLINE |
NS_STYLE_TEXT_DECORATION_LINE_THROUGH;
nscolor overColor, underColor, strikeColor;
nsStyleContext* context = GetStyleContext();
PRBool hasDecorations = context->HasTextDecorations();
NS_STYLE_TEXT_DECORATION_LINE_THROUGH;
while (hasDecorations) {
for (nsStyleContext* context = GetStyleContext();
decorMask && context && context->HasTextDecorations();
context = context->GetParent()) {
const nsStyleTextReset* styleText = context->GetStyleTextReset();
if (!useOverride &&
(NS_STYLE_TEXT_DECORATION_OVERRIDE_ALL & styleText->mTextDecoration)) {
// This handles the <a href="blah.html"><font color="green">La
// la la</font></a> case. The link underline should be green.
useOverride = PR_TRUE;
overrideColor = context->GetStyleColor()->mColor;
overrideColor = context->GetStyleColor()->mColor;
}
PRUint8 useDecorations = decorMask & styleText->mTextDecoration;
@ -3586,30 +3582,59 @@ nsTextFrame::PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
nscolor color = context->GetStyleColor()->mColor;
if (NS_STYLE_TEXT_DECORATION_UNDERLINE & useDecorations) {
underColor = useOverride ? overrideColor : color;
decorations.mUnderColor = useOverride ? overrideColor : color;
decorMask &= ~NS_STYLE_TEXT_DECORATION_UNDERLINE;
decorations |= NS_STYLE_TEXT_DECORATION_UNDERLINE;
decorations.mDecorations |= NS_STYLE_TEXT_DECORATION_UNDERLINE;
}
if (NS_STYLE_TEXT_DECORATION_OVERLINE & useDecorations) {
overColor = useOverride ? overrideColor : color;
decorations.mOverColor = useOverride ? overrideColor : color;
decorMask &= ~NS_STYLE_TEXT_DECORATION_OVERLINE;
decorations |= NS_STYLE_TEXT_DECORATION_OVERLINE;
decorations.mDecorations |= NS_STYLE_TEXT_DECORATION_OVERLINE;
}
if (NS_STYLE_TEXT_DECORATION_LINE_THROUGH & useDecorations) {
strikeColor = useOverride ? overrideColor : color;
decorations.mStrikeColor = useOverride ? overrideColor : color;
decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_THROUGH;
decorations |= NS_STYLE_TEXT_DECORATION_LINE_THROUGH;
decorations.mDecorations |= NS_STYLE_TEXT_DECORATION_LINE_THROUGH;
}
}
if (0 == decorMask)
break;
context = context->GetParent();
if (!context)
break;
hasDecorations = context->HasTextDecorations();
}
if (!decorations)
return decorations;
}
void
nsTextFrame::UnionTextDecorationOverflow(
nsPresContext* aPresContext,
const gfxTextRun::Metrics& aTextMetrics,
nsRect* aOverflowRect)
{
NS_ASSERTION(mTextRun, "mTextRun is null");
nsRect rect;
TextDecorations decorations = GetTextDecorations(aPresContext);
float ratio = 1.0f;
// Note that we need to add underline area when this frame has selection for
// spellchecking and IME.
if (mState & NS_FRAME_SELECTED_CONTENT) {
nsILookAndFeel* look = aPresContext->LookAndFeel();
look->GetMetric(nsILookAndFeel::eMetricFloat_IMEUnderlineRelativeSize,
ratio);
decorations.mDecorations |= NS_STYLE_TEXT_DECORATION_UNDERLINE;
}
nsLineLayout::CombineTextDecorations(aPresContext, decorations.mDecorations,
this, *aOverflowRect, nscoord(NS_round(aTextMetrics.mAscent)),
ratio);
}
void
nsTextFrame::PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
nsTextPaintStyle& aTextPaintStyle,
PropertyProvider& aProvider)
{
TextDecorations decorations =
GetTextDecorations(aTextPaintStyle.PresContext());
if (!decorations.HasDecorationlines())
return;
gfxFont::Metrics fontMetrics = GetFontMetrics(aProvider.GetFontGroup());
@ -3620,26 +3645,26 @@ nsTextFrame::PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
gfxSize size(GetRect().width / app, 0);
gfxFloat ascent = gfxFloat(mAscent) / app;
if (decorations & NS_FONT_DECORATION_OVERLINE) {
if (decorations.HasOverline()) {
size.height = fontMetrics.underlineSize;
nsCSSRendering::PaintDecorationLine(
aCtx, overColor, pt, size, ascent, ascent, size.height,
aCtx, decorations.mOverColor, pt, size, ascent, ascent,
NS_STYLE_TEXT_DECORATION_OVERLINE, NS_STYLE_BORDER_STYLE_SOLID,
mTextRun->IsRightToLeft());
}
if (decorations & NS_FONT_DECORATION_UNDERLINE) {
if (decorations.HasUnderline()) {
size.height = fontMetrics.underlineSize;
gfxFloat offset = fontMetrics.underlineOffset;
nsCSSRendering::PaintDecorationLine(
aCtx, underColor, pt, size, ascent, offset, size.height,
aCtx, decorations.mUnderColor, pt, size, ascent, offset,
NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_SOLID,
mTextRun->IsRightToLeft());
}
if (decorations & NS_FONT_DECORATION_LINE_THROUGH) {
if (decorations.HasStrikeout()) {
size.height = fontMetrics.strikeoutSize;
gfxFloat offset = fontMetrics.strikeoutOffset;
nsCSSRendering::PaintDecorationLine(
aCtx, strikeColor, pt, size, ascent, offset, size.height,
aCtx, decorations.mStrikeColor, pt, size, ascent, offset,
NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_SOLID,
mTextRun->IsRightToLeft());
}
@ -3667,7 +3692,7 @@ static void DrawIMEUnderline(gfxContext* aContext, PRInt32 aIndex,
gfxFloat width = PR_MAX(0, aWidth - 2.0 * aSize);
gfxPoint pt(aPt.x + 1.0, aPt.y);
nsCSSRendering::PaintDecorationLine(
aContext, color, pt, gfxSize(width, actualSize), aAscent, aOffset, aSize,
aContext, color, pt, gfxSize(width, actualSize), aAscent, aOffset,
NS_STYLE_TEXT_DECORATION_UNDERLINE, style, aIsRTL);
}
@ -3685,7 +3710,7 @@ static void DrawSelectionDecorations(gfxContext* aContext, SelectionType aType,
case nsISelectionController::SELECTION_SPELLCHECK: {
nsCSSRendering::PaintDecorationLine(
aContext, NS_RGB(255,0,0),
aPt, size, aAscent, aFontMetrics.underlineOffset, size.height,
aPt, size, aAscent, aFontMetrics.underlineOffset,
NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_DOTTED,
aIsRTL);
break;
@ -4313,6 +4338,7 @@ nsTextFrame::SetSelected(nsPresContext* aPresContext,
found = PR_TRUE;
}
nsFrameState oldState = mState;
if ( aSelected )
AddStateBits(NS_FRAME_SELECTED_CONTENT);
else
@ -4325,6 +4351,20 @@ nsTextFrame::SetSelected(nsPresContext* aPresContext,
}
}
if (found) {
// If the selection state is changed, we need to reflow to recompute
// the overflow area for underline of spellchecking or IME. However, if
// the non-selected text already has underline, we don't need to reflow.
// And also when the IME underline is thicker than normal underline.
nsILookAndFeel* look = aPresContext->LookAndFeel();
float ratio;
look->GetMetric(nsILookAndFeel::eMetricFloat_IMEUnderlineRelativeSize,
ratio);
if (oldState != mState &&
(ratio > 1.0 || !GetTextDecorations(aPresContext).HasUnderline())) {
PresContext()->PresShell()->FrameNeedsReflow(this,
nsIPresShell::eStyleChange,
NS_FRAME_IS_DIRTY);
}
// Selection might change anything. Invalidate the overflow area.
Invalidate(GetOverflowRect(), PR_FALSE);
}
@ -5447,6 +5487,9 @@ nsTextFrame::Reflow(nsPresContext* aPresContext,
aMetrics.mOverflowArea.UnionRect(boundingBox,
nsRect(0, 0, aMetrics.width, aMetrics.height));
UnionTextDecorationOverflow(aPresContext, textMetrics,
&aMetrics.mOverflowArea);
/////////////////////////////////////////////////////////////////////
// Clean up, update state
/////////////////////////////////////////////////////////////////////
@ -5649,6 +5692,9 @@ nsTextFrame::RecomputeOverflowRect()
ConvertGfxRectOutward(textMetrics.mBoundingBox + gfxPoint(0, textMetrics.mAscent));
boundingBox.UnionRect(boundingBox,
nsRect(nsPoint(0,0), GetSize()));
UnionTextDecorationOverflow(PresContext(), textMetrics, &boundingBox);
return boundingBox;
}

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

@ -1512,18 +1512,10 @@ nsStyleTextReset::~nsStyleTextReset(void) { }
nsChangeHint nsStyleTextReset::CalcDifference(const nsStyleTextReset& aOther) const
{
if (mVerticalAlign == aOther.mVerticalAlign
&& mUnicodeBidi == aOther.mUnicodeBidi) {
if (mTextDecoration != aOther.mTextDecoration) {
// Reflow for blink changes, repaint for others
return
(mTextDecoration & NS_STYLE_TEXT_DECORATION_BLINK) ==
(aOther.mTextDecoration & NS_STYLE_TEXT_DECORATION_BLINK) ?
NS_STYLE_HINT_VISUAL : NS_STYLE_HINT_REFLOW;
}
if (mVerticalAlign == aOther.mVerticalAlign &&
mUnicodeBidi == aOther.mUnicodeBidi &&
mTextDecoration == aOther.mTextDecoration)
return NS_STYLE_HINT_NONE;
}
return NS_STYLE_HINT_REFLOW;
}

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

@ -465,7 +465,6 @@ nsTextBoxFrame::PaintTitle(nsIRenderingContext& aRenderingContext,
nsCSSRendering::PaintDecorationLine(ctx, overColor,
pt, gfxSize(width, sizePixel),
ascentPixel, ascentPixel,
sizePixel,
NS_STYLE_TEXT_DECORATION_OVERLINE,
NS_STYLE_BORDER_STYLE_SOLID,
isRTL);
@ -474,7 +473,6 @@ nsTextBoxFrame::PaintTitle(nsIRenderingContext& aRenderingContext,
nsCSSRendering::PaintDecorationLine(ctx, underColor,
pt, gfxSize(width, sizePixel),
ascentPixel, offsetPixel,
sizePixel,
NS_STYLE_TEXT_DECORATION_UNDERLINE,
NS_STYLE_BORDER_STYLE_SOLID,
isRTL);
@ -487,7 +485,6 @@ nsTextBoxFrame::PaintTitle(nsIRenderingContext& aRenderingContext,
nsCSSRendering::PaintDecorationLine(ctx, underColor,
pt, gfxSize(width, sizePixel),
ascentPixel, offsetPixel,
sizePixel,
NS_STYLE_TEXT_DECORATION_LINE_THROUGH,
NS_STYLE_BORDER_STYLE_SOLID,
isRTL);