--- a/content/events/src/nsContentEventHandler.cpp
+++ b/content/events/src/nsContentEventHandler.cpp
@@ -83,17 +83,22 @@ nsContentEventHandler::Init(nsQueryConte
if (mSelection)
return NS_OK;
aEvent->mSucceeded = PR_FALSE;
if (!mPresShell)
return NS_ERROR_NOT_AVAILABLE;
- nsresult rv = mPresShell->GetSelectionForCopy(getter_AddRefs(mSelection));
+ // If text frame which has overflowing selection underline is dirty,
+ // we need to flush the pending reflow here.
+ nsresult rv = mPresShell->FlushPendingNotifications(Flush_Layout);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mPresShell->GetSelectionForCopy(getter_AddRefs(mSelection));
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(mSelection,
"GetSelectionForCopy succeeded, but the result is null");
PRBool isCollapsed;
rv = mSelection->GetIsCollapsed(&isCollapsed);
if (NS_FAILED(rv))
return NS_ERROR_NOT_AVAILABLE;
--- a/layout/Makefile.in
+++ b/layout/Makefile.in
@@ -83,11 +83,12 @@ PARALLEL_DIRS += \
xul/base/test \
$(NULL)
TOOL_DIRS += tools/reftest
DIRS += tools/pageloader
ifndef MOZ_ENABLE_LIBXUL
TOOL_DIRS += html/tests
endif
+TOOL_DIRS += reftests/fonts reftests/fonts/mplus
endif
include $(topsrcdir)/config/rules.mk
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -329,23 +329,16 @@ static void DrawBorderImageComponent(nsI
PRUint8 aHFill,
PRUint8 aVFill,
const nsSize& aUnitSize);
static nscolor MakeBevelColor(PRIntn whichSide, PRUint8 style,
nscolor aBackgroundColor,
nscolor aBorderColor);
-static gfxRect GetTextDecorationRectInternal(const gfxPoint& aPt,
- const gfxSize& aLineSize,
- const gfxFloat aAscent,
- const gfxFloat aOffset,
- const PRUint8 aDecoration,
- const PRUint8 aStyle);
-
/* Returns FALSE iff all returned aTwipsRadii == 0, TRUE otherwise */
static PRBool GetBorderRadiusTwips(const nsStyleCorners& aBorderRadius,
const nscoord& aFrameWidth,
nscoord aTwipsRadii[8]);
static InlineBackgroundData* gInlineBGData = nsnull;
// Initialize any static variables used by nsCSSRendering.
@@ -2502,16 +2495,18 @@ nsCSSRendering::PaintDecorationLine(gfxC
const nscolor aColor,
const gfxPoint& aPt,
const gfxSize& aLineSize,
const gfxFloat aAscent,
const gfxFloat aOffset,
const PRUint8 aDecoration,
const PRUint8 aStyle)
{
+ NS_ASSERTION(aStyle != DECORATION_STYLE_NONE, "aStyle is none");
+
gfxRect rect =
GetTextDecorationRectInternal(aPt, aLineSize, aAscent, aOffset,
aDecoration, aStyle);
if (rect.IsEmpty())
return;
if (aDecoration != NS_STYLE_TEXT_DECORATION_UNDERLINE &&
aDecoration != NS_STYLE_TEXT_DECORATION_OVERLINE &&
@@ -2523,79 +2518,171 @@ nsCSSRendering::PaintDecorationLine(gfxC
gfxFloat lineHeight = PR_MAX(NS_round(aLineSize.height), 1.0);
PRBool contextIsSaved = PR_FALSE;
gfxFloat oldLineWidth;
nsRefPtr<gfxPattern> oldPattern;
switch (aStyle) {
- case NS_STYLE_BORDER_STYLE_SOLID:
- case NS_STYLE_BORDER_STYLE_DOUBLE:
+ case DECORATION_STYLE_SOLID:
+ case DECORATION_STYLE_DOUBLE:
oldLineWidth = aGfxContext->CurrentLineWidth();
oldPattern = aGfxContext->GetPattern();
break;
- case NS_STYLE_BORDER_STYLE_DASHED: {
+ case DECORATION_STYLE_DASHED: {
aGfxContext->Save();
contextIsSaved = PR_TRUE;
+ aGfxContext->Clip(rect);
gfxFloat dashWidth = lineHeight * DOT_LENGTH * DASH_LENGTH;
gfxFloat dash[2] = { dashWidth, dashWidth };
aGfxContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
aGfxContext->SetDash(dash, 2, 0.0);
+ // We should continue to draw the last dash even if it is not in the rect.
+ rect.size.width += dashWidth;
break;
}
- case NS_STYLE_BORDER_STYLE_DOTTED: {
+ case DECORATION_STYLE_DOTTED: {
aGfxContext->Save();
contextIsSaved = PR_TRUE;
+ aGfxContext->Clip(rect);
gfxFloat dashWidth = lineHeight * DOT_LENGTH;
gfxFloat dash[2];
if (lineHeight > 2.0) {
dash[0] = 0.0;
dash[1] = dashWidth * 2.0;
aGfxContext->SetLineCap(gfxContext::LINE_CAP_ROUND);
} else {
dash[0] = dashWidth;
dash[1] = dashWidth;
}
aGfxContext->SetDash(dash, 2, 0.0);
+ // We should continue to draw the last dot even if it is not in the rect.
+ rect.size.width += dashWidth;
break;
}
+ case DECORATION_STYLE_WAVY:
+ aGfxContext->Save();
+ contextIsSaved = PR_TRUE;
+ aGfxContext->Clip(rect);
+ if (lineHeight > 2.0) {
+ aGfxContext->SetAntialiasMode(gfxContext::MODE_COVERAGE);
+ } else {
+ // Don't use anti-aliasing here. Because looks like lighter color wavy
+ // line at this case. And probably, users don't think the
+ // non-anti-aliased wavy line is not pretty.
+ aGfxContext->SetAntialiasMode(gfxContext::MODE_ALIASED);
+ }
+ break;
default:
NS_ERROR("Invalid style value!");
return;
}
// The y position should be set to the middle of the line.
rect.pos.y += lineHeight / 2;
aGfxContext->SetColor(gfxRGBA(aColor));
aGfxContext->SetLineWidth(lineHeight);
switch (aStyle) {
- case NS_STYLE_BORDER_STYLE_SOLID:
+ case DECORATION_STYLE_SOLID:
aGfxContext->NewPath();
aGfxContext->MoveTo(rect.TopLeft());
aGfxContext->LineTo(rect.TopRight());
aGfxContext->Stroke();
break;
- case NS_STYLE_BORDER_STYLE_DOUBLE:
+ case DECORATION_STYLE_DOUBLE:
+ /**
+ * We are drawing double line as:
+ *
+ * +-------------------------------------------+
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineHeight
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
+ * | |
+ * | |
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineHeight
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
+ * +-------------------------------------------+
+ */
aGfxContext->NewPath();
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:
+ case DECORATION_STYLE_DOTTED:
+ case DECORATION_STYLE_DASHED:
aGfxContext->NewPath();
aGfxContext->MoveTo(rect.TopLeft());
aGfxContext->LineTo(rect.TopRight());
aGfxContext->Stroke();
break;
+ case DECORATION_STYLE_WAVY: {
+ /**
+ * We are drawing wavy line as:
+ *
+ * P: Path, X: Painted pixel
+ *
+ * +---------------------------------------+
+ * XX|X XXXXXX XXXXXX |
+ * PP|PX XPPPPPPX XPPPPPPX | ^
+ * XX|XPX XPXXXXXXPX XPXXXXXXPX| |
+ * | XPX XPX XPX XPX XP|X |adv
+ * | XPXXXXXXPX XPXXXXXXPX X|PX |
+ * | XPPPPPPX XPPPPPPX |XPX v
+ * | XXXXXX XXXXXX | XX
+ * +---------------------------------------+
+ * <---><---> ^
+ * adv flatLengthAtVertex rightMost
+ *
+ * 1. Always starts from top-left of the drawing area, however, we need
+ * to draw the line from outside of the rect. Because the start
+ * point of the line is not good style if we draw from inside it.
+ * 2. First, draw horizontal line from outside the rect to top-left of
+ * the rect;
+ * 3. Goes down to bottom of the area at 45 degrees.
+ * 4. Slides to right horizontaly, see |flatLengthAtVertex|.
+ * 5. Goes up to top of the area at 45 degrees.
+ * 6. Slides to right horizontaly.
+ * 7. Repeat from 2 until reached to right-most edge of the area.
+ */
+
+ rect.pos.x += lineHeight / 2.0;
+ aGfxContext->NewPath();
+
+ gfxPoint pt(rect.pos);
+ gfxFloat rightMost = pt.x + rect.Width() + lineHeight;
+ gfxFloat adv = rect.Height() - lineHeight;
+ gfxFloat flatLengthAtVertex = PR_MAX((lineHeight - 1.0) * 2.0, 1.0);
+
+ pt.x -= lineHeight;
+ aGfxContext->MoveTo(pt); // 1
+
+ pt.x = rect.pos.x;
+ aGfxContext->LineTo(pt); // 2
+
+ PRBool goDown = PR_TRUE;
+ while (pt.x < rightMost) {
+ pt.x += adv;
+ pt.y += goDown ? adv : -adv;
+
+ aGfxContext->LineTo(pt); // 3 and 5
+
+ pt.x += flatLengthAtVertex;
+ aGfxContext->LineTo(pt); // 4 and 6
+
+ goDown = !goDown;
+ }
+ aGfxContext->Stroke();
+ break;
+ }
default:
NS_ERROR("Invalid style value!");
break;
}
if (contextIsSaved) {
aGfxContext->Restore();
} else {
@@ -2608,65 +2695,105 @@ 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");
+ NS_ASSERTION(aStyle != DECORATION_STYLE_NONE, "aStyle is none");
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;
}
-static gfxRect
-GetTextDecorationRectInternal(const gfxPoint& aPt,
- const gfxSize& aLineSize,
- const gfxFloat aAscent,
- const gfxFloat aOffset,
- const PRUint8 aDecoration,
- const PRUint8 aStyle)
+gfxRect
+nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
+ const gfxSize& aLineSize,
+ const gfxFloat aAscent,
+ const gfxFloat aOffset,
+ const PRUint8 aDecoration,
+ const PRUint8 aStyle)
{
+ NS_ASSERTION(aStyle <= DECORATION_STYLE_WAVY, "Invalid aStyle value");
+
+ if (aStyle == DECORATION_STYLE_NONE)
+ return gfxRect(0, 0, 0, 0);
+
gfxRect r;
r.pos.x = NS_floor(aPt.x + 0.5);
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);
+ gfxFloat lineHeight = NS_round(aLineSize.height);
+ lineHeight = PR_MAX(lineHeight, 1.0);
+ gfxFloat underlineOffsetAdjust = 0.0;
+ r.size.height = lineHeight;
+ if (aStyle == DECORATION_STYLE_DOUBLE) {
+ /**
+ * We will draw double line as:
+ *
+ * +-------------------------------------------+
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineHeight
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
+ * | | ^
+ * | | | gap
+ * | | v
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineHeight
+ * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
+ * +-------------------------------------------+
+ */
+ gfxFloat gap = NS_round(lineHeight / 2.0);
gap = PR_MAX(gap, 1.0);
- r.size.height = basesize * 2.0 + gap;
- } else {
- r.size.height = basesize;
+ r.size.height = lineHeight * 2.0 + gap;
+ } else if (aStyle == DECORATION_STYLE_WAVY) {
+ /**
+ * We will draw wavy line as:
+ *
+ * +-------------------------------------------+
+ * |XXXXX XXXXXX XXXXXX | ^
+ * |XXXXXX XXXXXXXX XXXXXXXX | | lineHeight
+ * |XXXXXXX XXXXXXXXXX XXXXXXXXXX| v
+ * | XXX XXX XXX XXX XX|
+ * | XXXXXXXXXX XXXXXXXXXX X|
+ * | XXXXXXXX XXXXXXXX |
+ * | XXXXXX XXXXXX |
+ * +-------------------------------------------+
+ */
+ r.size.height = lineHeight > 2.0 ? lineHeight * 4.0 : lineHeight * 3.0;
+ // If this is underline, the middle of the rect should be aligned to the
+ // specified underline offset. So, wavy line's top edge can overlap to
+ // baseline. Because even if the wavy line overlaps the baseline of the
+ // text, that shouldn't cause unreadability.
+ underlineOffsetAdjust = r.Height() / 2.0;
}
gfxFloat baseline = NS_floor(aPt.y + aAscent + 0.5);
- gfxFloat offset = 0;
+ gfxFloat offset = 0.0;
switch (aDecoration) {
case NS_STYLE_TEXT_DECORATION_UNDERLINE:
- offset = aOffset;
+ offset = aOffset + underlineOffsetAdjust;
break;
case NS_STYLE_TEXT_DECORATION_OVERLINE:
- offset = aOffset - basesize + r.Height();
+ offset = aOffset - lineHeight + r.Height();
break;
case NS_STYLE_TEXT_DECORATION_LINE_THROUGH: {
gfxFloat extra = NS_floor(r.Height() / 2.0 + 0.5);
- extra = PR_MAX(extra, basesize);
- offset = aOffset - basesize + extra;
+ extra = PR_MAX(extra, lineHeight);
+ offset = aOffset - lineHeight + extra;
break;
}
default:
NS_ERROR("Invalid decoration value!");
}
r.pos.y = baseline - NS_floor(offset + 0.5);
return r;
}
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -197,16 +197,25 @@ struct nsCSSRendering {
const nsStyleBackground* aBGColor,
const nsRect& aBorderRect,
PRInt32 aAppUnitsPerCSSPixel,
PRUint8 aStartBevelSide = 0,
nscoord aStartBevelOffset = 0,
PRUint8 aEndBevelSide = 0,
nscoord aEndBevelOffset = 0);
+ enum {
+ DECORATION_STYLE_NONE = 0,
+ DECORATION_STYLE_SOLID = 1,
+ DECORATION_STYLE_DOTTED = 2,
+ DECORATION_STYLE_DASHED = 3,
+ DECORATION_STYLE_DOUBLE = 4,
+ DECORATION_STYLE_WAVY = 5
+ };
+
/**
* Function for painting the decoration lines for the text.
* 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
* @param aPt the top/left edge of the text
@@ -215,21 +224,18 @@ struct nsCSSRendering {
* @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.
+ * @param aStyle the style of the decoration line (See above
+ * enum names).
*/
static void PaintDecorationLine(gfxContext* aGfxContext,
const nscolor aColor,
const gfxPoint& aPt,
const gfxSize& aLineSize,
const gfxFloat aAscent,
const gfxFloat aOffset,
const PRUint8 aDecoration,
@@ -246,31 +252,36 @@ struct nsCSSRendering {
* @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.
+ * @param aStyle the style of the decoration line (See above
+ * enum names).
* 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 gfxRect GetTextDecorationRectInternal(const gfxPoint& aPt,
+ const gfxSize& aLineSize,
+ const gfxFloat aAscent,
+ const gfxFloat aOffset,
+ const PRUint8 aDecoration,
+ const PRUint8 aStyle);
};
/*
* nsContextBoxBlur
* Creates an 8-bit alpha channel context for callers to draw in, blurs the
* contents of that context and applies it as a 1-color mask on a
* different existing context. Uses gfxAlphaBoxBlur as its back end.
*
--- a/layout/base/tests/Makefile.in
+++ b/layout/base/tests/Makefile.in
@@ -67,16 +67,17 @@ DEFINES += -D_IMPL_NS_LAYOUT
test_bug465448.xul \
test_bug469170.html \
test_bug471126.html \
test_bug435293-scale.html \
test_bug435293-interaction.html \
test_bug435293-skew.html \
test_printpreview.html \
test_bug482976.html \
+ decoration_line_rendering.js \
$(NULL)
# test_bug396024.html is currently disabled because it interacts badly with
# the "You can't print-preview while the page is loading" dialog.
# (See bug 407080)
# Tests for bugs 441782 and 467672 don't pass reliably on Windows, because of bug 469208
ifeq (,$(filter windows,$(MOZ_WIDGET_TOOLKIT)))
_TEST_FILES += \
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/decoration_line_rendering.js
@@ -0,0 +1,180 @@
+function addPoint(aSVGElement, aPolylineElement, aX, aY) {
+ var pt = aSVGElement.createSVGPoint();
+ pt.x = aX;
+ pt.y = aY;
+ aPolylineElement.points.appendItem(pt);
+}
+
+function round(aFloat)
+{
+ return aFloat >= 0.0 ? Math.floor(aFloat + 0.5) : Math.ceil(aFloat - 0.5);
+}
+
+const kDecorationStyleNone = 0;
+const kDecorationStyleSolid = 1;
+const kDecorationStyleDotted = 2;
+const kDecorationStyleDashed = 3;
+const kDecorationStyleDouble = 4;
+const kDecorationStyleWavy = 5;
+
+const kDotLength = 1.0;
+const kDashLength = 3.0;
+
+const kSVGNS = "http://www.w3.org/2000/svg";
+
+// XXX following functions only support to draw underline now.
+
+function drawDecorationLine(aDocument, aColor, aPt, aLineSize, aAscent, aOffset, aStyle)
+{
+ var rect = getTextDecorationRect(aPt, aLineSize, aAscent, aOffset, aStyle);
+ if (rect.width == 0 || rect.height == 0)
+ return;
+
+ var root = aDocument.documentElement;
+ var container = aDocument.createElementNS(kSVGNS, "svg");
+ root.appendChild(container);
+
+ var line1 = aDocument.createElementNS(kSVGNS, "polyline");
+ var line2;
+
+ var style = "position: absolute;";
+ style += "left: " + rect.x + "px;";
+ style += "top: " + rect.y + "px;";
+ style += "width: " + rect.width + "px;";
+ style += "height: " + rect.height + "px;";
+ container.setAttribute("style", style);
+ rect.x = rect.y = 0;
+
+ var lineHeight = Math.max(round(aLineSize.height), 1.0);
+
+ switch (aStyle) {
+ case kDecorationStyleDouble:
+ line2 = aDocument.createElementNS(kSVGNS, "polyline");
+ container.appendChild(line2);
+ case kDecorationStyleSolid:
+ container.appendChild(line1);
+ break;
+ case kDecorationStyleDashed:
+ container.appendChild(line1);
+ var dashWidth = lineHeight * kDotLength * kDashLength;
+ var dash = "stroke-dasharray: " + dashWidth + ", " + dashWidth + ";";
+ var lineCap = "stroke-linecap: butt;"
+ line1.setAttribute("style", dash + lineCap);
+ rect.width += dashWidth;
+ break;
+ case kDecorationStyleDotted:
+ container.appendChild(line1);
+ var dashWidth = lineHeight * kDotLength;
+ var dash = "stroke-dasharray: ";
+ var lineCap = "";
+ if (lineHeight > 2.0) {
+ dash += "0.0, " + dashWidth * 2.0 + ";";
+ lineCap = "stroke-linecap: round;";
+ } else {
+ dash += dashWidth + ", " + dashWidth + ";";
+ }
+ rect.width += dashWidth;
+ line1.setAttribute("style", dash + lineCap);
+ break;
+ case kDecorationStyleWavy:
+ container.appendChild(line1);
+ if (lineHeight > 2.0) {
+ //
+ } else {
+ line1.setAttribute("shape-rendering", "optimizeSpeed");
+ }
+ break;
+ }
+
+ rect.y += lineHeight / 2;
+
+ line1.setAttribute("fill", "none");
+ line1.setAttribute("stroke", aColor);
+ line1.setAttribute("stroke-width", lineHeight);
+ if (line2) {
+ line2.setAttribute("fill", "none");
+ line2.setAttribute("stroke", aColor);
+ line2.setAttribute("stroke-width", lineHeight);
+ }
+
+ switch (aStyle) {
+ case kDecorationStyleSolid:
+ addPoint(container, line1, rect.x, rect.y);
+ addPoint(container, line1, rect.x + rect.width, rect.y);
+ break;
+ case kDecorationStyleDouble:
+ addPoint(container, line1, rect.x, rect.y);
+ addPoint(container, line1, rect.x + rect.width, rect.y);
+ rect.height -= lineHeight;
+ addPoint(container, line2, rect.x, rect.y + rect.height);
+ addPoint(container, line2, rect.x + rect.width, rect.y + rect.height);
+ break;
+ case kDecorationStyleDotted:
+ case kDecorationStyleDashed:
+ addPoint(container, line1, rect.x, rect.y);
+ addPoint(container, line1, rect.x + rect.width, rect.y);
+ break;
+ case kDecorationStyleWavy:
+ rect.x += lineHeight / 2.0;
+
+ var pt = { x: rect.x, y: rect.y };
+ var rightMost = pt.x + rect.width + lineHeight;
+ var adv = rect.height - lineHeight;
+ var flatLengthAtVertex = Math.max((lineHeight - 1.0) * 2.0, 1.0);
+
+ var points = "";
+
+ pt.x -= lineHeight;
+ addPoint(container, line1, pt.x, pt.y);
+
+ pt.x = rect.x;
+ addPoint(container, line1, pt.x, pt.y);
+
+ var goDown = true;
+ while (pt.x < rightMost) {
+ pt.x += adv;
+ pt.y += goDown ? adv : -adv;
+
+ addPoint(container, line1, pt.x, pt.y);
+
+ pt.x += flatLengthAtVertex;
+ addPoint(container, line1, pt.x, pt.y);
+
+ goDown = !goDown;
+ }
+ break;
+ }
+}
+
+function getTextDecorationRect(aPt, aLineSize, aAscent, aOffset, aStyle)
+{
+ if (aStyle == kDecorationStyleNone)
+ return { x: 0, y: 0, width: 0, height: 0 };
+
+ var r = {};
+ r.x = Math.floor(aPt.x + 0.5);
+ r.width = round(aLineSize.width);
+
+ var lineHeight = round(aLineSize.height);
+ lineHeight = Math.max(lineHeight, 1.0);
+ var underlineOffsetAdjust = 0.0;
+ r.height = lineHeight;
+ if (aStyle == kDecorationStyleDouble) {
+ var gap = round(lineHeight / 2.0);
+ gap = Math.max(gap, 1.0);
+ r.height = lineHeight * 2.0 + gap;
+ } else if (aStyle == kDecorationStyleWavy) {
+ r.height = lineHeight > 2.0 ? lineHeight * 4.0 : lineHeight * 3.0;
+ underlineOffsetAdjust = r.height / 2.0;
+ }
+
+ var baseline = Math.floor(aPt.y + aAscent + 0.5);
+ var offset = 0.0;
+
+ offset = aOffset + underlineOffsetAdjust;
+
+ r.y = baseline - Math.floor(offset + 0.5);
+
+ return r;
+}
+
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -5982,17 +5982,17 @@ nsBlockFrame::PaintTextDecorationLine(gf
// Only paint if we have a positive width
if (width > 0) {
gfxPoint pt(PresContext()->AppUnitsToGfxUnits(start + aPt.x),
PresContext()->AppUnitsToGfxUnits(aLine->mBounds.y + aPt.y));
gfxSize size(PresContext()->AppUnitsToGfxUnits(width), aSize);
nsCSSRendering::PaintDecorationLine(
aCtx, aColor, pt, size,
PresContext()->AppUnitsToGfxUnits(aLine->GetAscent()),
- aOffset, aDecoration, NS_STYLE_BORDER_STYLE_SOLID);
+ aOffset, aDecoration, nsCSSRendering::DECORATION_STYLE_SOLID);
}
}
#ifdef DEBUG
static void DebugOutputDrawLine(PRInt32 aDepth, nsLineBox* aLine, PRBool aDrawn) {
if (nsBlockFrame::gNoisyDamageRepair) {
nsFrame::IndentBy(stdout, aDepth+1);
nsRect lineArea = aLine->GetCombinedArea();
--- a/layout/generic/nsHTMLContainerFrame.cpp
+++ b/layout/generic/nsHTMLContainerFrame.cpp
@@ -356,17 +356,17 @@ nsHTMLContainerFrame::PaintTextDecoratio
bp.side(side) = 0;
}
}
nscoord innerWidth = mRect.width - bp.left - bp.right;
gfxPoint pt(PresContext()->AppUnitsToGfxUnits(bp.left + aPt.x),
PresContext()->AppUnitsToGfxUnits(bp.top + aPt.y));
gfxSize size(PresContext()->AppUnitsToGfxUnits(innerWidth), aSize);
nsCSSRendering::PaintDecorationLine(aCtx, aColor, pt, size, aAscent, aOffset,
- aDecoration, NS_STYLE_BORDER_STYLE_SOLID);
+ aDecoration, nsCSSRendering::DECORATION_STYLE_SOLID);
}
void
nsHTMLContainerFrame::GetTextDecorations(nsPresContext* aPresContext,
PRBool aIsBlock,
PRUint8& aDecorations,
nscolor& aUnderColor,
nscolor& aOverColor,
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -2650,68 +2650,8 @@ nsLineLayout::RelativePositionFrames(Per
// NS_FRAME_OUTSIDE_CHILDREN bit..
if (psd->mFrame) {
PerFrameData* spanPFD = psd->mFrame;
nsIFrame* frame = spanPFD->mFrame;
frame->FinishAndStoreOverflow(&combinedAreaResult, frame->GetSize());
}
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));
- nsIThebesFontMetrics* tfm = static_cast<nsIThebesFontMetrics*>(fm.get());
- gfxFontGroup* fontGroup = tfm->GetThebesFontGroup();
- gfxFont* firstFont = fontGroup->GetFontAt(0);
- if (!firstFont)
- return; // OOM
- const gfxFont::Metrics& metrics = firstFont->GetMetrics();
-
- gfxFloat ascent = aAscentOverride == 0 ? metrics.maxAscent :
- aPresContext->AppUnitsToGfxUnits(aAscentOverride);
- nsRect decorationArea;
- if (aDecorations & (NS_STYLE_TEXT_DECORATION_UNDERLINE |
- NS_STYLE_TEXT_DECORATION_OVERLINE)) {
- gfxSize size(aPresContext->AppUnitsToGfxUnits(aCombinedArea.width),
- metrics.underlineSize);
- if (aDecorations & NS_STYLE_TEXT_DECORATION_OVERLINE) {
- decorationArea =
- nsCSSRendering::GetTextDecorationRect(aPresContext, size, ascent,
- metrics.maxAscent, 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.0f);
- size.height *= aUnderlineSizeRatio;
- gfxFloat underlineOffset = fontGroup->GetUnderlineOffset();
- decorationArea =
- nsCSSRendering::GetTextDecorationRect(aPresContext, size, ascent,
- underlineOffset,
- NS_STYLE_TEXT_DECORATION_UNDERLINE,
- NS_STYLE_BORDER_STYLE_SOLID);
- aCombinedArea.UnionRect(aCombinedArea, decorationArea);
- }
- }
- if (aDecorations & NS_STYLE_TEXT_DECORATION_LINE_THROUGH) {
- gfxSize size(aPresContext->AppUnitsToGfxUnits(aCombinedArea.width),
- metrics.strikeoutSize);
- decorationArea =
- nsCSSRendering::GetTextDecorationRect(aPresContext, size, ascent,
- metrics.strikeoutOffset,
- NS_STYLE_TEXT_DECORATION_LINE_THROUGH,
- NS_STYLE_BORDER_STYLE_SOLID);
- aCombinedArea.UnionRect(aCombinedArea, decorationArea);
- }
-}
--- a/layout/generic/nsLineLayout.h
+++ b/layout/generic/nsLineLayout.h
@@ -139,22 +139,16 @@ public:
/**
* Handle all the relative positioning in the line, compute the
* combined area (== overflow area) for the line, and handle view
* sizing/positioning and the setting of NS_FRAME_OUTSIDE_CHILDREN.
*/
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
protected:
#define LL_FIRSTLETTERSTYLEOK 0x00000008
#define LL_ISTOPOFPAGE 0x00000010
#define LL_IMPACTEDBYFLOATS 0x00000040
#define LL_LASTFLOATWASLETTERFRAME 0x00000080
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -437,15 +437,17 @@ protected:
return !!(mDecorations & NS_STYLE_TEXT_DECORATION_OVERLINE);
}
PRBool HasStrikeout() {
return !!(mDecorations & NS_STYLE_TEXT_DECORATION_LINE_THROUGH);
}
};
TextDecorations GetTextDecorations(nsPresContext* aPresContext);
- PRBool HasSelectionOverflowingDecorations(nsPresContext* aPresContext,
- float* aRatio = nsnull);
+ // Set non empty rect to aRect, it should be overflow rect or frame rect.
+ // If the result rect is larger than the given rect, this returns PR_TRUE.
+ PRBool CombineSelectionUnderlineRect(nsPresContext* aPresContext,
+ nsRect& aRect);
PRBool IsFloatingFirstLetterChild();
};
#endif
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -249,30 +249,57 @@ public:
PRBool GetSelectionColors(nscolor* aForeColor,
nscolor* aBackColor);
void GetHighlightColors(nscolor* aForeColor,
nscolor* aBackColor);
void GetIMESelectionColors(PRInt32 aIndex,
nscolor* aForeColor,
nscolor* aBackColor);
// if this returns PR_FALSE, we don't need to draw underline.
- PRBool GetIMEUnderline(PRInt32 aIndex,
- nscolor* aLineColor,
- float* aRelativeSize,
- PRUint8* aStyle);
+ PRBool GetSelectionUnderlineForPaint(PRInt32 aIndex,
+ nscolor* aLineColor,
+ float* aRelativeSize,
+ PRUint8* aStyle);
+
+ // if this returns PR_FALSE, we don't need to draw underline.
+ static PRBool GetSelectionUnderline(nsPresContext* aPresContext,
+ PRInt32 aIndex,
+ nscolor* aLineColor,
+ float* aRelativeSize,
+ PRUint8* aStyle);
nsPresContext* PresContext() { return mPresContext; }
enum {
eIndexRawInput = 0,
eIndexSelRawText,
eIndexConvText,
- eIndexSelConvText
+ eIndexSelConvText,
+ eIndexSpellChecker
};
+ static PRInt32 GetUnderlineStyleIndexForSelectionType(PRInt32 aSelectionType)
+ {
+ switch (aSelectionType) {
+ case nsISelectionController::SELECTION_IME_RAWINPUT:
+ return eIndexRawInput;
+ case nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT:
+ return eIndexSelRawText;
+ case nsISelectionController::SELECTION_IME_CONVERTEDTEXT:
+ return eIndexConvText;
+ case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT:
+ return eIndexSelConvText;
+ case nsISelectionController::SELECTION_SPELLCHECK:
+ return eIndexSpellChecker;
+ default:
+ NS_WARNING("non-IME selection type");
+ return eIndexRawInput;
+ }
+ }
+
protected:
nsTextFrame* mFrame;
nsPresContext* mPresContext;
PRPackedBool mInitCommonColors;
PRPackedBool mInitSelectionColors;
// Selection data
@@ -280,34 +307,35 @@ protected:
nscolor mSelectionTextColor;
nscolor mSelectionBGColor;
// Common data
PRInt32 mSufficientContrast;
nscolor mFrameBackgroundColor;
- // IME selection colors and underline info
- struct nsIMEStyle {
+ // selection colors and underline info, the colors are resolved colors,
+ // i.e., the foreground color and background color are swapped if it's needed.
+ // And also line color will be resolved from them.
+ struct nsSelectionStyle {
PRBool mInit;
nscolor mTextColor;
nscolor mBGColor;
nscolor mUnderlineColor;
PRUint8 mUnderlineStyle;
+ float mUnderlineRelativeSize;
};
- nsIMEStyle mIMEStyle[4];
- // indices
- float mIMEUnderlineRelativeSize;
+ nsSelectionStyle mSelectionStyle[5];
// Color initializations
void InitCommonColors();
PRBool InitSelectionColors();
- nsIMEStyle* GetIMEStyle(PRInt32 aIndex);
- void InitIMEStyle(PRInt32 aIndex);
+ nsSelectionStyle* GetSelectionStyle(PRInt32 aIndex);
+ void InitSelectionStyle(PRInt32 aIndex);
PRBool EnsureSufficientContrast(nscolor *aForeColor, nscolor *aBackColor);
nscolor GetResolvedForeColor(nscolor aColor, nscolor aDefaultForeColor,
nscolor aBackColor);
};
static void
@@ -2942,19 +2970,18 @@ ShouldDarkenColors(nsPresContext* aPresC
}
nsTextPaintStyle::nsTextPaintStyle(nsTextFrame* aFrame)
: mFrame(aFrame),
mPresContext(aFrame->PresContext()),
mInitCommonColors(PR_FALSE),
mInitSelectionColors(PR_FALSE)
{
- for (int i = 0; i < 4; i++)
- mIMEStyle[i].mInit = PR_FALSE;
- mIMEUnderlineRelativeSize = -1.0f;
+ for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(mSelectionStyle); i++)
+ mSelectionStyle[i].mInit = PR_FALSE;
}
PRBool
nsTextPaintStyle::EnsureSufficientContrast(nscolor *aForeColor, nscolor *aBackColor)
{
InitCommonColors();
// If the combination of selection background color and frame background color
@@ -3022,42 +3049,42 @@ nsTextPaintStyle::GetHighlightColors(nsc
void
nsTextPaintStyle::GetIMESelectionColors(PRInt32 aIndex,
nscolor* aForeColor,
nscolor* aBackColor)
{
NS_ASSERTION(aForeColor, "aForeColor is null");
NS_ASSERTION(aBackColor, "aBackColor is null");
- NS_ASSERTION(aIndex >= 0 && aIndex < 4, "Index out of range");
-
- nsIMEStyle* IMEStyle = GetIMEStyle(aIndex);
- *aForeColor = IMEStyle->mTextColor;
- *aBackColor = IMEStyle->mBGColor;
+ NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
+
+ nsSelectionStyle* selectionStyle = GetSelectionStyle(aIndex);
+ *aForeColor = selectionStyle->mTextColor;
+ *aBackColor = selectionStyle->mBGColor;
}
PRBool
-nsTextPaintStyle::GetIMEUnderline(PRInt32 aIndex,
- nscolor* aLineColor,
- float* aRelativeSize,
- PRUint8* aStyle)
+nsTextPaintStyle::GetSelectionUnderlineForPaint(PRInt32 aIndex,
+ nscolor* aLineColor,
+ float* aRelativeSize,
+ PRUint8* aStyle)
{
NS_ASSERTION(aLineColor, "aLineColor is null");
NS_ASSERTION(aRelativeSize, "aRelativeSize is null");
- NS_ASSERTION(aIndex >= 0 && aIndex < 4, "Index out of range");
-
- nsIMEStyle* IMEStyle = GetIMEStyle(aIndex);
- if (IMEStyle->mUnderlineStyle == NS_STYLE_BORDER_STYLE_NONE ||
- IMEStyle->mUnderlineColor == NS_TRANSPARENT ||
- mIMEUnderlineRelativeSize <= 0.0f)
+ NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
+
+ nsSelectionStyle* selectionStyle = GetSelectionStyle(aIndex);
+ if (selectionStyle->mUnderlineStyle == NS_STYLE_BORDER_STYLE_NONE ||
+ selectionStyle->mUnderlineColor == NS_TRANSPARENT ||
+ selectionStyle->mUnderlineRelativeSize <= 0.0f)
return PR_FALSE;
- *aLineColor = IMEStyle->mUnderlineColor;
- *aRelativeSize = mIMEUnderlineRelativeSize;
- *aStyle = IMEStyle->mUnderlineStyle;
+ *aLineColor = selectionStyle->mUnderlineColor;
+ *aRelativeSize = selectionStyle->mUnderlineRelativeSize;
+ *aStyle = selectionStyle->mUnderlineStyle;
return PR_TRUE;
}
void
nsTextPaintStyle::InitCommonColors()
{
if (mInitCommonColors)
return;
@@ -3175,101 +3202,154 @@ nsTextPaintStyle::InitSelectionColors()
mSelectionTextColor = EnsureDifferentColors(mFrame->GetStyleColor()->mColor,
mSelectionBGColor);
} else {
EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
}
return PR_TRUE;
}
-nsTextPaintStyle::nsIMEStyle*
-nsTextPaintStyle::GetIMEStyle(PRInt32 aIndex)
-{
- InitIMEStyle(aIndex);
- return &mIMEStyle[aIndex];
+nsTextPaintStyle::nsSelectionStyle*
+nsTextPaintStyle::GetSelectionStyle(PRInt32 aIndex)
+{
+ InitSelectionStyle(aIndex);
+ return &mSelectionStyle[aIndex];
}
struct StyleIDs {
nsILookAndFeel::nsColorID mForeground, mBackground, mLine;
nsILookAndFeel::nsMetricID mLineStyle;
+ nsILookAndFeel::nsMetricFloatID mLineRelativeSize;
};
-static StyleIDs IMEStyleIDs[] = {
+static StyleIDs SelectionStyleIDs[] = {
{ nsILookAndFeel::eColor_IMERawInputForeground,
nsILookAndFeel::eColor_IMERawInputBackground,
nsILookAndFeel::eColor_IMERawInputUnderline,
- nsILookAndFeel::eMetric_IMERawInputUnderlineStyle },
+ nsILookAndFeel::eMetric_IMERawInputUnderlineStyle,
+ nsILookAndFeel::eMetricFloat_IMEUnderlineRelativeSize },
{ nsILookAndFeel::eColor_IMESelectedRawTextForeground,
nsILookAndFeel::eColor_IMESelectedRawTextBackground,
nsILookAndFeel::eColor_IMESelectedRawTextUnderline,
- nsILookAndFeel::eMetric_IMESelectedRawTextUnderlineStyle },
+ nsILookAndFeel::eMetric_IMESelectedRawTextUnderlineStyle,
+ nsILookAndFeel::eMetricFloat_IMEUnderlineRelativeSize },
{ nsILookAndFeel::eColor_IMEConvertedTextForeground,
nsILookAndFeel::eColor_IMEConvertedTextBackground,
nsILookAndFeel::eColor_IMEConvertedTextUnderline,
- nsILookAndFeel::eMetric_IMEConvertedTextUnderlineStyle },
+ nsILookAndFeel::eMetric_IMEConvertedTextUnderlineStyle,
+ nsILookAndFeel::eMetricFloat_IMEUnderlineRelativeSize },
{ nsILookAndFeel::eColor_IMESelectedConvertedTextForeground,
nsILookAndFeel::eColor_IMESelectedConvertedTextBackground,
nsILookAndFeel::eColor_IMESelectedConvertedTextUnderline,
- nsILookAndFeel::eMetric_IMESelectedConvertedTextUnderline }
+ nsILookAndFeel::eMetric_IMESelectedConvertedTextUnderline,
+ nsILookAndFeel::eMetricFloat_IMEUnderlineRelativeSize },
+ { nsILookAndFeel::eColor_LAST_COLOR,
+ nsILookAndFeel::eColor_LAST_COLOR,
+ nsILookAndFeel::eColor_SpellCheckerUnderline,
+ nsILookAndFeel::eMetric_SpellCheckerUnderlineStyle,
+ nsILookAndFeel::eMetricFloat_SpellCheckerUnderlineRelativeSize }
};
static PRUint8 sUnderlineStyles[] = {
- NS_STYLE_BORDER_STYLE_NONE, // NS_UNDERLINE_STYLE_NONE 0
- NS_STYLE_BORDER_STYLE_DOTTED, // NS_UNDERLINE_STYLE_DOTTED 1
- NS_STYLE_BORDER_STYLE_DASHED, // NS_UNDERLINE_STYLE_DASHED 2
- NS_STYLE_BORDER_STYLE_SOLID, // NS_UNDERLINE_STYLE_SOLID 3
- NS_STYLE_BORDER_STYLE_DOUBLE // NS_UNDERLINE_STYLE_DOUBLE 4
+ nsCSSRendering::DECORATION_STYLE_NONE, // NS_UNDERLINE_STYLE_NONE 0
+ nsCSSRendering::DECORATION_STYLE_DOTTED, // NS_UNDERLINE_STYLE_DOTTED 1
+ nsCSSRendering::DECORATION_STYLE_DASHED, // NS_UNDERLINE_STYLE_DASHED 2
+ nsCSSRendering::DECORATION_STYLE_SOLID, // NS_UNDERLINE_STYLE_SOLID 3
+ nsCSSRendering::DECORATION_STYLE_DOUBLE, // NS_UNDERLINE_STYLE_DOUBLE 4
+ nsCSSRendering::DECORATION_STYLE_WAVY // NS_UNDERLINE_STYLE_WAVY 5
};
void
-nsTextPaintStyle::InitIMEStyle(PRInt32 aIndex)
-{
- nsIMEStyle* IMEStyle = &mIMEStyle[aIndex];
- if (IMEStyle->mInit)
+nsTextPaintStyle::InitSelectionStyle(PRInt32 aIndex)
+{
+ NS_ASSERTION(aIndex >= 0 && aIndex < 5, "aIndex is invalid");
+ nsSelectionStyle* selectionStyle = &mSelectionStyle[aIndex];
+ if (selectionStyle->mInit)
return;
- StyleIDs* styleIDs = &IMEStyleIDs[aIndex];
+ StyleIDs* styleIDs = &SelectionStyleIDs[aIndex];
nsILookAndFeel* look = mPresContext->LookAndFeel();
- nscolor foreColor, backColor, lineColor;
- PRInt32 lineStyle;
- look->GetColor(styleIDs->mForeground, foreColor);
- look->GetColor(styleIDs->mBackground, backColor);
- look->GetColor(styleIDs->mLine, lineColor);
- look->GetMetric(styleIDs->mLineStyle, lineStyle);
+ nscolor foreColor, backColor;
+ if (styleIDs->mForeground == nsILookAndFeel::eColor_LAST_COLOR) {
+ foreColor = NS_SAME_AS_FOREGROUND_COLOR;
+ } else {
+ look->GetColor(styleIDs->mForeground, foreColor);
+ }
+ if (styleIDs->mBackground == nsILookAndFeel::eColor_LAST_COLOR) {
+ backColor = NS_TRANSPARENT;
+ } else {
+ look->GetColor(styleIDs->mBackground, backColor);
+ }
// Convert special color to actual color
NS_ASSERTION(foreColor != NS_TRANSPARENT,
"foreColor cannot be NS_TRANSPARENT");
NS_ASSERTION(backColor != NS_SAME_AS_FOREGROUND_COLOR,
"backColor cannot be NS_SAME_AS_FOREGROUND_COLOR");
NS_ASSERTION(backColor != NS_40PERCENT_FOREGROUND_COLOR,
"backColor cannot be NS_40PERCENT_FOREGROUND_COLOR");
foreColor = GetResolvedForeColor(foreColor, GetTextColor(), backColor);
if (NS_GET_A(backColor) > 0)
EnsureSufficientContrast(&foreColor, &backColor);
+ nscolor lineColor;
+ float relativeSize;
+ PRUint8 lineStyle;
+ GetSelectionUnderline(mPresContext, aIndex,
+ &lineColor, &relativeSize, &lineStyle);
lineColor = GetResolvedForeColor(lineColor, foreColor, backColor);
- if (!NS_IS_VALID_UNDERLINE_STYLE(lineStyle))
- lineStyle = NS_UNDERLINE_STYLE_SOLID;
-
- IMEStyle->mTextColor = foreColor;
- IMEStyle->mBGColor = backColor;
- IMEStyle->mUnderlineColor = lineColor;
- IMEStyle->mUnderlineStyle = sUnderlineStyles[lineStyle];
- IMEStyle->mInit = PR_TRUE;
-
- if (mIMEUnderlineRelativeSize == -1.0f) {
- look->GetMetric(nsILookAndFeel::eMetricFloat_IMEUnderlineRelativeSize,
- mIMEUnderlineRelativeSize);
- NS_ASSERTION(mIMEUnderlineRelativeSize >= 0.0f,
- "underline size must be larger than 0");
- }
+ selectionStyle->mTextColor = foreColor;
+ selectionStyle->mBGColor = backColor;
+ selectionStyle->mUnderlineColor = lineColor;
+ selectionStyle->mUnderlineStyle = lineStyle;
+ selectionStyle->mUnderlineRelativeSize = relativeSize;
+ selectionStyle->mInit = PR_TRUE;
+}
+
+/* static */ PRBool
+nsTextPaintStyle::GetSelectionUnderline(nsPresContext* aPresContext,
+ PRInt32 aIndex,
+ nscolor* aLineColor,
+ float* aRelativeSize,
+ PRUint8* aStyle)
+{
+ NS_ASSERTION(aPresContext, "aPresContext is null");
+ NS_ASSERTION(aRelativeSize, "aRelativeSize is null");
+ NS_ASSERTION(aStyle, "aStyle is null");
+ NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
+
+ nsILookAndFeel* look = aPresContext->LookAndFeel();
+
+ StyleIDs& styleID = SelectionStyleIDs[aIndex];
+ nscolor color;
+ float size;
+ PRInt32 style;
+
+ look->GetColor(styleID.mLine, color);
+ look->GetMetric(styleID.mLineStyle, style);
+ if (!NS_IS_VALID_UNDERLINE_STYLE(style)) {
+ NS_ERROR("Invalid underline style value is specified");
+ style = NS_UNDERLINE_STYLE_SOLID;
+ }
+ look->GetMetric(styleID.mLineRelativeSize, size);
+
+ NS_ASSERTION(size, "selection underline relative size must be larger than 0");
+
+ if (aLineColor) {
+ *aLineColor = color;
+ }
+ *aRelativeSize = size;
+ *aStyle = sUnderlineStyles[style];
+
+ return sUnderlineStyles[style] != nsCSSRendering::DECORATION_STYLE_NONE &&
+ color != NS_TRANSPARENT &&
+ size > 0.0f;
}
inline nscolor Get40PercentColor(nscolor aForeColor, nscolor aBackColor)
{
nscolor foreColor = NS_RGBA(NS_GET_R(aForeColor),
NS_GET_G(aForeColor),
NS_GET_B(aForeColor),
(PRUint8)(255 * 0.4f));
@@ -3935,24 +4015,20 @@ nsTextFrame::UnionTextDecorationOverflow
fm->GetMaxAscent(fontAscent);
fm->GetMaxHeight(fontHeight);
nsRect fontRect(0, mAscent - fontAscent, GetSize().width, fontHeight);
aOverflowRect->UnionRect(*aOverflowRect, fontRect);
}
// When this frame is not selected, the text-decoration area must be in
// frame bounds.
- float ratio;
+ nsRect decorationRect;
if (!(GetStateBits() & NS_FRAME_SELECTED_CONTENT) ||
- !HasSelectionOverflowingDecorations(aPresContext, &ratio))
+ !CombineSelectionUnderlineRect(aPresContext, *aOverflowRect))
return;
-
- nsLineLayout::CombineTextDecorations(aPresContext,
- NS_STYLE_TEXT_DECORATION_UNDERLINE,
- this, *aOverflowRect, mAscent, ratio);
AddStateBits(TEXT_SELECTION_UNDERLINE_OVERFLOWED);
}
void
nsTextFrame::PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
const gfxPoint& aFramePt,
const gfxPoint& aTextBaselinePt,
nsTextPaintStyle& aTextPaintStyle,
@@ -3976,102 +4052,94 @@ nsTextFrame::PaintTextDecorations(gfxCon
gfxFloat ascent = gfxFloat(mAscent) / app;
nscolor lineColor;
if (decorations.HasOverline()) {
lineColor = aOverrideColor ? *aOverrideColor : decorations.mOverColor;
size.height = fontMetrics.underlineSize;
nsCSSRendering::PaintDecorationLine(
aCtx, lineColor, pt, size, ascent, fontMetrics.maxAscent,
- NS_STYLE_TEXT_DECORATION_OVERLINE, NS_STYLE_BORDER_STYLE_SOLID);
+ NS_STYLE_TEXT_DECORATION_OVERLINE,
+ nsCSSRendering::DECORATION_STYLE_SOLID);
}
if (decorations.HasUnderline()) {
lineColor = aOverrideColor ? *aOverrideColor : decorations.mUnderColor;
size.height = fontMetrics.underlineSize;
gfxFloat offset = aProvider.GetFontGroup()->GetUnderlineOffset();
nsCSSRendering::PaintDecorationLine(
aCtx, lineColor, pt, size, ascent, offset,
- NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_SOLID);
+ NS_STYLE_TEXT_DECORATION_UNDERLINE,
+ nsCSSRendering::DECORATION_STYLE_SOLID);
}
if (decorations.HasStrikeout()) {
lineColor = aOverrideColor ? *aOverrideColor : decorations.mStrikeColor;
size.height = fontMetrics.strikeoutSize;
gfxFloat offset = fontMetrics.strikeoutOffset;
nsCSSRendering::PaintDecorationLine(
aCtx, lineColor, pt, size, ascent, offset,
- NS_STYLE_TEXT_DECORATION_LINE_THROUGH, NS_STYLE_BORDER_STYLE_SOLID);
+ NS_STYLE_TEXT_DECORATION_LINE_THROUGH,
+ nsCSSRendering::DECORATION_STYLE_SOLID);
}
}
// Make sure this stays in sync with DrawSelectionDecorations below
static const SelectionType SelectionTypesWithDecorations =
nsISelectionController::SELECTION_SPELLCHECK |
nsISelectionController::SELECTION_IME_RAWINPUT |
nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT |
nsISelectionController::SELECTION_IME_CONVERTEDTEXT |
nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT;
-static void DrawIMEUnderline(gfxContext* aContext, PRInt32 aIndex,
- nsTextPaintStyle& aTextPaintStyle, const gfxPoint& aPt, gfxFloat aWidth,
- gfxFloat aAscent, gfxFloat aSize, gfxFloat aOffset)
-{
- nscolor color;
- float relativeSize;
- PRUint8 style;
- if (!aTextPaintStyle.GetIMEUnderline(aIndex, &color, &relativeSize, &style))
- return;
-
- gfxFloat actualSize = relativeSize * aSize;
- 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,
- NS_STYLE_TEXT_DECORATION_UNDERLINE, style);
-}
-
/**
* This, plus SelectionTypesWithDecorations, encapsulates all knowledge about
* drawing text decoration for selections.
*/
static void DrawSelectionDecorations(gfxContext* aContext, SelectionType aType,
nsTextPaintStyle& aTextPaintStyle, const gfxPoint& aPt, gfxFloat aWidth,
gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics)
{
+ gfxPoint pt(aPt);
gfxSize size(aWidth, aFontMetrics.underlineSize);
switch (aType) {
+ case nsISelectionController::SELECTION_IME_RAWINPUT:
+ case nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT:
+ case nsISelectionController::SELECTION_IME_CONVERTEDTEXT:
+ case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT:
+ // IME decoration lines should not be drawn on the both ends, i.e., we
+ // need to cut both edges of the decoration lines. Because same style
+ // IME selections can adjoin, but the users need to be able to know
+ // where are the boundaries of the selections.
+ //
+ // X: underline
+ //
+ // IME selection #1 IME selection #2 IME selection #3
+ // | | |
+ // | XXXXXXXXXXXXXXXXXXX | XXXXXXXXXXXXXXXXXXXX | XXXXXXXXXXXXXXXXXXX
+ // +---------------------+----------------------+--------------------
+ // ^ ^ ^ ^ ^
+ // gap gap gap
+ pt.x += 1.0;
+ size.width -= 2.0;
case nsISelectionController::SELECTION_SPELLCHECK: {
- nsCSSRendering::PaintDecorationLine(
- aContext, NS_RGB(255,0,0),
- aPt, size, aAscent, aFontMetrics.underlineOffset,
- NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_DOTTED);
+ float relativeSize;
+ PRUint8 style;
+ nscolor color;
+ PRInt32 index =
+ nsTextPaintStyle::GetUnderlineStyleIndexForSelectionType(aType);
+ if (aTextPaintStyle.GetSelectionUnderlineForPaint(index, &color,
+ &relativeSize,
+ &style)) {
+ size.height *= relativeSize;
+ nsCSSRendering::PaintDecorationLine(
+ aContext, color, pt, size, aAscent, aFontMetrics.underlineOffset,
+ NS_STYLE_TEXT_DECORATION_UNDERLINE, style);
+ }
break;
}
-
- case nsISelectionController::SELECTION_IME_RAWINPUT:
- DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexRawInput,
- aTextPaintStyle, aPt, aWidth, aAscent, size.height,
- aFontMetrics.underlineOffset);
- break;
- case nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT:
- DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexSelRawText,
- aTextPaintStyle, aPt, aWidth, aAscent, size.height,
- aFontMetrics.underlineOffset);
- break;
- case nsISelectionController::SELECTION_IME_CONVERTEDTEXT:
- DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexConvText,
- aTextPaintStyle, aPt, aWidth, aAscent, size.height,
- aFontMetrics.underlineOffset);
- break;
- case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT:
- DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexSelConvText,
- aTextPaintStyle, aPt, aWidth, aAscent, size.height,
- aFontMetrics.underlineOffset);
- break;
-
default:
NS_WARNING("Requested selection decorations when there aren't any");
break;
}
}
/**
* This function encapsulates all knowledge of how selections affect foreground
@@ -4086,30 +4154,22 @@ static PRBool GetSelectionTextColors(Sel
{
switch (aType) {
case nsISelectionController::SELECTION_NORMAL:
return aTextPaintStyle.GetSelectionColors(aForeground, aBackground);
case nsISelectionController::SELECTION_FIND:
aTextPaintStyle.GetHighlightColors(aForeground, aBackground);
return PR_TRUE;
case nsISelectionController::SELECTION_IME_RAWINPUT:
- aTextPaintStyle.GetIMESelectionColors(nsTextPaintStyle::eIndexRawInput,
- aForeground, aBackground);
- return PR_TRUE;
case nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT:
- aTextPaintStyle.GetIMESelectionColors(nsTextPaintStyle::eIndexSelRawText,
- aForeground, aBackground);
- return PR_TRUE;
case nsISelectionController::SELECTION_IME_CONVERTEDTEXT:
- aTextPaintStyle.GetIMESelectionColors(nsTextPaintStyle::eIndexConvText,
- aForeground, aBackground);
- return PR_TRUE;
case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT:
- aTextPaintStyle.GetIMESelectionColors(nsTextPaintStyle::eIndexSelConvText,
- aForeground, aBackground);
+ aTextPaintStyle.GetIMESelectionColors(
+ nsTextPaintStyle::GetUnderlineStyleIndexForSelectionType(aType),
+ aForeground, aBackground);
return PR_TRUE;
default:
*aForeground = aTextPaintStyle.GetTextColor();
*aBackground = NS_RGBA(0,0,0,0);
return PR_FALSE;
}
}
@@ -4702,39 +4762,63 @@ nsTextFrame::CalcContentOffsetsFromFrame
offsets.content = GetContent();
offsets.offset = offsets.secondaryOffset = selectedOffset;
offsets.associateWithNext = mContentOffset == offsets.offset;
return offsets;
}
PRBool
-nsTextFrame::HasSelectionOverflowingDecorations(nsPresContext* aPresContext,
- float* aRatio)
-{
- float ratio;
- nsILookAndFeel* look = aPresContext->LookAndFeel();
- look->GetMetric(nsILookAndFeel::eMetricFloat_IMEUnderlineRelativeSize, ratio);
- if (aRatio)
- *aRatio = ratio;
- if (ratio <= 1.0f)
+nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
+ nsRect& aRect)
+{
+ if (aRect.IsEmpty())
return PR_FALSE;
+ nsRect givenRect = aRect;
+
+ nsCOMPtr<nsIFontMetrics> fm;
+ nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
+ nsIThebesFontMetrics* tfm = static_cast<nsIThebesFontMetrics*>(fm.get());
+ gfxFontGroup* fontGroup = tfm->GetThebesFontGroup();
+ gfxFont* firstFont = fontGroup->GetFontAt(0);
+ if (!firstFont)
+ return PR_FALSE; // OOM
+ const gfxFont::Metrics& metrics = firstFont->GetMetrics();
+ gfxFloat underlineOffset = fontGroup->GetUnderlineOffset();
+ gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(mAscent);
+
SelectionDetails *details = GetSelectionDetails();
- PRBool retval = PR_FALSE;
for (SelectionDetails *sd = details; sd; sd = sd->mNext) {
- if (sd->mStart != sd->mEnd &&
- sd->mType & SelectionTypesWithDecorations) {
- retval = PR_TRUE;
- break;
+ if (sd->mStart == sd->mEnd || !(sd->mType & SelectionTypesWithDecorations))
+ continue;
+
+ PRUint8 style;
+ float relativeSize;
+ PRInt32 index =
+ nsTextPaintStyle::GetUnderlineStyleIndexForSelectionType(sd->mType);
+ if (!nsTextPaintStyle::GetSelectionUnderline(aPresContext, index, nsnull,
+ &relativeSize, &style)) {
+ continue;
}
+ nsRect decorationArea;
+ gfxSize size(aPresContext->AppUnitsToGfxUnits(aRect.width),
+ metrics.underlineSize);
+ relativeSize = PR_MAX(relativeSize, 1.0f);
+ size.height *= relativeSize;
+ decorationArea =
+ nsCSSRendering::GetTextDecorationRect(aPresContext, size,
+ ascent, underlineOffset,
+ NS_STYLE_TEXT_DECORATION_UNDERLINE,
+ style);
+ aRect.UnionRect(aRect, decorationArea);
}
DestroySelectionDetails(details);
-
- return retval;
+
+ return !aRect.IsEmpty() && !givenRect.Contains(aRect);
}
//null range means the whole thing
NS_IMETHODIMP
nsTextFrame::SetSelected(nsPresContext* aPresContext,
nsIDOMRange *aRange,
PRBool aSelected,
nsSpread aSpread,
@@ -4816,19 +4900,19 @@ nsTextFrame::SetSelected(nsPresContext*
}
}
if (found) {
// If the selection state is changed in this content, we need to reflow
// to recompute the overflow area for underline of spellchecking or IME if
// their underline is thicker than normal decoration line.
PRBool didHaveSelectionUnderline =
!!(mState & TEXT_SELECTION_UNDERLINE_OVERFLOWED);
- PRBool willHaveSelectionUnderline =
- aSelected && HasSelectionOverflowingDecorations(PresContext());
- if (didHaveSelectionUnderline != willHaveSelectionUnderline) {
+ nsRect r(nsPoint(0, 0), GetSize());
+ if (didHaveSelectionUnderline != aSelected ||
+ (aSelected && CombineSelectionUnderlineRect(PresContext(), r))) {
PresContext()->PresShell()->FrameNeedsReflow(this,
nsIPresShell::eStyleChange,
NS_FRAME_IS_DIRTY);
}
// Selection might change anything. Invalidate the overflow area.
InvalidateOverflowRect();
}
if (aSpread == eSpreadDown)
--- a/layout/generic/test/Makefile.in
+++ b/layout/generic/test/Makefile.in
@@ -65,12 +65,16 @@ include $(topsrcdir)/config/rules.mk
test_bug448860.html \
test_bug460532.html \
test_bug468167.html \
test_bug469613.xul \
test_bug470212.html \
test_character_movement.html \
test_word_movement.html \
test_backspace_delete.xul \
+ test_selection_underline.html \
+ frame_selection_underline.xhtml \
+ frame_selection_underline-ref.xhtml \
+ frame_selection_underline.css \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/frame_selection_underline-ref.xhtml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" class="willBeRemoved">
+<head>
+<link rel="stylesheet" type="text/css" href="frame_selection_underline.css"/>
+<script type="text/javascript" src="decorationline.js"></script>
+</head>
+<body class="reference">
+ <div id="selectionSpellChecker" class="selection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t0" > </span></div><div
+ class="font2"><span id="t1" > </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t2" > </span></div><div
+ class="font2"><span id="t3" > </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t4" > </span></div><div
+ class="font2"><span id="t5" > </span></div></div></div>
+ <div id="selectionIMERawInput" class="selection IMEselection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t6" > </span></div><div
+ class="font2"><span id="t7" > </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t8" > </span></div><div
+ class="font2"><span id="t9" > </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t10"> </span></div><div
+ class="font2"><span id="t11"> </span></div></div></div>
+ <div id="selectionIMESelectedRawText" class="selection IMEselection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t12"> </span></div><div
+ class="font2"><span id="t13"> </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t14"> </span></div><div
+ class="font2"><span id="t15"> </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t16"> </span></div><div
+ class="font2"><span id="t17"> </span></div></div></div>
+ <div id="selectionIMEConvertedText" class="selection IMEselection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t18"> </span></div><div
+ class="font2"><span id="t19"> </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t20"> </span></div><div
+ class="font2"><span id="t21"> </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t22"> </span></div><div
+ class="font2"><span id="t23"> </span></div></div></div>
+ <div id="selectionIMESelectedConvertedText" class="selection IMEselection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t24"> </span></div><div
+ class="font2"><span id="t25"> </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t26"> </span></div><div
+ class="font2"><span id="t27"> </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t28"> </span></div><div
+ class="font2"><span id="t29"> </span></div></div></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/frame_selection_underline.css
@@ -0,0 +1,69 @@
+html, body, div, span {
+ margin: 0;
+ padding: 0;
+ line-height: 1;
+}
+
+div.selection {
+ overflow: hidden;
+ display: block;
+ width: auto;
+ height: 100px;
+ white-space: nowrap;
+}
+
+div.fontsize {
+ display: inline-block;
+ width: auto;
+ height: auto;
+}
+
+div.fontsize.size1 {
+ font-size: 16px;
+}
+
+div.fontsize.size2 {
+ font-size: 32px;
+}
+
+div.fontsize.size3 {
+ font-size: 52px;
+}
+
+@font-face {
+ font-family: "AhemTest";
+ src: url(../../../fonts/Ahem.ttf);
+}
+
+@font-face {
+ font-family: "mplusTest";
+ src: url(../../../fonts/mplus/mplus-1p-regular.ttf);
+}
+
+div.font1,
+div.font2 {
+ display: inline-block;
+ width: 120px;
+ height: 140px;
+ margin: 10px 1px;
+ overflow: hidden;
+}
+
+div.font1 {
+ font-family: "AhemTest";
+}
+
+div.font2 {
+ font-family: "mplusTest";
+}
+
+span {
+ text-align: top;
+}
+
+body.reference div.IMEselection span,
+body.reference div.IMEselection span,
+body.reference div.IMEselection span,
+body.reference div.IMEselection span {
+ background-color: black;
+}
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/frame_selection_underline.xhtml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" class="willBeRemoved">
+<head>
+<link rel="stylesheet" type="text/css" href="frame_selection_underline.css"/>
+<script type="text/javascript" src="decorationline.js"></script>
+<script type="text/javascript">
+<![CDATA[
+
+function onLoad()
+{
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+ var docShell =
+ window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIWebNavigation)
+ .QueryInterface(Components.interfaces.nsIDocShell);
+ var controller =
+ docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsISelectionDisplay)
+ .QueryInterface(Components.interfaces.nsISelectionController);
+
+ const selections = [
+ {
+ id: "selectionSpellChecker",
+ selectionType: controller.SELECTION_SPELLCHECK
+ },
+ {
+ id: "selectionIMERawInput",
+ selectionType: controller.SELECTION_IME_RAWINPUT
+ },
+ {
+ id: "selectionIMESelectedRawText",
+ selectionType: controller.SELECTION_IME_SELECTEDRAWTEXT
+ },
+ {
+ id: "selectionIMEConvertedText",
+ selectionType: controller.SELECTION_IME_CONVERTEDTEXT
+ },
+ {
+ id: "selectionIMESelectedConvertedText",
+ selectionType: controller.SELECTION_IME_SELECTEDCONVERTEDTEXT
+ },
+ ];
+
+ for (var i = 0; i < selections.length; i++) {
+ var sel = controller.getSelection(selections[i].selectionType);
+ var range = document.createRange();
+ range.selectNodeContents(document.getElementById(selections[i].id));
+ sel.addRange(range);
+ }
+
+ document.documentElement.removeAttribute("class");
+}
+
+]]>
+</script>
+</head>
+<body class="test" onload="onLoad();">
+ <div id="selectionSpellChecker" class="selection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t0" > </span></div><div
+ class="font2"><span id="t1" > </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t2" > </span></div><div
+ class="font2"><span id="t3" > </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t4" > </span></div><div
+ class="font2"><span id="t5" > </span></div></div></div>
+ <div id="selectionIMERawInput" class="selection IMEselection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t6" > </span></div><div
+ class="font2"><span id="t7" > </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t8" > </span></div><div
+ class="font2"><span id="t9" > </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t10"> </span></div><div
+ class="font2"><span id="t11"> </span></div></div></div>
+ <div id="selectionIMESelectedRawText" class="selection IMEselection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t12"> </span></div><div
+ class="font2"><span id="t13"> </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t14"> </span></div><div
+ class="font2"><span id="t15"> </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t16"> </span></div><div
+ class="font2"><span id="t17"> </span></div></div></div>
+ <div id="selectionIMEConvertedText" class="selection IMEselection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t18"> </span></div><div
+ class="font2"><span id="t19"> </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t20"> </span></div><div
+ class="font2"><span id="t21"> </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t22"> </span></div><div
+ class="font2"><span id="t23"> </span></div></div></div>
+ <div id="selectionIMESelectedConvertedText" class="selection IMEselection"><div
+ class="fontsize size1"><div
+ class="font1"><span id="t24"> </span></div><div
+ class="font2"><span id="t25"> </span></div></div><div
+ class="fontsize size2"><div
+ class="font1"><span id="t26"> </span></div><div
+ class="font2"><span id="t27"> </span></div></div><div
+ class="fontsize size3"><div
+ class="font1"><span id="t28"> </span></div><div
+ class="font2"><span id="t29"> </span></div></div></div>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/test_selection_underline.html
@@ -0,0 +1,412 @@
+<html>
+
+<head>
+ <title>Test for selection underline</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <script type="text/javascript" src="../../base/tests/decoration_line_rendering.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+// Canvas related code stolen from layout/base/tests/bidi_numeral_test.js which
+// stole from http://developer.mozilla.org/en/docs/Code_snippets:Canvas
+
+const kStyleNames = [ "none", "dotted", "dashed", "solid", "double", "wavy" ];
+
+var RemoteCanvas = function(aURL, aIsReference, aStyle, aRelativeSize) {
+ this.url = aURL;
+ this.id = kStyleNames[aStyle] + aRelativeSize;
+ if (aIsReference)
+ this.id = "ref-" + this.id;
+ this.isReference = aIsReference;
+ this.underlineStyle = aStyle;
+ this.underlineRelativeSize = aRelativeSize;
+ this.snapshot = null;
+};
+
+RemoteCanvas.CANVAS_WIDTH = 820;
+RemoteCanvas.CANVAS_HEIGHT = 500;
+
+RemoteCanvas.prototype.compare = function(otherCanvas, expected) {
+ var ret = compareSnapshots(this.snapshot, otherCanvas.snapshot, expected);
+ this.snapshotDataURL = ret[1];
+ otherCanvas.snapshotDataURL = ret[2];
+ return ret[0];
+}
+
+RemoteCanvas.prototype.load = function(callback) {
+ var iframe = document.createElement("iframe");
+ iframe.id = this.id;
+ iframe.width = RemoteCanvas.CANVAS_WIDTH + "px";
+ iframe.height = RemoteCanvas.CANVAS_HEIGHT + "px";
+ iframe.src = this.url;
+ var me = this;
+ iframe.addEventListener("load", function() {
+ me.remotePageLoaded(callback);
+ }, false);
+ window.document.body.appendChild(iframe);
+};
+
+const kIsMac = navigator.platform.indexOf("Mac") == 0;
+const kIsWin = navigator.platform.indexOf("Win") == 0;
+const kIsLinux = navigator.platform.indexOf("Linux") == 0;
+
+/**
+ * gFontMetrics has predictable font metrics:
+ * 0: font-family: Ahem.ttf; font-size: 16px;
+ * 1: font-family: mplus-1p-regular.ttf; font-size: 16px;
+ * 2: font-family: Ahem.ttf; font-size: 32px;
+ * 3: font-family: mplus-1p-regular.ttf; font-size: 32px;
+ * 4: font-family: Ahem.ttf; font-size: 52px;
+ * 5: font-family: mplus-1p-regular.ttf; font-size: 52px;
+ */
+var gFontMetrics = [];
+if (kIsWin) {
+ gFontMetrics = [
+ { ascent: 13, offset: -2, lineHeight: 1 },
+ { ascent: 17, offset: -2, lineHeight: 1 },
+ { ascent: 26, offset: -4, lineHeight: 1 },
+ { ascent: 34, offset: -4, lineHeight: 2 },
+ { ascent: 42, offset: -7, lineHeight: 1 },
+ { ascent: 56, offset: -7, lineHeight: 3 }
+ ];
+}
+
+/*
+
+if (kIsMac) {
+ // XXX mnakano: I got following metrics on my Mac (both 10.4 and 10.5).
+ // However, on tinderbox machines, they are different values. I'm not sure
+ // the reason.
+ gFontMetrics = [
+ { ascent: 13, offset: -2.127930, lineHeight: 1.000000 },
+ { ascent: 18, offset: -2.000000, lineHeight: 1.000000 },
+ { ascent: 26, offset: -4.255859, lineHeight: 1.000000 },
+ { ascent: 35, offset: -4.000000, lineHeight: 1.600098 },
+ { ascent: 42, offset: -6.915771, lineHeight: 1.040222 },
+ { ascent: 56, offset: -6.500000, lineHeight: 2.600159 }
+ ];
+}
+
+if (kIsLinux) {
+ // XXX mnakano: I got following metrics on my Ubuntu 8.10. However, on
+ // tinderbox machines, they are different. Probably, the values depend on
+ // the version of FreeType and Pango. I bet we cannot test this on Linux
+ // without the way to get the actual font metrics from javascript.
+ gFontMetrics = [
+ { ascent: 13, offset: -1.015625, lineHeight: 1.000000 },
+ { ascent: 18, offset: -1.015625, lineHeight: 1.000000 },
+ { ascent: 26, offset: -2.031250, lineHeight: 1.000000 },
+ { ascent: 35, offset: -2.031250, lineHeight: 1.600003 },
+ { ascent: 42, offset: -3.300781, lineHeight: 1.040001 },
+ { ascent: 56, offset: -3.300781, lineHeight: 2.600002 }
+ ];
+}
+
+*/
+
+const kUnderlineStyles = [
+ { color: "rgb(100%, 0%, 0%)", isIMESelection: false },
+ { color: "rgb( 0%,100%, 0%)", isIMESelection: true },
+ { color: "rgb( 0%, 0%,100%)", isIMESelection: true },
+ { color: "rgb(100%,100%, 0%)", isIMESelection: true },
+ { color: "rgb( 0%,100%,100%)", isIMESelection: true }
+];
+
+function drawSelectionDecorationLines(aDocument, aStyle, aRelativeSize)
+{
+ var index = 0;
+ for (var i = 0; i < kUnderlineStyles.length; i++) {
+ var underlineStyle = kUnderlineStyles[i];
+ for (var j = 0; j < gFontMetrics.length; j++) {
+ var fontMetrics = gFontMetrics[j];
+ var element = aDocument.getElementById("t" + index++);
+ var pt = { x: element.getBoundingClientRect().left,
+ y: element.getBoundingClientRect().top };
+ var width = 120;
+ if (underlineStyle.isIMESelection) {
+ pt.x += 1;
+ width -= 1;
+ }
+ drawDecorationLine(aDocument, underlineStyle.color, pt,
+ { width: width, height: fontMetrics.lineHeight * aRelativeSize },
+ fontMetrics.ascent, fontMetrics.offset, aStyle);
+ }
+ }
+}
+
+RemoteCanvas.prototype.remotePageLoaded = function(callback) {
+ var ldrFrame = document.getElementById(this.id);
+ if (this.isReference) {
+ var doc = ldrFrame.contentDocument;
+ drawSelectionDecorationLines(doc, this.underlineStyle,
+ this.underlineRelativeSize);
+ doc.documentElement.removeAttribute("class");
+ }
+ this.snapshot = snapshotWindow(ldrFrame.contentWindow);
+ callback(this);
+};
+
+var gPrefs = [
+ {
+ name: "ui.SpellCheckerUnderline",
+ type: "char",
+ newValue: "#ff0000"
+ },
+ {
+ name: "ui.IMERawInputBackground",
+ type: "char",
+ newValue: "#ffffff"
+ },
+ {
+ name: "ui.IMERawInputForeground",
+ type: "char",
+ newValue: "#000000"
+ },
+ {
+ name: "ui.IMERawInputUnderline",
+ type: "char",
+ newValue: "#00ff00"
+ },
+ {
+ name: "ui.IMESelectedRawTextBackground",
+ type: "char",
+ newValue: "#ffffff"
+ },
+ {
+ name: "ui.IMESelectedRawTextForeground",
+ type: "char",
+ newValue: "#000000"
+ },
+ {
+ name: "ui.IMESelectedRawTextUnderline",
+ type: "char",
+ newValue: "#0000ff"
+ },
+ {
+ name: "ui.IMEConvertedTextBackground",
+ type: "char",
+ newValue: "#ffffff"
+ },
+ {
+ name: "ui.IMEConvertedTextForeground",
+ type: "char",
+ newValue: "#000000"
+ },
+ {
+ name: "ui.IMEConvertedTextUnderline",
+ type: "char",
+ newValue: "#ffff00"
+ },
+ {
+ name: "ui.IMESelectedConvertedTextBackground",
+ type: "char",
+ newValue: "#ffffff"
+ },
+ {
+ name: "ui.IMESelectedConvertedTextForeground",
+ type: "char",
+ newValue: "#000000"
+ },
+ {
+ name: "ui.IMESelectedConvertedTextUnderline",
+ type: "char",
+ newValue: "#00ffff"
+ },
+ {
+ name: "ui.SpellCheckerUnderlineStyle",
+ type: "int",
+ newValue: 0
+ },
+ {
+ name: "ui.IMERawInputUnderlineStyle",
+ type: "int",
+ newValue: 0
+ },
+ {
+ name: "ui.IMESelectedRawTextUnderlineStyle",
+ type: "int",
+ newValue: 0
+ },
+ {
+ name: "ui.IMEConvertedTextUnderlineStyle",
+ type: "int",
+ newValue: 0
+ },
+ {
+ name: "ui.IMESelectedConvertedTextUnderlineStyle",
+ type: "int",
+ newValue: 0
+ },
+ {
+ name: "ui.SpellCheckerUnderlineRelativeSize",
+ type: "float",
+ newValue: 1.0
+ },
+ {
+ name: "ui.IMEUnderlineRelativeSize",
+ type: "float",
+ newValue: 1.0
+ }
+];
+
+function setPrefValue(aPrefs, aName, aType, aValue)
+{
+ if (aType == "char")
+ aPrefs.setCharPref(aName, aValue);
+ else if (aType == "int")
+ aPrefs.setIntPref(aName, aValue);
+ else if (aType == "float")
+ aPrefs.setIntPref(aName, aValue * 100);
+}
+
+const kPrefStyles = [ 0, 3, 1, 2, 4, 5 ];
+
+var gTests = [
+ { size: 1.0, style: kDecorationStyleNone },
+ { size: 1.0, style: kDecorationStyleSolid },
+ { size: 1.0, style: kDecorationStyleDotted },
+ { size: 1.0, style: kDecorationStyleDashed },
+ { size: 1.0, style: kDecorationStyleDouble },
+ { size: 1.0, style: kDecorationStyleWavy },
+ { size: 2.0, style: kDecorationStyleNone },
+ { size: 2.0, style: kDecorationStyleSolid },
+ { size: 2.0, style: kDecorationStyleDotted },
+ { size: 2.0, style: kDecorationStyleDashed },
+ { size: 2.0, style: kDecorationStyleDouble },
+ { size: 2.0, style: kDecorationStyleWavy }
+];
+
+function run()
+{
+ var test = gTests.shift();
+
+ if (!test) {
+ SimpleTest.finish();
+ cleanup();
+ return;
+ }
+
+ netscape.security.PrivilegeManager.enablePrivilege(
+ 'UniversalPreferencesRead UniversalPreferencesWrite UniversalXPConnect');
+
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+
+ setPrefValue(prefs, "ui.SpellCheckerUnderlineRelativeSize", "float",
+ test.size);
+ setPrefValue(prefs, "ui.IMEUnderlineRelativeSize", "float",
+ test.size);
+ setPrefValue(prefs, "ui.SpellCheckerUnderlineStyle", "int",
+ kPrefStyles[test.style]);
+ setPrefValue(prefs, "ui.IMERawInputUnderlineStyle", "int",
+ kPrefStyles[test.style]);
+ setPrefValue(prefs, "ui.IMESelectedRawTextUnderlineStyle", "int",
+ kPrefStyles[test.style]);
+ setPrefValue(prefs, "ui.IMEConvertedTextUnderlineStyle", "int",
+ kPrefStyles[test.style]);
+ setPrefValue(prefs, "ui.IMESelectedConvertedTextUnderlineStyle", "int",
+ kPrefStyles[test.style]);
+
+ doTest(test.style, test.size);
+}
+
+function doTest(aStyle, aSize)
+{
+
+ var canvases = [];
+ function callbackTestCanvas(canvas)
+ {
+ canvases.push(canvas);
+
+ if (canvases.length != 2)
+ return;
+
+ var result = !canvases[0].isReference ? canvases[0] : canvases[1];
+ var reference = canvases[0].isReference ? canvases[0] : canvases[1];
+
+ // when both canvases are loaded
+ ok(result.compare(reference, true),
+ "Rendering of reftest (style: " + kStyleNames[aStyle] +
+ ", size: " + aSize + ") is different\n" +
+ "RESULT=" + result.snapshotDataURL + "\n" +
+ "REFERENCE=" + reference.snapshotDataURL + "\n");
+
+ var iframe = window.document.getElementById(canvases[0].id);
+ iframe.parentNode.removeChild(iframe);
+ iframe = window.document.getElementById(canvases[1].id);
+ iframe.parentNode.removeChild(iframe);
+
+ canvases = [];
+
+ setTimeout(run, 0);
+ }
+
+ var testCanvas = new RemoteCanvas("frame_selection_underline.xhtml",
+ false, aStyle, aSize);
+ testCanvas.load(callbackTestCanvas);
+
+ var refFile = "frame_selection_underline-ref.xhtml";
+ var refCanvas = new RemoteCanvas(refFile, true, aStyle, aSize);
+ refCanvas.load(callbackTestCanvas);
+}
+
+function onLoad()
+{
+ SimpleTest.waitForExplicitFinish();
+
+ if (gFontMetrics.length == 0) {
+ todo(false, "test_selection_underline doesn't support this platform");
+ SimpleTest.finish();
+ return;
+ }
+
+ netscape.security.PrivilegeManager.enablePrivilege(
+ 'UniversalPreferencesRead UniversalPreferencesWrite UniversalXPConnect');
+
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+
+ for (var i = 0; i < gPrefs.length; i++) {
+ gPrefs[i].wasUserSetValue = prefs.prefHasUserValue(gPrefs[i].name);
+ if (gPrefs[i].wasUserSetValue) {
+ if (gPrefs[i].type == "char")
+ gPrefs[i].oldValue = prefs.getCharPref(gPrefs[i].name);
+ else if (gPrefs[i].type == "int")
+ gPrefs[i].oldValue = prefs.getIntPref(gPrefs[i].name);
+ else if (gPrefs[i].type == "float")
+ gPrefs[i].oldValue = prefs.getIntPref(gPrefs[i].name) / 100;
+ }
+ setPrefValue(prefs, gPrefs[i].name, gPrefs[i].type, gPrefs[i].newValue);
+ }
+
+ run();
+}
+
+function cleanup()
+{
+ netscape.security.PrivilegeManager.enablePrivilege(
+ 'UniversalPreferencesRead UniversalPreferencesWrite UniversalXPConnect');
+
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+
+ for (var i = 0; i < gPrefs.length; i++) {
+ prefs.clearUserPref(gPrefs[i].name);
+ if (gPrefs[i].wasUserSetValue)
+ setPrefValue(prefs, gPrefs[i].name, gPrefs[i].type, gPrefs[i].oldValue);
+ }
+}
+
+</script>
+
+</head>
+<body onload="onLoad();">
+
+<pre id="test">
+</pre>
+
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/reftests/fonts/Makefile.in
@@ -0,0 +1,50 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of 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
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = Ahem.ttf \
+ $(NULL)
+
+libs:: $(_TEST_FILES)
+ $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/fonts
new file mode 100644
--- /dev/null
+++ b/layout/reftests/fonts/mplus/Makefile.in
@@ -0,0 +1,50 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of 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
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES = mplus-1p-regular.ttf \
+ $(NULL)
+
+libs:: $(_TEST_FILES)
+ $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/fonts/mplus
--- a/layout/xul/base/src/nsTextBoxFrame.cpp
+++ b/layout/xul/base/src/nsTextBoxFrame.cpp
@@ -466,27 +466,27 @@ nsTextBoxFrame::DrawText(nsIRenderingCon
// general case -- see below.)
if (decorations & (NS_FONT_DECORATION_OVERLINE |
NS_FONT_DECORATION_UNDERLINE)) {
fontMet->GetUnderline(offset, size);
gfxFloat offsetPixel = presContext->AppUnitsToGfxUnits(offset);
gfxFloat sizePixel = presContext->AppUnitsToGfxUnits(size);
if (decorations & NS_FONT_DECORATION_UNDERLINE) {
nsCSSRendering::PaintDecorationLine(ctx, underColor,
- pt, gfxSize(width, sizePixel),
- ascentPixel, offsetPixel,
- NS_STYLE_TEXT_DECORATION_UNDERLINE,
- NS_STYLE_BORDER_STYLE_SOLID);
+ pt, gfxSize(width, sizePixel),
+ ascentPixel, offsetPixel,
+ NS_STYLE_TEXT_DECORATION_UNDERLINE,
+ nsCSSRendering::DECORATION_STYLE_SOLID);
}
if (decorations & NS_FONT_DECORATION_OVERLINE) {
nsCSSRendering::PaintDecorationLine(ctx, overColor,
- pt, gfxSize(width, sizePixel),
- ascentPixel, ascentPixel,
- NS_STYLE_TEXT_DECORATION_OVERLINE,
- NS_STYLE_BORDER_STYLE_SOLID);
+ pt, gfxSize(width, sizePixel),
+ ascentPixel, ascentPixel,
+ NS_STYLE_TEXT_DECORATION_OVERLINE,
+ nsCSSRendering::DECORATION_STYLE_SOLID);
}
}
aRenderingContext.SetFont(fontMet);
CalculateUnderline(aRenderingContext);
aRenderingContext.SetColor(aOverrideColor ? *aOverrideColor : GetStyleColor()->mColor);
@@ -550,20 +550,19 @@ nsTextBoxFrame::DrawText(nsIRenderingCon
// Strikeout is drawn on top of the text, per
// http://www.w3.org/TR/CSS21/zindex.html point 7.2.1.4.1.1.
if (decorations & NS_FONT_DECORATION_LINE_THROUGH) {
fontMet->GetStrikeout(offset, size);
gfxFloat offsetPixel = presContext->AppUnitsToGfxUnits(offset);
gfxFloat sizePixel = presContext->AppUnitsToGfxUnits(size);
nsCSSRendering::PaintDecorationLine(ctx, strikeColor,
- pt, gfxSize(width, sizePixel),
- ascentPixel, offsetPixel,
- NS_STYLE_TEXT_DECORATION_LINE_THROUGH,
- NS_STYLE_BORDER_STYLE_SOLID);
+ pt, gfxSize(width, sizePixel), ascentPixel, offsetPixel,
+ NS_STYLE_TEXT_DECORATION_LINE_THROUGH,
+ nsCSSRendering::DECORATION_STYLE_SOLID);
}
}
void nsTextBoxFrame::PaintOneShadow(gfxContext* aCtx,
const nsRect& aTextRect,
nsCSSShadowItem* aShadowDetails,
const nscolor& aForegroundColor,
const nsRect& aDirtyRect) {
--- a/widget/public/nsILookAndFeel.h
+++ b/widget/public/nsILookAndFeel.h
@@ -39,21 +39,20 @@
#define __nsILookAndFeel
#include "nsISupports.h"
#include "nsColor.h"
// for |#ifdef NS_DEBUG|
struct nsSize;
-// {6672E0EA-C936-11DC-9BB7-0014850B592F}
+// {EE288A5F-B98B-4105-B4AE-884F21588A92}
#define NS_ILOOKANDFEEL_IID \
-{ 0x6672e0ea, 0xc936, 0x11dc, \
- { 0x9b, 0xb7, 0x00, 0x14, 0x85, 0x0b, 0x59, 0x2f} }
-
+{ 0xee288a5f, 0xb98b, 0x4105, \
+ { 0xb4, 0xae, 0x88, 0x4f, 0x21, 0x58, 0x8a, 0x92 } }
class nsILookAndFeel: public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ILOOKANDFEEL_IID)
// When modifying this list, also modify nsXPLookAndFeel::sColorPrefs
// in widget/src/xpwidgts/nsXPLookAndFeel.cpp.
typedef enum {
@@ -86,16 +85,18 @@ public:
eColor_IMESelectedRawTextUnderline,
eColor_IMEConvertedTextBackground,
eColor_IMEConvertedTextForeground,
eColor_IMEConvertedTextUnderline,
eColor_IMESelectedConvertedTextBackground,
eColor_IMESelectedConvertedTextForeground,
eColor_IMESelectedConvertedTextUnderline,
+ eColor_SpellCheckerUnderline,
+
// New CSS 2 color definitions
eColor_activeborder,
eColor_activecaption,
eColor_appworkspace,
eColor_background,
eColor_buttonface,
eColor_buttonhighlight,
eColor_buttonshadow,
@@ -290,23 +291,24 @@ public:
* If true, clicking on a scrollbar (not as in dragging the thumb) defaults
* to scrolling the view corresponding to the clicked point. Otherwise, we
* only do so if the scrollbar is clicked using the middle mouse button or
* if shift is pressed when the scrollbar is clicked.
*/
eMetric_ScrollToClick,
/**
- * IME underline styles, the values should be NS_DECORATION_LINE_STYLE_*.
- * They are defined below.
+ * IME and spell checker underline styles, the values should be
+ * NS_DECORATION_LINE_STYLE_*. They are defined below.
*/
eMetric_IMERawInputUnderlineStyle,
eMetric_IMESelectedRawTextUnderlineStyle,
eMetric_IMEConvertedTextUnderlineStyle,
eMetric_IMESelectedConvertedTextUnderline,
+ eMetric_SpellCheckerUnderlineStyle,
/**
* If this metric != 0, show icons in menus.
*/
eMetric_ImagesInMenus
} nsMetricID;
enum {
@@ -336,16 +338,17 @@ public:
eMetricFloat_TextFieldHorizontalInsidePadding,
eMetricFloat_TextAreaVerticalInsidePadding,
eMetricFloat_TextAreaHorizontalInsidePadding,
eMetricFloat_ListVerticalInsidePadding,
eMetricFloat_ListHorizontalInsidePadding,
eMetricFloat_ButtonVerticalInsidePadding,
eMetricFloat_ButtonHorizontalInsidePadding,
eMetricFloat_IMEUnderlineRelativeSize,
+ eMetricFloat_SpellCheckerUnderlineRelativeSize,
// The width/height ratio of the cursor. If used, the CaretWidth int metric
// should be added to the calculated caret width.
eMetricFloat_CaretAspectRatio
} nsMetricFloatID;
NS_IMETHOD GetColor(const nsColorID aID, nscolor &aColor) = 0;
NS_IMETHOD GetMetric(const nsMetricID aID, PRInt32 & aMetric) = 0;
@@ -389,42 +392,43 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsILookAnd
// On the Mac, GetColor(eColor_TextSelectForeground, color) returns this
// constant to specify that the foreground color should not be changed
// (ie. a colored text keeps its colors when selected).
// Of course if other plaforms work like the Mac, they can use it too.
#define NS_DONT_CHANGE_COLOR NS_RGB(0x01, 0x01, 0x01)
-// --------------------------------
-// Special colors for eColor_IME*
-// --------------------------------
+// -----------------------------------------------------------------
+// Special colors for eColor_IME* and eColor_SpellCheckerUnderline
+// -----------------------------------------------------------------
// For background color only.
#define NS_TRANSPARENT NS_RGBA(0x01, 0x00, 0x00, 0x00)
// For foreground color only.
#define NS_SAME_AS_FOREGROUND_COLOR NS_RGBA(0x02, 0x00, 0x00, 0x00)
#define NS_40PERCENT_FOREGROUND_COLOR NS_RGBA(0x03, 0x00, 0x00, 0x00)
-#define NS_IS_IME_SPECIAL_COLOR(c) ((c) == NS_TRANSPARENT || \
- (c) == NS_SAME_AS_FOREGROUND_COLOR || \
- (c) == NS_40PERCENT_FOREGROUND_COLOR)
+#define NS_IS_SELECTION_SPECIAL_COLOR(c) ((c) == NS_TRANSPARENT || \
+ (c) == NS_SAME_AS_FOREGROUND_COLOR || \
+ (c) == NS_40PERCENT_FOREGROUND_COLOR)
// -------------------------------------------------
// Underline styles for eMetric_IME*UnderlineStyle
// -------------------------------------------------
#define NS_UNDERLINE_STYLE_NONE 0
#define NS_UNDERLINE_STYLE_DOTTED 1
#define NS_UNDERLINE_STYLE_DASHED 2
#define NS_UNDERLINE_STYLE_SOLID 3
#define NS_UNDERLINE_STYLE_DOUBLE 4
+#define NS_UNDERLINE_STYLE_WAVY 5
#define NS_IS_VALID_UNDERLINE_STYLE(s) \
- (NS_UNDERLINE_STYLE_NONE <= (s) && (s) <= NS_UNDERLINE_STYLE_DOUBLE)
+ (NS_UNDERLINE_STYLE_NONE <= (s) && (s) <= NS_UNDERLINE_STYLE_WAVY)
// ------------------------------------------
// Bits for eMetric_AlertNotificationOrigin
// ------------------------------------------
#define NS_ALERT_HORIZONTAL 1
#define NS_ALERT_LEFT 2
#define NS_ALERT_TOP 4
--- a/widget/src/beos/nsLookAndFeel.cpp
+++ b/widget/src/beos/nsLookAndFeel.cpp
@@ -125,16 +125,19 @@ nsresult nsLookAndFeel::NativeGetColor(c
case eColor_IMERawInputUnderline:
case eColor_IMEConvertedTextUnderline:
aColor = NS_SAME_AS_FOREGROUND_COLOR;
break;
case eColor_IMESelectedRawTextUnderline:
case eColor_IMESelectedConvertedTextUnderline:
aColor = NS_TRANSPARENT;
break;
+ case eColor_SpellCheckerUnderline:
+ aColor = NS_RGB(0xff, 0, 0);
+ break;
// two following colors get initialisation in XPLookAndFeel.
//eColor_TextSelectBackgroundDisabled,
//eColor_TextSelectBackgroundAttention,
// CSS 2 Colors
case eColor_activeborder:
aColor = NS_RGB(0x88, 0x88, 0x88);
break;
@@ -436,16 +439,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
case eMetric_IMERawInputUnderlineStyle:
case eMetric_IMEConvertedTextUnderlineStyle:
aMetric = NS_UNDERLINE_STYLE_SOLID;
break;
case eMetric_IMESelectedRawTextUnderlineStyle:
case eMetric_IMESelectedConvertedTextUnderline:
aMetric = NS_UNDERLINE_STYLE_NONE;
break;
+ case eMetric_SpellCheckerUnderlineStyle:
+ aMetric = NS_UNDERLINE_STYLE_WAVY;
+ break;
default:
aMetric = 0;
res = NS_ERROR_FAILURE;
}
return res;
}
NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricFloatID aID, float & aMetric)
@@ -478,14 +484,17 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
aMetric = 0.25f;
break;
case eMetricFloat_ButtonHorizontalInsidePadding:
aMetric = 0.25f;
break;
case eMetricFloat_IMEUnderlineRelativeSize:
aMetric = 1.0f;
break;
+ case eMetricFloat_SpellCheckerUnderlineRelativeSize:
+ aMetric = 1.0f;
+ break;
default:
aMetric = -1.0;
res = NS_ERROR_FAILURE;
}
return res;
}
--- a/widget/src/cocoa/nsLookAndFeel.mm
+++ b/widget/src/cocoa/nsLookAndFeel.mm
@@ -150,17 +150,20 @@ nsresult nsLookAndFeel::NativeGetColor(c
case eColor_IMERawInputUnderline:
case eColor_IMEConvertedTextUnderline:
aColor = NS_40PERCENT_FOREGROUND_COLOR;
break;
case eColor_IMESelectedRawTextUnderline:
case eColor_IMESelectedConvertedTextUnderline:
aColor = NS_SAME_AS_FOREGROUND_COLOR;
break;
-
+ case eColor_SpellCheckerUnderline:
+ aColor = NS_RGB(0xff, 0, 0);
+ break;
+
//
// css2 system colors http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
//
// It's really hard to effectively map these to the Appearance Manager properly,
// since they are modeled word for word after the win32 system colors and don't have any
// real counterparts in the Mac world. I'm sure we'll be tweaking these for
// years to come.
//
@@ -665,16 +668,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
}
break;
case eMetric_IMERawInputUnderlineStyle:
case eMetric_IMEConvertedTextUnderlineStyle:
case eMetric_IMESelectedRawTextUnderlineStyle:
case eMetric_IMESelectedConvertedTextUnderline:
aMetric = NS_UNDERLINE_STYLE_SOLID;
break;
+ case eMetric_SpellCheckerUnderlineStyle:
+ aMetric = NS_UNDERLINE_STYLE_DOTTED;
+ break;
default:
aMetric = 0;
res = NS_ERROR_FAILURE;
}
return res;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
@@ -709,15 +715,18 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
aMetric = 0.5f;
break;
case eMetricFloat_ButtonHorizontalInsidePadding:
aMetric = 0.5f;
break;
case eMetricFloat_IMEUnderlineRelativeSize:
aMetric = 2.0f;
break;
+ case eMetricFloat_SpellCheckerUnderlineRelativeSize:
+ aMetric = 2.0f;
+ break;
default:
aMetric = -1.0;
res = NS_ERROR_FAILURE;
}
return res;
}
--- a/widget/src/gtk2/nsLookAndFeel.cpp
+++ b/widget/src/gtk2/nsLookAndFeel.cpp
@@ -148,16 +148,19 @@ nsresult nsLookAndFeel::NativeGetColor(c
case eColor_IMERawInputUnderline:
case eColor_IMEConvertedTextUnderline:
aColor = NS_SAME_AS_FOREGROUND_COLOR;
break;
case eColor_IMESelectedRawTextUnderline:
case eColor_IMESelectedConvertedTextUnderline:
aColor = NS_TRANSPARENT;
break;
+ case eColor_SpellCheckerUnderline:
+ aColor = NS_RGB(0xff, 0, 0);
+ break;
// css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
case eColor_activeborder:
// active window border
aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
break;
case eColor_activecaption:
// active window caption background
@@ -573,16 +576,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
case eMetric_IMERawInputUnderlineStyle:
case eMetric_IMEConvertedTextUnderlineStyle:
aMetric = NS_UNDERLINE_STYLE_SOLID;
break;
case eMetric_IMESelectedRawTextUnderlineStyle:
case eMetric_IMESelectedConvertedTextUnderline:
aMetric = NS_UNDERLINE_STYLE_NONE;
break;
+ case eMetric_SpellCheckerUnderlineStyle:
+ aMetric = NS_UNDERLINE_STYLE_WAVY;
+ break;
case eMetric_ImagesInMenus:
aMetric = moz_gtk_images_in_menus();
break;
default:
aMetric = 0;
res = NS_ERROR_FAILURE;
}
@@ -621,16 +627,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
aMetric = 0.25f;
break;
case eMetricFloat_ButtonHorizontalInsidePadding:
aMetric = 0.25f;
break;
case eMetricFloat_IMEUnderlineRelativeSize:
aMetric = 1.0f;
break;
+ case eMetricFloat_SpellCheckerUnderlineRelativeSize:
+ aMetric = 1.0f;
+ break;
case eMetricFloat_CaretAspectRatio:
aMetric = sCaretRatio;
break;
default:
aMetric = -1.0;
res = NS_ERROR_FAILURE;
}
return res;
--- a/widget/src/os2/nsLookAndFeel.cpp
+++ b/widget/src/os2/nsLookAndFeel.cpp
@@ -109,16 +109,19 @@ nsresult nsLookAndFeel::NativeGetColor(c
case eColor_IMERawInputUnderline:
case eColor_IMEConvertedTextUnderline:
aColor = NS_SAME_AS_FOREGROUND_COLOR;
return NS_OK;
case eColor_IMESelectedRawTextUnderline:
case eColor_IMESelectedConvertedTextUnderline:
aColor = NS_TRANSPARENT;
return NS_OK;
+ case eColor_SpellCheckerUnderline:
+ aColor = NS_RGB(0xff, 0, 0);
+ return NS_OK;
// New CSS 2 Color definitions
case eColor_activeborder:
idx = SYSCLR_ACTIVEBORDER;
break;
case eColor_activecaption:
idx = SYSCLR_ACTIVETITLETEXT;
break;
@@ -384,16 +387,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
case eMetric_IMERawInputUnderlineStyle:
case eMetric_IMEConvertedTextUnderlineStyle:
aMetric = NS_UNDERLINE_STYLE_SOLID;
break;
case eMetric_IMESelectedRawTextUnderlineStyle:
case eMetric_IMESelectedConvertedTextUnderline:
aMetric = NS_UNDERLINE_STYLE_NONE;
break;
+ case eMetric_SpellCheckerUnderlineStyle:
+ aMetric = NS_UNDERLINE_STYLE_WAVY;
+ break;
default:
aMetric = 0;
res = NS_ERROR_FAILURE;
}
return res;
}
@@ -427,16 +433,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
aMetric = 0.25f;
break;
case eMetricFloat_ButtonHorizontalInsidePadding:
aMetric = 0.25f;
break;
case eMetricFloat_IMEUnderlineRelativeSize:
aMetric = 1.0f;
break;
+ case eMetricFloat_SpellCheckerUnderlineRelativeSize:
+ aMetric = 1.0f;
+ break;
default:
aMetric = -1.0;
res = NS_ERROR_FAILURE;
}
return res;
}
--- a/widget/src/photon/nsLookAndFeel.cpp
+++ b/widget/src/photon/nsLookAndFeel.cpp
@@ -114,16 +114,19 @@ nsresult nsLookAndFeel::NativeGetColor(c
case eColor_IMERawInputUnderline:
case eColor_IMEConvertedTextUnderline:
aColor = NS_SAME_AS_FOREGROUND_COLOR;
break;
case eColor_IMESelectedRawTextUnderline:
case eColor_IMESelectedConvertedTextUnderline:
aColor = NS_TRANSPARENT;
break;
+ case eColor_SpellCheckerUnderline:
+ aColor = NS_RGB(0xff, 0, 0);
+ break;
// css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
case eColor_activeborder:
aColor = PH_TO_NS_RGB(Pg_BLACK);
break;
case eColor_activecaption:
aColor = PH_TO_NS_RGB(Pg_YELLOW);
break;
@@ -376,16 +379,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
case eMetric_IMERawInputUnderlineStyle:
case eMetric_IMEConvertedTextUnderlineStyle:
aMetric = NS_UNDERLINE_STYLE_SOLID;
break;
case eMetric_IMESelectedRawTextUnderlineStyle:
case eMetric_IMESelectedConvertedTextUnderline:
aMetric = NS_UNDERLINE_STYLE_NONE;
break;
+ case eMetric_SpellCheckerUnderlineStyle:
+ aMetric = NS_UNDERLINE_STYLE_WAVY;
+ break;
default:
aMetric = 0;
res = NS_ERROR_FAILURE;
}
return res;
}
@@ -422,15 +428,18 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
aMetric = 0.25f;
break;
case eMetricFloat_ButtonHorizontalInsidePadding:
aMetric = 0.25f;
break;
case eMetricFloat_IMEUnderlineRelativeSize:
aMetric = 1.0f;
break;
+ case eMetricFloat_SpellCheckerUnderlineRelativeSize:
+ aMetric = 1.0f;
+ break;
default:
aMetric = -1.0;
res = NS_ERROR_FAILURE;
}
return res;
}
--- a/widget/src/qt/nsLookAndFeel.cpp
+++ b/widget/src/qt/nsLookAndFeel.cpp
@@ -137,16 +137,20 @@ nsresult nsLookAndFeel::NativeGetColor(c
aColor = NS_SAME_AS_FOREGROUND_COLOR;
break;
case eColor_IMESelectedRawTextUnderline:
case eColor_IMESelectedConvertedTextUnderline:
aColor = NS_TRANSPARENT;
break;
+ case eColor_SpellCheckerUnderline:
+ aColor = NS_RGB(0xff, 0, 0);
+ break;
+
case eColor_activeborder:
aColor = QCOLOR_TO_NS_RGB(palette.color(QPalette::Normal, QPalette::Window));
break;
case eColor_activecaption:
aColor = QCOLOR_TO_NS_RGB(palette.color(QPalette::Normal, QPalette::Window));
break;
@@ -476,16 +480,20 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
aMetric = eMetric_ScrollThumbStyleProportional;
break;
case eMetric_WindowsDefaultTheme:
aMetric = 0;
res = NS_ERROR_NOT_IMPLEMENTED;
break;
+ case eMetric_SpellCheckerUnderlineStyle:
+ aMetric = NS_UNDERLINE_STYLE_WAVY;
+ break;
+
default:
aMetric = 0;
res = NS_ERROR_FAILURE;
}
return res;
}
#ifdef NS_LOOKANDFEEL_DEBUG
@@ -546,15 +554,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
case eMetricFloat_ButtonHorizontalInsidePadding:
aMetric = 0.25f;
break;
case eMetricFloat_IMEUnderlineRelativeSize:
aMetric = 1.0f;
break;
+ case eMetricFloat_SpellCheckerUnderlineRelativeSize:
+ aMetric = 1.0f;
+ break;
+
default:
aMetric = -1.0;
res = NS_ERROR_FAILURE;
break;
}
return res;
}
--- a/widget/src/windows/nsLookAndFeel.cpp
+++ b/widget/src/windows/nsLookAndFeel.cpp
@@ -157,16 +157,19 @@ nsresult nsLookAndFeel::NativeGetColor(c
case eColor_IMERawInputUnderline:
case eColor_IMEConvertedTextUnderline:
aColor = NS_SAME_AS_FOREGROUND_COLOR;
return NS_OK;
case eColor_IMESelectedRawTextUnderline:
case eColor_IMESelectedConvertedTextUnderline:
aColor = NS_TRANSPARENT;
return NS_OK;
+ case eColor_SpellCheckerUnderline:
+ aColor = NS_RGB(0xff, 0, 0);
+ return NS_OK;
// New CSS 2 Color definitions
case eColor_activeborder:
idx = COLOR_ACTIVEBORDER;
break;
case eColor_activecaption:
idx = COLOR_ACTIVECAPTION;
break;
@@ -594,16 +597,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
case eMetric_IMERawInputUnderlineStyle:
case eMetric_IMEConvertedTextUnderlineStyle:
aMetric = NS_UNDERLINE_STYLE_DASHED;
break;
case eMetric_IMESelectedRawTextUnderlineStyle:
case eMetric_IMESelectedConvertedTextUnderline:
aMetric = NS_UNDERLINE_STYLE_NONE;
break;
+ case eMetric_SpellCheckerUnderlineStyle:
+ aMetric = NS_UNDERLINE_STYLE_WAVY;
+ break;
default:
aMetric = 0;
res = NS_ERROR_FAILURE;
}
return res;
}
NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricFloatID aID, float & aMetric)
@@ -636,16 +642,19 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(c
aMetric = 0.25f;
break;
case eMetricFloat_ButtonHorizontalInsidePadding:
aMetric = 0.25f;
break;
case eMetricFloat_IMEUnderlineRelativeSize:
aMetric = 1.0f;
break;
+ case eMetricFloat_SpellCheckerUnderlineRelativeSize:
+ aMetric = 1.0f;
+ break;
default:
aMetric = -1.0;
res = NS_ERROR_FAILURE;
}
return res;
}
/* virtual */
--- a/widget/src/xpwidgets/nsXPLookAndFeel.cpp
+++ b/widget/src/xpwidgets/nsXPLookAndFeel.cpp
@@ -116,16 +116,18 @@ nsLookAndFeelIntPref nsXPLookAndFeel::sI
{ "ui.IMERawInputUnderlineStyle",
eMetric_IMERawInputUnderlineStyle, PR_FALSE, nsLookAndFeelTypeInt, 0 },
{ "ui.IMESelectedRawTextUnderlineStyle",
eMetric_IMESelectedRawTextUnderlineStyle, PR_FALSE, nsLookAndFeelTypeInt, 0 },
{ "ui.IMEConvertedTextUnderlineStyle",
eMetric_IMEConvertedTextUnderlineStyle, PR_FALSE, nsLookAndFeelTypeInt, 0 },
{ "ui.IMESelectedConvertedTextUnderlineStyle",
eMetric_IMESelectedConvertedTextUnderline, PR_FALSE, nsLookAndFeelTypeInt, 0 },
+ { "ui.SpellCheckerUnderlineStyle",
+ eMetric_SpellCheckerUnderlineStyle, PR_FALSE, nsLookAndFeelTypeInt, 0 },
};
nsLookAndFeelFloatPref nsXPLookAndFeel::sFloatPrefs[] =
{
{ "ui.textFieldVerticalInsidePadding",
eMetricFloat_TextFieldVerticalInsidePadding, PR_FALSE, nsLookAndFeelTypeFloat, 0 },
{ "ui.textFieldHorizontalInsidePadding",
eMetricFloat_TextFieldHorizontalInsidePadding, PR_FALSE, nsLookAndFeelTypeFloat, 0 },
@@ -138,16 +140,19 @@ nsLookAndFeelFloatPref nsXPLookAndFeel::
{ "ui.listHorizontalInsidePadding",
eMetricFloat_ListHorizontalInsidePadding, PR_FALSE, nsLookAndFeelTypeFloat, 0 },
{ "ui.buttonVerticalInsidePadding", eMetricFloat_ButtonVerticalInsidePadding,
PR_FALSE, nsLookAndFeelTypeFloat, 0 },
{ "ui.buttonHorizontalInsidePadding", eMetricFloat_ButtonHorizontalInsidePadding,
PR_FALSE, nsLookAndFeelTypeFloat, 0 },
{ "ui.IMEUnderlineRelativeSize", eMetricFloat_IMEUnderlineRelativeSize,
PR_FALSE, nsLookAndFeelTypeFloat, 0 },
+ { "ui.SpellCheckerUnderlineRelativeSize",
+ eMetricFloat_SpellCheckerUnderlineRelativeSize, PR_FALSE,
+ nsLookAndFeelTypeFloat, 0 },
{ "ui.caretAspectRatio", eMetricFloat_CaretAspectRatio, PR_FALSE,
nsLookAndFeelTypeFloat, 0 },
};
// This array MUST be kept in the same order as the color list in nsILookAndFeel.h.
/* XXX If you add any strings longer than
* "ui.IMESelectedConvertedTextBackground"
@@ -179,16 +184,17 @@ const char nsXPLookAndFeel::sColorPrefs[
"ui.IMESelectedRawTextForeground",
"ui.IMESelectedRawTextUnderline",
"ui.IMEConvertedTextBackground",
"ui.IMEConvertedTextForeground",
"ui.IMEConvertedTextUnderline",
"ui.IMESelectedConvertedTextBackground",
"ui.IMESelectedConvertedTextForeground",
"ui.IMESelectedConvertedTextUnderline",
+ "ui.SpellCheckerUnderline",
"ui.activeborder",
"ui.activecaption",
"ui.appworkspace",
"ui.background",
"ui.buttonface",
"ui.buttonhighlight",
"ui.buttonshadow",
"ui.buttontext",
@@ -480,17 +486,18 @@ nsXPLookAndFeel::IsSpecialColor(const ns
case eColor_IMESelectedRawTextForeground:
case eColor_IMESelectedConvertedTextForeground:
case eColor_IMERawInputForeground:
case eColor_IMEConvertedTextForeground:
case eColor_IMERawInputUnderline:
case eColor_IMEConvertedTextUnderline:
case eColor_IMESelectedRawTextUnderline:
case eColor_IMESelectedConvertedTextUnderline:
- return NS_IS_IME_SPECIAL_COLOR(aColor);
+ case eColor_SpellCheckerUnderline:
+ return NS_IS_SELECTION_SPECIAL_COLOR(aColor);
default:
/*
* In GetColor(), every color that is not a special color is color
* corrected. Use PR_FALSE to make other colors color corrected.
*/
return PR_FALSE;
}
return PR_FALSE;