mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-14 04:03:47 +00:00
Bug 1074735 pt 2 - Support drawing CSS text decorations (underline, overline, strikeout) on vertical text frames. r=smontagu
This commit is contained in:
parent
5194872bdc
commit
45724811c5
@ -3817,11 +3817,13 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext,
|
||||
// End table border-collapsing section
|
||||
|
||||
gfxRect
|
||||
nsCSSRendering::ExpandPaintingRectForDecorationLine(nsIFrame* aFrame,
|
||||
const uint8_t aStyle,
|
||||
const gfxRect& aClippedRect,
|
||||
const gfxFloat aXInFrame,
|
||||
const gfxFloat aCycleLength)
|
||||
nsCSSRendering::ExpandPaintingRectForDecorationLine(
|
||||
nsIFrame* aFrame,
|
||||
const uint8_t aStyle,
|
||||
const gfxRect& aClippedRect,
|
||||
const gfxFloat aICoordInFrame,
|
||||
const gfxFloat aCycleLength,
|
||||
bool aVertical)
|
||||
{
|
||||
switch (aStyle) {
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
|
||||
@ -3836,25 +3838,32 @@ nsCSSRendering::ExpandPaintingRectForDecorationLine(nsIFrame* aFrame,
|
||||
nsBlockFrame* block = nullptr;
|
||||
// Note that when we paint the decoration lines in relative positioned
|
||||
// box, we should paint them like all of the boxes are positioned as static.
|
||||
nscoord frameXInBlockAppUnits = 0;
|
||||
nscoord framePosInBlockAppUnits = 0;
|
||||
for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
|
||||
block = do_QueryFrame(f);
|
||||
if (block) {
|
||||
break;
|
||||
}
|
||||
frameXInBlockAppUnits += f->GetNormalPosition().x;
|
||||
framePosInBlockAppUnits += aVertical ?
|
||||
f->GetNormalPosition().y : f->GetNormalPosition().x;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(block, aClippedRect);
|
||||
|
||||
nsPresContext *pc = aFrame->PresContext();
|
||||
gfxFloat frameXInBlock = pc->AppUnitsToGfxUnits(frameXInBlockAppUnits);
|
||||
int32_t rectXInBlock = int32_t(NS_round(frameXInBlock + aXInFrame));
|
||||
int32_t extraLeft =
|
||||
rectXInBlock - (rectXInBlock / int32_t(aCycleLength) * aCycleLength);
|
||||
gfxFloat framePosInBlock = pc->AppUnitsToGfxUnits(framePosInBlockAppUnits);
|
||||
int32_t rectPosInBlock =
|
||||
int32_t(NS_round(framePosInBlock + aICoordInFrame));
|
||||
int32_t extraStartEdge =
|
||||
rectPosInBlock - (rectPosInBlock / int32_t(aCycleLength) * aCycleLength);
|
||||
gfxRect rect(aClippedRect);
|
||||
rect.x -= extraLeft;
|
||||
rect.width += extraLeft;
|
||||
if (aVertical) {
|
||||
rect.y -= extraStartEdge;
|
||||
rect.height += extraStartEdge;
|
||||
} else {
|
||||
rect.x -= extraStartEdge;
|
||||
rect.width += extraStartEdge;
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
@ -3864,19 +3873,21 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
const gfxRect& aDirtyRect,
|
||||
const nscolor aColor,
|
||||
const gfxPoint& aPt,
|
||||
const gfxFloat aXInFrame,
|
||||
const gfxFloat aICoordInFrame,
|
||||
const gfxSize& aLineSize,
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const uint8_t aDecoration,
|
||||
const uint8_t aStyle,
|
||||
bool aVertical,
|
||||
const gfxFloat aDescentLimit)
|
||||
{
|
||||
NS_ASSERTION(aStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE, "aStyle is none");
|
||||
|
||||
gfxRect rect =
|
||||
GetTextDecorationRectInternal(aPt, aLineSize, aAscent, aOffset,
|
||||
aDecoration, aStyle, aDescentLimit);
|
||||
aDecoration, aStyle, aVertical,
|
||||
aDescentLimit);
|
||||
if (rect.IsEmpty() || !rect.Intersects(aDirtyRect)) {
|
||||
return;
|
||||
}
|
||||
@ -3888,7 +3899,7 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
return;
|
||||
}
|
||||
|
||||
gfxFloat lineHeight = std::max(NS_round(aLineSize.height), 1.0);
|
||||
gfxFloat lineThickness = std::max(NS_round(aLineSize.height), 1.0);
|
||||
bool contextIsSaved = false;
|
||||
|
||||
gfxFloat oldLineWidth;
|
||||
@ -3904,12 +3915,14 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
aGfxContext->Save();
|
||||
contextIsSaved = true;
|
||||
aGfxContext->Clip(rect);
|
||||
gfxFloat dashWidth = lineHeight * DOT_LENGTH * DASH_LENGTH;
|
||||
gfxFloat dashWidth = lineThickness * DOT_LENGTH * DASH_LENGTH;
|
||||
gfxFloat dash[2] = { dashWidth, dashWidth };
|
||||
aGfxContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
|
||||
aGfxContext->SetDash(dash, 2, 0.0);
|
||||
rect = ExpandPaintingRectForDecorationLine(aFrame, aStyle, rect,
|
||||
aXInFrame, dashWidth * 2);
|
||||
aICoordInFrame,
|
||||
dashWidth * 2,
|
||||
aVertical);
|
||||
// We should continue to draw the last dash even if it is not in the rect.
|
||||
rect.width += dashWidth;
|
||||
break;
|
||||
@ -3918,9 +3931,9 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
aGfxContext->Save();
|
||||
contextIsSaved = true;
|
||||
aGfxContext->Clip(rect);
|
||||
gfxFloat dashWidth = lineHeight * DOT_LENGTH;
|
||||
gfxFloat dashWidth = lineThickness * DOT_LENGTH;
|
||||
gfxFloat dash[2];
|
||||
if (lineHeight > 2.0) {
|
||||
if (lineThickness > 2.0) {
|
||||
dash[0] = 0.0;
|
||||
dash[1] = dashWidth * 2.0;
|
||||
aGfxContext->SetLineCap(gfxContext::LINE_CAP_ROUND);
|
||||
@ -3930,7 +3943,9 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
}
|
||||
aGfxContext->SetDash(dash, 2, 0.0);
|
||||
rect = ExpandPaintingRectForDecorationLine(aFrame, aStyle, rect,
|
||||
aXInFrame, dashWidth * 2);
|
||||
aICoordInFrame,
|
||||
dashWidth * 2,
|
||||
aVertical);
|
||||
// We should continue to draw the last dot even if it is not in the rect.
|
||||
rect.width += dashWidth;
|
||||
break;
|
||||
@ -3939,7 +3954,7 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
aGfxContext->Save();
|
||||
contextIsSaved = true;
|
||||
aGfxContext->Clip(rect);
|
||||
if (lineHeight > 2.0) {
|
||||
if (lineThickness > 2.0) {
|
||||
aGfxContext->SetAntialiasMode(AntialiasMode::SUBPIXEL);
|
||||
} else {
|
||||
// Don't use anti-aliasing here. Because looks like lighter color wavy
|
||||
@ -3954,15 +3969,22 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
// The y position should be set to the middle of the line.
|
||||
rect.y += lineHeight / 2;
|
||||
rect.y += lineThickness / 2;
|
||||
|
||||
aGfxContext->SetColor(gfxRGBA(aColor));
|
||||
aGfxContext->SetLineWidth(lineHeight);
|
||||
aGfxContext->SetLineWidth(lineThickness);
|
||||
switch (aStyle) {
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_DASHED:
|
||||
aGfxContext->NewPath();
|
||||
aGfxContext->MoveTo(rect.TopLeft());
|
||||
aGfxContext->LineTo(rect.TopRight());
|
||||
if (aVertical) {
|
||||
aGfxContext->MoveTo(rect.TopLeft());
|
||||
aGfxContext->LineTo(rect.BottomLeft());
|
||||
} else {
|
||||
aGfxContext->MoveTo(rect.TopLeft());
|
||||
aGfxContext->LineTo(rect.TopRight());
|
||||
}
|
||||
aGfxContext->Stroke();
|
||||
break;
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE:
|
||||
@ -3971,28 +3993,29 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
*
|
||||
* +-------------------------------------------+
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineHeight
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
|
||||
* | |
|
||||
* | |
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineHeight
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
|
||||
* +-------------------------------------------+
|
||||
*/
|
||||
aGfxContext->NewPath();
|
||||
aGfxContext->MoveTo(rect.TopLeft());
|
||||
aGfxContext->LineTo(rect.TopRight());
|
||||
rect.height -= lineHeight;
|
||||
aGfxContext->MoveTo(rect.BottomLeft());
|
||||
aGfxContext->LineTo(rect.BottomRight());
|
||||
aGfxContext->Stroke();
|
||||
break;
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_DASHED:
|
||||
aGfxContext->NewPath();
|
||||
aGfxContext->MoveTo(rect.TopLeft());
|
||||
aGfxContext->LineTo(rect.TopRight());
|
||||
if (aVertical) {
|
||||
aGfxContext->MoveTo(rect.TopLeft());
|
||||
aGfxContext->LineTo(rect.BottomLeft());
|
||||
rect.width -= lineThickness;
|
||||
aGfxContext->MoveTo(rect.TopRight());
|
||||
aGfxContext->LineTo(rect.BottomRight());
|
||||
} else {
|
||||
aGfxContext->MoveTo(rect.TopLeft());
|
||||
aGfxContext->LineTo(rect.TopRight());
|
||||
rect.height -= lineThickness;
|
||||
aGfxContext->MoveTo(rect.BottomLeft());
|
||||
aGfxContext->LineTo(rect.BottomRight());
|
||||
}
|
||||
aGfxContext->Stroke();
|
||||
break;
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_WAVY: {
|
||||
@ -4023,44 +4046,64 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
* 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.
|
||||
*
|
||||
* In the vertical case, swap horizontal and vertical coordinates and
|
||||
* directions in the above description.
|
||||
*/
|
||||
|
||||
gfxFloat adv = rect.Height() - lineHeight;
|
||||
gfxFloat flatLengthAtVertex = std::max((lineHeight - 1.0) * 2.0, 1.0);
|
||||
gfxFloat& rectICoord = aVertical ? rect.y : rect.x;
|
||||
gfxFloat& rectISize = aVertical ? rect.height : rect.width;
|
||||
const gfxFloat rectBSize = aVertical ? rect.width : rect.height;
|
||||
|
||||
const gfxFloat adv = rectBSize - lineThickness;
|
||||
const gfxFloat flatLengthAtVertex =
|
||||
std::max((lineThickness - 1.0) * 2.0, 1.0);
|
||||
|
||||
// Align the start of wavy lines to the nearest ancestor block.
|
||||
gfxFloat cycleLength = 2 * (adv + flatLengthAtVertex);
|
||||
const gfxFloat cycleLength = 2 * (adv + flatLengthAtVertex);
|
||||
rect = ExpandPaintingRectForDecorationLine(aFrame, aStyle, rect,
|
||||
aXInFrame, cycleLength);
|
||||
aICoordInFrame, cycleLength,
|
||||
aVertical);
|
||||
// figure out if we can trim whole cycles from the left and right edges
|
||||
// of the line, to try and avoid creating an unnecessarily long and
|
||||
// complex path
|
||||
int32_t skipCycles = floor((aDirtyRect.x - rect.x) / cycleLength);
|
||||
const gfxFloat dirtyRectICoord = aVertical ? aDirtyRect.y : aDirtyRect.x;
|
||||
int32_t skipCycles = floor((dirtyRectICoord - rectICoord) / cycleLength);
|
||||
if (skipCycles > 0) {
|
||||
rect.x += skipCycles * cycleLength;
|
||||
rect.width -= skipCycles * cycleLength;
|
||||
rectICoord += skipCycles * cycleLength;
|
||||
rectISize -= skipCycles * cycleLength;
|
||||
}
|
||||
|
||||
rect.x += lineHeight / 2.0;
|
||||
rectICoord += lineThickness / 2.0;
|
||||
gfxPoint pt(rect.TopLeft());
|
||||
gfxFloat rightMost = pt.x + rect.Width() + lineHeight;
|
||||
gfxFloat& ptICoord = aVertical ? pt.y : pt.x;
|
||||
gfxFloat& ptBCoord = aVertical ? pt.x : pt.y;
|
||||
if (aVertical) {
|
||||
ptBCoord += adv + lineThickness / 2.0;
|
||||
}
|
||||
gfxFloat iCoordLimit = ptICoord + rectISize + lineThickness;
|
||||
|
||||
skipCycles = floor((rightMost - aDirtyRect.XMost()) / cycleLength);
|
||||
const gfxFloat dirtyRectIMost = aVertical ?
|
||||
aDirtyRect.YMost() : aDirtyRect.XMost();
|
||||
skipCycles = floor((iCoordLimit - dirtyRectIMost) / cycleLength);
|
||||
if (skipCycles > 0) {
|
||||
rightMost -= skipCycles * cycleLength;
|
||||
iCoordLimit -= skipCycles * cycleLength;
|
||||
}
|
||||
|
||||
aGfxContext->NewPath();
|
||||
|
||||
pt.x -= lineHeight;
|
||||
ptICoord -= lineThickness;
|
||||
aGfxContext->MoveTo(pt); // 1
|
||||
|
||||
pt.x = rect.X();
|
||||
ptICoord = rectICoord;
|
||||
aGfxContext->LineTo(pt); // 2
|
||||
|
||||
bool goDown = true;
|
||||
// In vertical mode, to go "down" relative to the text we need to
|
||||
// decrease the block coordinate, whereas in horizontal we increase
|
||||
// it. So the sense of this flag is effectively inverted.
|
||||
bool goDown = aVertical ? false : true;
|
||||
uint32_t iter = 0;
|
||||
while (pt.x < rightMost) {
|
||||
while (ptICoord < iCoordLimit) {
|
||||
if (++iter > 1000) {
|
||||
// stroke the current path and start again, to avoid pathological
|
||||
// behavior in cairo with huge numbers of path segments
|
||||
@ -4069,12 +4112,12 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
aGfxContext->MoveTo(pt);
|
||||
iter = 0;
|
||||
}
|
||||
pt.x += adv;
|
||||
pt.y += goDown ? adv : -adv;
|
||||
ptICoord += adv;
|
||||
ptBCoord += goDown ? adv : -adv;
|
||||
|
||||
aGfxContext->LineTo(pt); // 3 and 5
|
||||
|
||||
pt.x += flatLengthAtVertex;
|
||||
ptICoord += flatLengthAtVertex;
|
||||
aGfxContext->LineTo(pt); // 4 and 6
|
||||
|
||||
goDown = !goDown;
|
||||
@ -4101,12 +4144,13 @@ nsCSSRendering::DecorationLineToPath(nsIFrame* aFrame,
|
||||
const gfxRect& aDirtyRect,
|
||||
const nscolor aColor,
|
||||
const gfxPoint& aPt,
|
||||
const gfxFloat aXInFrame,
|
||||
const gfxFloat aICoordInFrame,
|
||||
const gfxSize& aLineSize,
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const uint8_t aDecoration,
|
||||
const uint8_t aStyle,
|
||||
bool aVertical,
|
||||
const gfxFloat aDescentLimit)
|
||||
{
|
||||
NS_ASSERTION(aStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE, "aStyle is none");
|
||||
@ -4115,7 +4159,8 @@ nsCSSRendering::DecorationLineToPath(nsIFrame* aFrame,
|
||||
|
||||
gfxRect rect =
|
||||
GetTextDecorationRectInternal(aPt, aLineSize, aAscent, aOffset,
|
||||
aDecoration, aStyle, aDescentLimit);
|
||||
aDecoration, aStyle, aVertical,
|
||||
aDescentLimit);
|
||||
if (rect.IsEmpty() || !rect.Intersects(aDirtyRect)) {
|
||||
return;
|
||||
}
|
||||
@ -4132,14 +4177,14 @@ nsCSSRendering::DecorationLineToPath(nsIFrame* aFrame,
|
||||
return;
|
||||
}
|
||||
|
||||
gfxFloat lineHeight = std::max(NS_round(aLineSize.height), 1.0);
|
||||
gfxFloat lineThickness = std::max(NS_round(aLineSize.height), 1.0);
|
||||
|
||||
// The y position should be set to the middle of the line.
|
||||
rect.y += lineHeight / 2;
|
||||
rect.y += lineThickness / 2;
|
||||
|
||||
aGfxContext->Rectangle
|
||||
(gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(0.0, lineHeight / 2)),
|
||||
gfxSize(rect.Width(), lineHeight)));
|
||||
(gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(0.0, lineThickness / 2)),
|
||||
gfxSize(rect.Width(), lineThickness)));
|
||||
}
|
||||
|
||||
nsRect
|
||||
@ -4149,6 +4194,7 @@ nsCSSRendering::GetTextDecorationRect(nsPresContext* aPresContext,
|
||||
const gfxFloat aOffset,
|
||||
const uint8_t aDecoration,
|
||||
const uint8_t aStyle,
|
||||
bool aVertical,
|
||||
const gfxFloat aDescentLimit)
|
||||
{
|
||||
NS_ASSERTION(aPresContext, "aPresContext is null");
|
||||
@ -4156,7 +4202,8 @@ nsCSSRendering::GetTextDecorationRect(nsPresContext* aPresContext,
|
||||
|
||||
gfxRect rect =
|
||||
GetTextDecorationRectInternal(gfxPoint(0, 0), aLineSize, aAscent, aOffset,
|
||||
aDecoration, aStyle, aDescentLimit);
|
||||
aDecoration, aStyle, aVertical,
|
||||
aDescentLimit);
|
||||
// The rect values are already rounded to nearest device pixels.
|
||||
nsRect r;
|
||||
r.x = aPresContext->GfxUnitsToAppUnits(rect.X());
|
||||
@ -4173,6 +4220,7 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
const gfxFloat aOffset,
|
||||
const uint8_t aDecoration,
|
||||
const uint8_t aStyle,
|
||||
bool aVertical,
|
||||
const gfxFloat aDescentLimit)
|
||||
{
|
||||
NS_ASSERTION(aStyle <= NS_STYLE_TEXT_DECORATION_STYLE_WAVY,
|
||||
@ -4183,42 +4231,52 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
|
||||
bool canLiftUnderline = aDescentLimit >= 0.0;
|
||||
|
||||
const gfxFloat left = floor(aPt.x + 0.5),
|
||||
right = floor(aPt.x + aLineSize.width + 0.5);
|
||||
gfxFloat iCoord = aVertical ? aPt.y : aPt.x;
|
||||
gfxFloat bCoord = aVertical ? aPt.x : aPt.y;
|
||||
|
||||
// 'left' and 'right' are relative to the line, so for vertical writing modes
|
||||
// they will actually become top and bottom of the rendered line.
|
||||
// Similarly, aLineSize.width and .height are actually length and thickness
|
||||
// of the line, which runs horizontally or vertically according to aVertical.
|
||||
const gfxFloat left = floor(iCoord + 0.5),
|
||||
right = floor(iCoord + aLineSize.width + 0.5);
|
||||
|
||||
// We compute |r| as if for a horizontal text run, and then swap vertical
|
||||
// and horizontal coordinates at the end if vertical was requested.
|
||||
gfxRect r(left, 0, right - left, 0);
|
||||
|
||||
gfxFloat lineHeight = NS_round(aLineSize.height);
|
||||
lineHeight = std::max(lineHeight, 1.0);
|
||||
gfxFloat lineThickness = NS_round(aLineSize.height);
|
||||
lineThickness = std::max(lineThickness, 1.0);
|
||||
|
||||
gfxFloat ascent = NS_round(aAscent);
|
||||
gfxFloat descentLimit = floor(aDescentLimit);
|
||||
|
||||
gfxFloat suggestedMaxRectHeight = std::max(std::min(ascent, descentLimit), 1.0);
|
||||
r.height = lineHeight;
|
||||
r.height = lineThickness;
|
||||
if (aStyle == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE) {
|
||||
/**
|
||||
* We will draw double line as:
|
||||
*
|
||||
* +-------------------------------------------+
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineHeight
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
|
||||
* | | ^
|
||||
* | | | gap
|
||||
* | | v
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineHeight
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
|
||||
* |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
|
||||
* +-------------------------------------------+
|
||||
*/
|
||||
gfxFloat gap = NS_round(lineHeight / 2.0);
|
||||
gfxFloat gap = NS_round(lineThickness / 2.0);
|
||||
gap = std::max(gap, 1.0);
|
||||
r.height = lineHeight * 2.0 + gap;
|
||||
r.height = lineThickness * 2.0 + gap;
|
||||
if (canLiftUnderline) {
|
||||
if (r.Height() > suggestedMaxRectHeight) {
|
||||
// Don't shrink the line height, because the thickness has some meaning.
|
||||
// We can just shrink the gap at this time.
|
||||
r.height = std::max(suggestedMaxRectHeight, lineHeight * 2.0 + 1.0);
|
||||
r.height = std::max(suggestedMaxRectHeight, lineThickness * 2.0 + 1.0);
|
||||
}
|
||||
}
|
||||
} else if (aStyle == NS_STYLE_TEXT_DECORATION_STYLE_WAVY) {
|
||||
@ -4227,7 +4285,7 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
*
|
||||
* +-------------------------------------------+
|
||||
* |XXXXX XXXXXX XXXXXX | ^
|
||||
* |XXXXXX XXXXXXXX XXXXXXXX | | lineHeight
|
||||
* |XXXXXX XXXXXXXX XXXXXXXX | | lineThickness
|
||||
* |XXXXXXX XXXXXXXXXX XXXXXXXXXX| v
|
||||
* | XXX XXX XXX XXX XX|
|
||||
* | XXXXXXXXXX XXXXXXXXXX X|
|
||||
@ -4235,19 +4293,19 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
* | XXXXXX XXXXXX |
|
||||
* +-------------------------------------------+
|
||||
*/
|
||||
r.height = lineHeight > 2.0 ? lineHeight * 4.0 : lineHeight * 3.0;
|
||||
r.height = lineThickness > 2.0 ? lineThickness * 4.0 : lineThickness * 3.0;
|
||||
if (canLiftUnderline) {
|
||||
if (r.Height() > suggestedMaxRectHeight) {
|
||||
// Don't shrink the line height even if there is not enough space,
|
||||
// because the thickness has some meaning. E.g., the 1px wavy line and
|
||||
// 2px wavy line can be used for different meaning in IME selections
|
||||
// at same time.
|
||||
r.height = std::max(suggestedMaxRectHeight, lineHeight * 2.0);
|
||||
r.height = std::max(suggestedMaxRectHeight, lineThickness * 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfxFloat baseline = floor(aPt.y + aAscent + 0.5);
|
||||
gfxFloat baseline = floor(bCoord + aAscent + 0.5);
|
||||
gfxFloat offset = 0.0;
|
||||
switch (aDecoration) {
|
||||
case NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE:
|
||||
@ -4265,18 +4323,27 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_TEXT_DECORATION_LINE_OVERLINE:
|
||||
offset = aOffset - lineHeight + r.Height();
|
||||
offset = aOffset - lineThickness + r.Height();
|
||||
break;
|
||||
case NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH: {
|
||||
gfxFloat extra = floor(r.Height() / 2.0 + 0.5);
|
||||
extra = std::max(extra, lineHeight);
|
||||
offset = aOffset - lineHeight + extra;
|
||||
extra = std::max(extra, lineThickness);
|
||||
offset = aOffset - lineThickness + extra;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_ERROR("Invalid decoration value!");
|
||||
}
|
||||
r.y = baseline - floor(offset + 0.5);
|
||||
|
||||
if (aVertical) {
|
||||
r.y = baseline + floor(aOffset + 0.5); // this will need updating when we
|
||||
// support sideways-left orientation
|
||||
Swap(r.x, r.y);
|
||||
Swap(r.width, r.height);
|
||||
} else {
|
||||
r.y = baseline - floor(aOffset + 0.5);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -598,23 +598,29 @@ struct nsCSSRendering {
|
||||
* Function for painting the decoration lines for the text.
|
||||
* NOTE: aPt, aLineSize, aAscent and aOffset are non-rounded device pixels,
|
||||
* not app units.
|
||||
* NOTE: aLineSize is a "logical" size in textRun orientation, so that for
|
||||
* a vertical textrun, aLineSize.width (which is the decoration line
|
||||
* length) will actually be a physical height; and conversely,
|
||||
* aLineSize.height [thickness] will be a physical width. The alternate
|
||||
* names in [brackets] in the comments here apply to the vertical case.
|
||||
*
|
||||
* input:
|
||||
* @param aFrame the frame which needs the decoration line
|
||||
* @param aGfxContext
|
||||
* @param aDirtyRect no need to paint outside this rect
|
||||
* @param aColor the color of the decoration line
|
||||
* @param aPt the top/left edge of the text
|
||||
* @param aXInFrame the distance between aPt.x and left edge of
|
||||
* aFrame. If the decoration line is for shadow,
|
||||
* set the distance between the left edge of
|
||||
* the aFrame and the position of the text as
|
||||
* @param aICoordInFrame the distance between aPt.x [y] and left [top]
|
||||
* edge of aFrame. If the decoration line is for
|
||||
* shadow, set the distance between the left edge
|
||||
* of the aFrame and the position of the text as
|
||||
* positioned without offset of the shadow.
|
||||
* @param aLineSize the width and the height of the decoration
|
||||
* line
|
||||
* @param aLineSize the width [length] and the height [thickness]
|
||||
* of the decoration line
|
||||
* @param aAscent the ascent of the text
|
||||
* @param aOffset the offset of the decoration line from
|
||||
* the baseline of the text (if the value is
|
||||
* positive, the line is lifted up)
|
||||
* positive, the line is lifted up [right])
|
||||
* @param aDecoration which line will be painted. The value can be
|
||||
* NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE or
|
||||
* NS_STYLE_TEXT_DECORATION_LINE_OVERLINE or
|
||||
@ -638,12 +644,13 @@ struct nsCSSRendering {
|
||||
const gfxRect& aDirtyRect,
|
||||
const nscolor aColor,
|
||||
const gfxPoint& aPt,
|
||||
const gfxFloat aXInFrame,
|
||||
const gfxFloat aICoordInFrame,
|
||||
const gfxSize& aLineSize,
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const uint8_t aDecoration,
|
||||
const uint8_t aStyle,
|
||||
bool aVertical,
|
||||
const gfxFloat aDescentLimit = -1.0);
|
||||
|
||||
/**
|
||||
@ -658,12 +665,13 @@ struct nsCSSRendering {
|
||||
const gfxRect& aDirtyRect,
|
||||
const nscolor aColor,
|
||||
const gfxPoint& aPt,
|
||||
const gfxFloat aXInFrame,
|
||||
const gfxFloat aICoordInFrame,
|
||||
const gfxSize& aLineSize,
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const uint8_t aDecoration,
|
||||
const uint8_t aStyle,
|
||||
bool aVertical,
|
||||
const gfxFloat aDescentLimit = -1.0);
|
||||
|
||||
/**
|
||||
@ -705,6 +713,7 @@ struct nsCSSRendering {
|
||||
const gfxFloat aOffset,
|
||||
const uint8_t aDecoration,
|
||||
const uint8_t aStyle,
|
||||
bool aVertical,
|
||||
const gfxFloat aDescentLimit = -1.0);
|
||||
|
||||
static gfxContext::GraphicsOperator GetGFXBlendMode(uint8_t mBlendMode) {
|
||||
@ -738,7 +747,8 @@ protected:
|
||||
const gfxFloat aOffset,
|
||||
const uint8_t aDecoration,
|
||||
const uint8_t aStyle,
|
||||
const gfxFloat aDscentLimit);
|
||||
bool aVertical,
|
||||
const gfxFloat aDescentLimit);
|
||||
|
||||
/**
|
||||
* Returns inflated rect for painting a decoration line.
|
||||
@ -755,16 +765,17 @@ protected:
|
||||
* NS_STYLE_TEXT_DECORATION_STYLE_WAVY.
|
||||
* @param aClippedRect the clipped rect for the decoration line.
|
||||
* in other words, visible area of the line.
|
||||
* @param aXInFrame the distance between left edge of aFrame and
|
||||
* aClippedRect.pos.x.
|
||||
* @param aICoordInFrame the distance between inline-start edge of aFrame
|
||||
* and aClippedRect.pos.
|
||||
* @param aCycleLength the width of one cycle of the line style.
|
||||
*/
|
||||
static gfxRect ExpandPaintingRectForDecorationLine(
|
||||
nsIFrame* aFrame,
|
||||
const uint8_t aStyle,
|
||||
const gfxRect &aClippedRect,
|
||||
const gfxFloat aXInFrame,
|
||||
const gfxFloat aCycleLength);
|
||||
const gfxFloat aICoordInFrame,
|
||||
const gfxFloat aCycleLength,
|
||||
bool aVertical);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1791,12 +1791,13 @@ GetHyphenTextRun(gfxTextRun* aTextRun, gfxContext* aContext, nsTextFrame* aTextF
|
||||
}
|
||||
|
||||
static gfxFont::Metrics
|
||||
GetFirstFontMetrics(gfxFontGroup* aFontGroup)
|
||||
GetFirstFontMetrics(gfxFontGroup* aFontGroup, bool aVertical)
|
||||
{
|
||||
if (!aFontGroup)
|
||||
return gfxFont::Metrics();
|
||||
gfxFont* font = aFontGroup->GetFirstValidFont();
|
||||
return font->GetMetrics(gfxFont::eHorizontal); // XXX vertical
|
||||
return font->GetMetrics(aVertical ? gfxFont::eVertical :
|
||||
gfxFont::eHorizontal);
|
||||
}
|
||||
|
||||
PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_NORMAL == 0);
|
||||
@ -3117,8 +3118,9 @@ ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun)
|
||||
// Round the space width when converting to appunits the same way
|
||||
// textruns do
|
||||
gfxFloat spaceWidthAppUnits =
|
||||
NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup()).spaceWidth *
|
||||
aTextRun->GetAppUnitsPerDevUnit());
|
||||
NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(),
|
||||
aTextRun->IsVertical()).spaceWidth *
|
||||
aTextRun->GetAppUnitsPerDevUnit());
|
||||
return textStyle->mTabSize * spaceWidthAppUnits;
|
||||
}
|
||||
|
||||
@ -4890,6 +4892,7 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
nsRect shadowRect =
|
||||
nsLayoutUtils::GetTextShadowRectsUnion(*aVisualOverflowRect, this);
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, shadowRect);
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
|
||||
if (IsFloatingFirstLetterChild()) {
|
||||
// The underline/overline drawable area must be contained in the overflow
|
||||
@ -4909,7 +4912,9 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
nscoord maxAscent = fontMetrics->MaxAscent();
|
||||
|
||||
gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel();
|
||||
gfxFloat gfxWidth = aVisualOverflowRect->width / appUnitsPerDevUnit;
|
||||
gfxFloat gfxWidth =
|
||||
(vertical ? aVisualOverflowRect->height : aVisualOverflowRect->width) /
|
||||
appUnitsPerDevUnit;
|
||||
gfxFloat gfxAscent = gfxFloat(mAscent) / appUnitsPerDevUnit;
|
||||
gfxFloat gfxMaxAscent = maxAscent / appUnitsPerDevUnit;
|
||||
gfxFloat gfxUnderlineSize = underlineSize / appUnitsPerDevUnit;
|
||||
@ -4917,11 +4922,11 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
nsRect underlineRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, gfxUnderlineSize), gfxAscent, gfxUnderlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle);
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle, vertical);
|
||||
nsRect overlineRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, gfxUnderlineSize), gfxAscent, gfxMaxAscent,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle);
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle, vertical);
|
||||
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, underlineRect);
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, overlineRect);
|
||||
@ -4941,9 +4946,9 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
nscoord inflationMinFontSize =
|
||||
nsLayoutUtils::InflationMinFontSizeFor(aBlock);
|
||||
|
||||
const nscoord width = GetSize().width;
|
||||
const nscoord measure = vertical ? GetSize().height : GetSize().width;
|
||||
const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(),
|
||||
gfxWidth = width / appUnitsPerDevUnit,
|
||||
gfxWidth = measure / appUnitsPerDevUnit,
|
||||
ascent = gfxFloat(mAscent) / appUnitsPerDevUnit;
|
||||
nscoord top(nscoord_MAX), bottom(nscoord_MIN);
|
||||
// Below we loop through all text decorations and compute the rectangle
|
||||
@ -4961,13 +4966,15 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
float inflation =
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation));
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.underlineSize),
|
||||
ascent, metrics.underlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle) +
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle,
|
||||
vertical) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
|
||||
top = std::min(decorationRect.y, top);
|
||||
@ -4986,13 +4993,15 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
float inflation =
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation));
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.underlineSize),
|
||||
ascent, metrics.maxAscent,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle) +
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle,
|
||||
vertical) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
|
||||
top = std::min(decorationRect.y, top);
|
||||
@ -5011,20 +5020,24 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
float inflation =
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation));
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.strikeoutSize),
|
||||
ascent, metrics.strikeoutOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, decorationStyle) +
|
||||
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, decorationStyle,
|
||||
vertical) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
top = std::min(decorationRect.y, top);
|
||||
bottom = std::max(decorationRect.YMost(), bottom);
|
||||
}
|
||||
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect,
|
||||
nsRect(0, top, width, bottom - top));
|
||||
vertical ?
|
||||
nsRect(top, 0, bottom - top, measure) :
|
||||
nsRect(0, top, measure, bottom - top));
|
||||
}
|
||||
}
|
||||
// When this frame is not selected, the text-decoration area must be in
|
||||
@ -5104,7 +5117,7 @@ PaintDecorationLine(nsIFrame* aFrame,
|
||||
nscolor aColor,
|
||||
const nscolor* aOverrideColor,
|
||||
const gfxPoint& aPt,
|
||||
gfxFloat aXInFrame,
|
||||
gfxFloat aICoordInFrame,
|
||||
const gfxSize& aLineSize,
|
||||
gfxFloat aAscent,
|
||||
gfxFloat aOffset,
|
||||
@ -5112,6 +5125,7 @@ PaintDecorationLine(nsIFrame* aFrame,
|
||||
uint8_t aStyle,
|
||||
DecorationType aDecorationType,
|
||||
nsTextFrame::DrawPathCallbacks* aCallbacks,
|
||||
bool aVertical,
|
||||
gfxFloat aDescentLimit = -1.0)
|
||||
{
|
||||
nscolor lineColor = aOverrideColor ? *aOverrideColor : aColor;
|
||||
@ -5122,7 +5136,7 @@ PaintDecorationLine(nsIFrame* aFrame,
|
||||
aCallbacks->NotifyBeforeSelectionDecorationLine(lineColor);
|
||||
}
|
||||
nsCSSRendering::DecorationLineToPath(aFrame, aCtx, aDirtyRect, lineColor,
|
||||
aPt, aXInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle,
|
||||
aPt, aICoordInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle,
|
||||
aDescentLimit);
|
||||
if (aDecorationType == eNormalDecoration) {
|
||||
aCallbacks->NotifyDecorationLinePathEmitted();
|
||||
@ -5131,8 +5145,8 @@ PaintDecorationLine(nsIFrame* aFrame,
|
||||
}
|
||||
} else {
|
||||
nsCSSRendering::PaintDecorationLine(aFrame, aCtx, aDirtyRect, lineColor,
|
||||
aPt, aXInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle,
|
||||
aDescentLimit);
|
||||
aPt, aICoordInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle,
|
||||
aVertical, aDescentLimit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5146,9 +5160,10 @@ static void DrawSelectionDecorations(gfxContext* aContext,
|
||||
nsTextFrame* aFrame,
|
||||
nsTextPaintStyle& aTextPaintStyle,
|
||||
const TextRangeStyle &aRangeStyle,
|
||||
const gfxPoint& aPt, gfxFloat aXInFrame, gfxFloat aWidth,
|
||||
const gfxPoint& aPt, gfxFloat aICoordInFrame, gfxFloat aWidth,
|
||||
gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics,
|
||||
nsTextFrame::DrawPathCallbacks* aCallbacks)
|
||||
nsTextFrame::DrawPathCallbacks* aCallbacks,
|
||||
bool aVertical)
|
||||
{
|
||||
gfxPoint pt(aPt);
|
||||
gfxSize size(aWidth,
|
||||
@ -5225,9 +5240,10 @@ static void DrawSelectionDecorations(gfxContext* aContext,
|
||||
}
|
||||
size.height *= relativeSize;
|
||||
PaintDecorationLine(aFrame, aContext, aDirtyRect, color, nullptr, pt,
|
||||
pt.x - aPt.x + aXInFrame, size, aAscent, aFontMetrics.underlineOffset,
|
||||
(aVertical ? (pt.y - aPt.y) : (pt.x - aPt.x)) + aICoordInFrame,
|
||||
size, aAscent, aFontMetrics.underlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, style, eSelectionDecoration,
|
||||
aCallbacks, descentLimit);
|
||||
aCallbacks, aVertical, descentLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5680,36 +5696,53 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
||||
}
|
||||
|
||||
gfxFont* firstFont = aProvider.GetFontGroup()->GetFirstValidFont();
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
gfxFont::Metrics
|
||||
decorationMetrics(firstFont->GetMetrics(gfxFont::eHorizontal)); // XXX vertical?
|
||||
decorationMetrics.underlineOffset =
|
||||
aProvider.GetFontGroup()->GetUnderlineOffset();
|
||||
decorationMetrics(firstFont->GetMetrics(vertical ?
|
||||
gfxFont::eVertical : gfxFont::eHorizontal));
|
||||
if (!vertical) {
|
||||
// The potential adjustment from using gfxFontGroup::GetUnderlineOffset
|
||||
// is only valid for horizontal text.
|
||||
decorationMetrics.underlineOffset =
|
||||
aProvider.GetFontGroup()->GetUnderlineOffset();
|
||||
}
|
||||
|
||||
gfxFloat startXOffset = aTextBaselinePt.x - aFramePt.x;
|
||||
gfxFloat startIOffset =
|
||||
vertical ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
|
||||
SelectionIterator iterator(selectedChars, aContentOffset, aContentLength,
|
||||
aProvider, mTextRun, startXOffset);
|
||||
gfxFloat xOffset, hyphenWidth;
|
||||
aProvider, mTextRun, startIOffset);
|
||||
gfxFloat iOffset, hyphenWidth;
|
||||
uint32_t offset, length;
|
||||
int32_t app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
|
||||
// XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint?
|
||||
gfxPoint pt(0.0, (aTextBaselinePt.y - mAscent) / app);
|
||||
gfxPoint pt;
|
||||
if (vertical) {
|
||||
pt.x = (aTextBaselinePt.x - mAscent) / app;
|
||||
} else {
|
||||
pt.y = (aTextBaselinePt.y - mAscent) / app;
|
||||
}
|
||||
gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app,
|
||||
aDirtyRect.width / app, aDirtyRect.height / app);
|
||||
SelectionType type;
|
||||
TextRangeStyle selectedStyle;
|
||||
while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth,
|
||||
while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth,
|
||||
&type, &selectedStyle)) {
|
||||
gfxFloat advance = hyphenWidth +
|
||||
mTextRun->GetAdvanceWidth(offset, length, &aProvider);
|
||||
if (type == aSelectionType) {
|
||||
pt.x = (aFramePt.x + xOffset -
|
||||
(mTextRun->IsRightToLeft() ? advance : 0)) / app;
|
||||
if (vertical) {
|
||||
pt.y = (aFramePt.y + iOffset -
|
||||
(mTextRun->IsRightToLeft() ? advance : 0)) / app;
|
||||
} else {
|
||||
pt.x = (aFramePt.x + iOffset -
|
||||
(mTextRun->IsRightToLeft() ? advance : 0)) / app;
|
||||
}
|
||||
gfxFloat width = Abs(advance) / app;
|
||||
gfxFloat xInFrame = pt.x - (aFramePt.x / app);
|
||||
DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, this,
|
||||
aTextPaintStyle, selectedStyle, pt, xInFrame,
|
||||
width, mAscent / app, decorationMetrics,
|
||||
aCallbacks);
|
||||
aCallbacks, vertical);
|
||||
}
|
||||
iterator.UpdateWithAdvance(advance);
|
||||
}
|
||||
@ -6096,10 +6129,11 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
nsTextFrame::DrawPathCallbacks* aCallbacks)
|
||||
{
|
||||
const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel();
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
|
||||
// XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint?
|
||||
nscoord x = NSToCoordRound(aFramePt.x);
|
||||
nscoord width = GetRect().width;
|
||||
nscoord width = vertical ? GetRect().height : GetRect().width;
|
||||
aClipEdges.Intersect(&x, &width);
|
||||
|
||||
gfxPoint decPt(x / app, 0);
|
||||
@ -6123,7 +6157,8 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
float inflation =
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation));
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
|
||||
decSize.height = metrics.underlineSize;
|
||||
decPt.y = (frameTop - dec.mBaselineOffset) / app;
|
||||
@ -6131,7 +6166,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
|
||||
dec.mStyle, eNormalDecoration, aCallbacks);
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, vertical);
|
||||
}
|
||||
// Overlines
|
||||
for (uint32_t i = aDecorations.mOverlines.Length(); i-- > 0; ) {
|
||||
@ -6143,7 +6178,8 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
float inflation =
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation));
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
|
||||
decSize.height = metrics.underlineSize;
|
||||
decPt.y = (frameTop - dec.mBaselineOffset) / app;
|
||||
@ -6151,7 +6187,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle,
|
||||
eNormalDecoration, aCallbacks);
|
||||
eNormalDecoration, aCallbacks, vertical);
|
||||
}
|
||||
|
||||
// CSS 2.1 mandates that text be painted after over/underlines, and *then*
|
||||
@ -6169,7 +6205,8 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
float inflation =
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation));
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
|
||||
decSize.height = metrics.strikeoutSize;
|
||||
decPt.y = (frameTop - dec.mBaselineOffset) / app;
|
||||
@ -6177,7 +6214,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
|
||||
dec.mStyle, eNormalDecoration, aCallbacks);
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, vertical);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6373,8 +6410,9 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
|
||||
GetFontSizeInflation());
|
||||
gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
|
||||
gfxFont* firstFont = fontGroup->GetFirstValidFont();
|
||||
bool vertical = GetWritingMode().IsVertical();
|
||||
const gfxFont::Metrics& metrics =
|
||||
firstFont->GetMetrics(gfxFont::eHorizontal); // XXX vertical?
|
||||
firstFont->GetMetrics(vertical ? gfxFont::eVertical : gfxFont::eHorizontal);
|
||||
gfxFloat underlineOffset = fontGroup->GetUnderlineOffset();
|
||||
gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(mAscent);
|
||||
gfxFloat descentLimit =
|
||||
@ -6419,7 +6457,7 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
|
||||
decorationArea =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext, size,
|
||||
ascent, underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
|
||||
style, descentLimit);
|
||||
style, vertical, descentLimit);
|
||||
aRect.UnionRect(aRect, decorationArea);
|
||||
}
|
||||
DestroySelectionDetails(details);
|
||||
|
@ -399,6 +399,8 @@ nsTextBoxFrame::DrawText(nsRenderingContext& aRenderingContext,
|
||||
// A mask of all possible decorations.
|
||||
uint8_t decorMask = NS_STYLE_TEXT_DECORATION_LINE_LINES_MASK;
|
||||
|
||||
bool vertical = GetWritingMode().IsVertical();
|
||||
|
||||
nsIFrame* f = this;
|
||||
do { // find decoration colors
|
||||
nsStyleContext* context = f->StyleContext();
|
||||
@ -477,14 +479,16 @@ nsTextBoxFrame::DrawText(nsRenderingContext& aRenderingContext,
|
||||
nsCSSRendering::PaintDecorationLine(this, ctx, dirtyRect, underColor,
|
||||
pt, xInFrame, gfxSize(width, sizePixel),
|
||||
ascentPixel, offsetPixel,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, underStyle);
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, underStyle,
|
||||
vertical);
|
||||
}
|
||||
if ((decorations & NS_FONT_DECORATION_OVERLINE) &&
|
||||
overStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
|
||||
nsCSSRendering::PaintDecorationLine(this, ctx, dirtyRect, overColor,
|
||||
pt, xInFrame, gfxSize(width, sizePixel),
|
||||
ascentPixel, ascentPixel,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, overStyle);
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, overStyle,
|
||||
vertical);
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,7 +566,7 @@ nsTextBoxFrame::DrawText(nsRenderingContext& aRenderingContext,
|
||||
nsCSSRendering::PaintDecorationLine(this, ctx, dirtyRect, strikeColor,
|
||||
pt, xInFrame, gfxSize(width, sizePixel), ascentPixel,
|
||||
offsetPixel, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
|
||||
strikeStyle);
|
||||
strikeStyle, vertical);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user