mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 12:25:53 +00:00
Bug 486708 Should lift up selection underline as far as possible if it overflows from the descent space r+sr=roc
This commit is contained in:
parent
52d3713040
commit
45600f33a1
@ -2507,13 +2507,14 @@ nsCSSRendering::PaintDecorationLine(gfxContext* aGfxContext,
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const PRUint8 aDecoration,
|
||||
const PRUint8 aStyle)
|
||||
const PRUint8 aStyle,
|
||||
const gfxFloat aDescentLimit)
|
||||
{
|
||||
NS_ASSERTION(aStyle != DECORATION_STYLE_NONE, "aStyle is none");
|
||||
|
||||
gfxRect rect =
|
||||
GetTextDecorationRectInternal(aPt, aLineSize, aAscent, aOffset,
|
||||
aDecoration, aStyle);
|
||||
aDecoration, aStyle, aDescentLimit);
|
||||
if (rect.IsEmpty())
|
||||
return;
|
||||
|
||||
@ -2706,14 +2707,15 @@ nsCSSRendering::GetTextDecorationRect(nsPresContext* aPresContext,
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const PRUint8 aDecoration,
|
||||
const PRUint8 aStyle)
|
||||
const PRUint8 aStyle,
|
||||
const gfxFloat aDescentLimit)
|
||||
{
|
||||
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);
|
||||
aDecoration, aStyle, aDescentLimit);
|
||||
// The rect values are already rounded to nearest device pixels.
|
||||
nsRect r;
|
||||
r.x = aPresContext->GfxUnitsToAppUnits(rect.X());
|
||||
@ -2729,19 +2731,27 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const PRUint8 aDecoration,
|
||||
const PRUint8 aStyle)
|
||||
const PRUint8 aStyle,
|
||||
const gfxFloat aDescentLimit)
|
||||
{
|
||||
NS_ASSERTION(aStyle <= DECORATION_STYLE_WAVY, "Invalid aStyle value");
|
||||
|
||||
if (aStyle == DECORATION_STYLE_NONE)
|
||||
return gfxRect(0, 0, 0, 0);
|
||||
|
||||
PRBool canLiftUnderline = aDescentLimit >= 0.0;
|
||||
|
||||
gfxRect r;
|
||||
r.pos.x = NS_floor(aPt.x + 0.5);
|
||||
r.size.width = NS_round(aLineSize.width);
|
||||
|
||||
gfxFloat lineHeight = NS_round(aLineSize.height);
|
||||
lineHeight = PR_MAX(lineHeight, 1.0);
|
||||
|
||||
gfxFloat ascent = NS_round(aAscent);
|
||||
gfxFloat descentLimit = NS_round(aDescentLimit);
|
||||
|
||||
gfxFloat suggestedMaxRectHeight = PR_MAX(PR_MIN(ascent, descentLimit), 1.0);
|
||||
gfxFloat underlineOffsetAdjust = 0.0;
|
||||
r.size.height = lineHeight;
|
||||
if (aStyle == DECORATION_STYLE_DOUBLE) {
|
||||
@ -2763,6 +2773,13 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
gfxFloat gap = NS_round(lineHeight / 2.0);
|
||||
gap = PR_MAX(gap, 1.0);
|
||||
r.size.height = lineHeight * 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.size.height = PR_MAX(suggestedMaxRectHeight, lineHeight * 2.0 + 1.0);
|
||||
}
|
||||
}
|
||||
} else if (aStyle == DECORATION_STYLE_WAVY) {
|
||||
/**
|
||||
* We will draw wavy line as:
|
||||
@ -2778,6 +2795,21 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
* +-------------------------------------------+
|
||||
*/
|
||||
r.size.height = lineHeight > 2.0 ? lineHeight * 4.0 : lineHeight * 3.0;
|
||||
if (canLiftUnderline) {
|
||||
// Wavy line's top edge can overlap to the baseline, because even if the
|
||||
// wavy line overlaps the baseline of the text, that shouldn't cause
|
||||
// unreadability.
|
||||
descentLimit += lineHeight;
|
||||
// Recompute suggestedMaxRectHeight with new descentLimit value.
|
||||
suggestedMaxRectHeight = PR_MAX(PR_MIN(ascent, descentLimit), 1.0);
|
||||
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.size.height = PR_MAX(suggestedMaxRectHeight, lineHeight * 2.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
|
||||
@ -2790,6 +2822,17 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
switch (aDecoration) {
|
||||
case NS_STYLE_TEXT_DECORATION_UNDERLINE:
|
||||
offset = aOffset + underlineOffsetAdjust;
|
||||
if (canLiftUnderline) {
|
||||
if (descentLimit < -offset + r.Height()) {
|
||||
// If we can ignore the offset and the decoration line is overflowing,
|
||||
// we should align the bottom edge of the decoration line rect if it's
|
||||
// possible. Otherwise, we should lift up the top edge of the rect as
|
||||
// far as possible.
|
||||
gfxFloat offsetBottomAligned = -descentLimit + r.Height();
|
||||
gfxFloat offsetTopAligned = underlineOffsetAdjust;
|
||||
offset = PR_MIN(offsetBottomAligned, offsetTopAligned);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_TEXT_DECORATION_OVERLINE:
|
||||
offset = aOffset - lineHeight + r.Height();
|
||||
|
@ -231,6 +231,17 @@ struct nsCSSRendering {
|
||||
* NS_STYLE_TEXT_DECORATION_LINE_THROUGH.
|
||||
* @param aStyle the style of the decoration line (See above
|
||||
* enum names).
|
||||
* @param aDescentLimit If aDescentLimit is zero or larger and the
|
||||
* underline overflows from the descent space,
|
||||
* the underline should be lifted up as far as
|
||||
* possible. Note that this does not mean the
|
||||
* underline never overflows from this
|
||||
* limitation. Because if the underline is
|
||||
* positioned to the baseline or upper, it causes
|
||||
* unreadability. Note that if this is zero
|
||||
* or larger, the underline rect may be shrunken
|
||||
* if it's possible. Therefore, this value is
|
||||
* used for strikeout line and overline too.
|
||||
*/
|
||||
static void PaintDecorationLine(gfxContext* aGfxContext,
|
||||
const nscolor aColor,
|
||||
@ -239,7 +250,8 @@ struct nsCSSRendering {
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const PRUint8 aDecoration,
|
||||
const PRUint8 aStyle);
|
||||
const PRUint8 aStyle,
|
||||
const gfxFloat aDescentLimit = -1.0);
|
||||
|
||||
/**
|
||||
* Function for getting the decoration line rect for the text.
|
||||
@ -259,6 +271,17 @@ struct nsCSSRendering {
|
||||
* NS_STYLE_TEXT_DECORATION_LINE_THROUGH.
|
||||
* @param aStyle the style of the decoration line (See above
|
||||
* enum names).
|
||||
* @param aDescentLimit If aDescentLimit is zero or larger and the
|
||||
* underline overflows from the descent space,
|
||||
* the underline should be lifted up as far as
|
||||
* possible. Note that this does not mean the
|
||||
* underline never overflows from this
|
||||
* limitation. Because if the underline is
|
||||
* positioned to the baseline or upper, it causes
|
||||
* unreadability. Note that if this is zero
|
||||
* or larger, the underline rect may be shrunken
|
||||
* if it's possible. Therefore, this value is
|
||||
* used for strikeout line and overline too.
|
||||
* output:
|
||||
* @return the decoration line rect for the input,
|
||||
* the each values are app units.
|
||||
@ -268,7 +291,8 @@ struct nsCSSRendering {
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const PRUint8 aDecoration,
|
||||
const PRUint8 aStyle);
|
||||
const PRUint8 aStyle,
|
||||
const gfxFloat aDescentLimit = -1.0);
|
||||
|
||||
protected:
|
||||
static gfxRect GetTextDecorationRectInternal(const gfxPoint& aPt,
|
||||
@ -276,7 +300,8 @@ protected:
|
||||
const gfxFloat aAscent,
|
||||
const gfxFloat aOffset,
|
||||
const PRUint8 aDecoration,
|
||||
const PRUint8 aStyle);
|
||||
const PRUint8 aStyle,
|
||||
const gfxFloat aDscentLimit);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -24,9 +24,11 @@ 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)
|
||||
function drawDecorationLine(aDocument, aColor, aPt, aLineSize, aAscent, aOffset,
|
||||
aStyle, aDescentLimit)
|
||||
{
|
||||
var rect = getTextDecorationRect(aPt, aLineSize, aAscent, aOffset, aStyle);
|
||||
var rect = getTextDecorationRect(aPt, aLineSize, aAscent, aOffset, aStyle,
|
||||
aDescentLimit);
|
||||
if (rect.width == 0 || rect.height == 0)
|
||||
return;
|
||||
|
||||
@ -146,25 +148,45 @@ function drawDecorationLine(aDocument, aColor, aPt, aLineSize, aAscent, aOffset,
|
||||
}
|
||||
}
|
||||
|
||||
function getTextDecorationRect(aPt, aLineSize, aAscent, aOffset, aStyle)
|
||||
function getTextDecorationRect(aPt, aLineSize, aAscent, aOffset, aStyle,
|
||||
aDescentLimit)
|
||||
{
|
||||
if (aStyle == kDecorationStyleNone)
|
||||
return { x: 0, y: 0, width: 0, height: 0 };
|
||||
|
||||
var liftupUnderline = aDescentLimit >= 0.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 ascent = round(aAscent);
|
||||
var descentLimit = round(aDescentLimit);
|
||||
|
||||
var suggestedMaxRectHeight = Math.max(Math.min(ascent, descentLimit), 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;
|
||||
if (liftupUnderline) {
|
||||
if (r.height > suggestedMaxRectHeight) {
|
||||
r.height = Math.max(suggestedMaxRectHeight, lineHeight * 2.0 + 1.0);
|
||||
}
|
||||
}
|
||||
} else if (aStyle == kDecorationStyleWavy) {
|
||||
r.height = lineHeight > 2.0 ? lineHeight * 4.0 : lineHeight * 3.0;
|
||||
if (liftupUnderline) {
|
||||
descentLimit += lineHeight;
|
||||
suggestedMaxRectHeight = Math.max(Math.min(ascent, descentLimit), 1.0);
|
||||
if (r.height > suggestedMaxRectHeight) {
|
||||
r.height = Math.max(suggestedMaxRectHeight, lineHeight * 2.0);
|
||||
}
|
||||
}
|
||||
underlineOffsetAdjust = r.height / 2.0;
|
||||
}
|
||||
|
||||
@ -172,6 +194,13 @@ function getTextDecorationRect(aPt, aLineSize, aAscent, aOffset, aStyle)
|
||||
var offset = 0.0;
|
||||
|
||||
offset = aOffset + underlineOffsetAdjust;
|
||||
if (liftupUnderline) {
|
||||
if (descentLimit < -offset + r.height) {
|
||||
var offsetBottomAligned = -descentLimit + r.height;
|
||||
var offsetTopAligned = underlineOffsetAdjust;
|
||||
offset = Math.min(offsetBottomAligned, offsetTopAligned);
|
||||
}
|
||||
}
|
||||
|
||||
r.y = baseline - Math.floor(offset + 0.5);
|
||||
|
||||
|
@ -4098,6 +4098,7 @@ static void DrawSelectionDecorations(gfxContext* aContext, SelectionType aType,
|
||||
{
|
||||
gfxPoint pt(aPt);
|
||||
gfxSize size(aWidth, aFontMetrics.underlineSize);
|
||||
gfxFloat descentLimit = aFontMetrics.maxDescent;
|
||||
|
||||
switch (aType) {
|
||||
case nsISelectionController::SELECTION_IME_RAWINPUT:
|
||||
@ -4131,7 +4132,7 @@ static void DrawSelectionDecorations(gfxContext* aContext, SelectionType aType,
|
||||
size.height *= relativeSize;
|
||||
nsCSSRendering::PaintDecorationLine(
|
||||
aContext, color, pt, size, aAscent, aFontMetrics.underlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_UNDERLINE, style);
|
||||
NS_STYLE_TEXT_DECORATION_UNDERLINE, style, descentLimit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -4785,6 +4786,7 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
|
||||
const gfxFont::Metrics& metrics = firstFont->GetMetrics();
|
||||
gfxFloat underlineOffset = fontGroup->GetUnderlineOffset();
|
||||
gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(mAscent);
|
||||
gfxFloat descentLimit = metrics.maxDescent;
|
||||
|
||||
SelectionDetails *details = GetSelectionDetails();
|
||||
for (SelectionDetails *sd = details; sd; sd = sd->mNext) {
|
||||
@ -4808,7 +4810,7 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext, size,
|
||||
ascent, underlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_UNDERLINE,
|
||||
style);
|
||||
style, descentLimit);
|
||||
aRect.UnionRect(aRect, decorationArea);
|
||||
}
|
||||
DestroySelectionDetails(details);
|
||||
|
@ -65,12 +65,12 @@ const kIsLinux = navigator.platform.indexOf("Linux") == 0;
|
||||
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 }
|
||||
{ ascent: 13, offset: -2, lineHeight: 1, descentLimit: 3 },
|
||||
{ ascent: 17, offset: -2, lineHeight: 1, descentLimit: 5 },
|
||||
{ ascent: 26, offset: -4, lineHeight: 1, descentLimit: 6 },
|
||||
{ ascent: 34, offset: -4, lineHeight: 2, descentLimit: 10 },
|
||||
{ ascent: 42, offset: -7, lineHeight: 1, descentLimit: 10 },
|
||||
{ ascent: 56, offset: -7, lineHeight: 3, descentLimit: 17 }
|
||||
];
|
||||
}
|
||||
|
||||
@ -132,7 +132,8 @@ function drawSelectionDecorationLines(aDocument, aStyle, aRelativeSize)
|
||||
}
|
||||
drawDecorationLine(aDocument, underlineStyle.color, pt,
|
||||
{ width: width, height: fontMetrics.lineHeight * aRelativeSize },
|
||||
fontMetrics.ascent, fontMetrics.offset, aStyle);
|
||||
fontMetrics.ascent, fontMetrics.offset, aStyle,
|
||||
fontMetrics.descentLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user