Implement text-align-last. Bug 536557, r=dbaron

This commit is contained in:
Simon Montagu 2012-01-12 19:52:21 +02:00
parent 3840ddc646
commit 3ca7ecdbcb
16 changed files with 134 additions and 54 deletions

View File

@ -620,6 +620,9 @@ interface nsIDOMCSS2Properties : nsISupports
attribute DOMString outlineOffset;
// raises(DOMException) on setting
attribute DOMString MozTextAlignLast;
// raises(DOMException) on setting
/* Mozilla extensions */
attribute DOMString overflowX;
// raises(DOMException) on setting

View File

@ -625,12 +625,13 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_TEXT_ALIGN_JUSTIFY 4
#define NS_STYLE_TEXT_ALIGN_CHAR 5 //align based on a certain character, for table cell
#define NS_STYLE_TEXT_ALIGN_END 6
#define NS_STYLE_TEXT_ALIGN_MOZ_CENTER 7
#define NS_STYLE_TEXT_ALIGN_MOZ_RIGHT 8
#define NS_STYLE_TEXT_ALIGN_MOZ_LEFT 9
#define NS_STYLE_TEXT_ALIGN_AUTO 7
#define NS_STYLE_TEXT_ALIGN_MOZ_CENTER 8
#define NS_STYLE_TEXT_ALIGN_MOZ_RIGHT 9
#define NS_STYLE_TEXT_ALIGN_MOZ_LEFT 10
// NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT is only used in data structs; it
// is never present in stylesheets or computed data.
#define NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT 10
#define NS_STYLE_TEXT_ALIGN_MOZ_CENTER_OR_INHERIT 11
// Note: make sure that the largest NS_STYLE_TEXT_ALIGN_* value is smaller than
// the smallest NS_STYLE_VERTICAL_ALIGN_* value below!
@ -682,15 +683,15 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
// Note: these values pickup after the text-align values because there
// are a few html cases where an object can have both types of
// alignment applied with a single attribute
#define NS_STYLE_VERTICAL_ALIGN_BASELINE 11
#define NS_STYLE_VERTICAL_ALIGN_SUB 12
#define NS_STYLE_VERTICAL_ALIGN_SUPER 13
#define NS_STYLE_VERTICAL_ALIGN_TOP 14
#define NS_STYLE_VERTICAL_ALIGN_TEXT_TOP 15
#define NS_STYLE_VERTICAL_ALIGN_MIDDLE 16
#define NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM 17
#define NS_STYLE_VERTICAL_ALIGN_BOTTOM 18
#define NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE 19
#define NS_STYLE_VERTICAL_ALIGN_BASELINE 12
#define NS_STYLE_VERTICAL_ALIGN_SUB 13
#define NS_STYLE_VERTICAL_ALIGN_SUPER 14
#define NS_STYLE_VERTICAL_ALIGN_TOP 15
#define NS_STYLE_VERTICAL_ALIGN_TEXT_TOP 16
#define NS_STYLE_VERTICAL_ALIGN_MIDDLE 17
#define NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM 18
#define NS_STYLE_VERTICAL_ALIGN_BOTTOM 19
#define NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE 20
// See nsStyleVisibility
#define NS_STYLE_VISIBILITY_HIDDEN 0

View File

@ -4107,16 +4107,15 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
}
bool
nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState,
line_iterator aLine)
nsBlockFrame::IsLastLine(nsBlockReflowState& aState,
line_iterator aLine)
{
while (++aLine != end_lines()) {
// There is another line
if (0 != aLine->GetChildCount()) {
// If the next line is a block line then we must not justify
// this line because it means that this line is the last in a
// If the next line is a block line then this line is the last in a
// group of inline lines.
return !aLine->IsBlock();
return aLine->IsBlock();
}
// The next line is empty, try the next one
}
@ -4131,13 +4130,13 @@ nsBlockFrame::ShouldJustifyLine(nsBlockReflowState& aState,
++line)
{
if (0 != line->GetChildCount())
return !line->IsBlock();
return line->IsBlock();
}
nextInFlow = (nsBlockFrame*) nextInFlow->GetNextInFlow();
}
// This is the last line - so don't allow justification
return false;
return true;
}
bool
@ -4222,10 +4221,19 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
// inline frames "shrink-wrap" around their children (therefore
// there is no extra horizontal space).
const nsStyleText* styleText = GetStyleText();
bool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign &&
!aLineLayout.GetLineEndsInBR() &&
ShouldJustifyLine(aState, aLine);
aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify);
/**
* text-align-last defaults to the same value as text-align when
* text-align-last is set to auto (unless when text-align is set to justify),
* so in that case we don't need to set isLastLine.
*
* In other words, isLastLine really means isLastLineAndWeCare.
*/
bool isLastLine = ((NS_STYLE_TEXT_ALIGN_AUTO != styleText->mTextAlignLast ||
NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign) &&
(aLineLayout.GetLineEndsInBR() ||
IsLastLine(aState, aLine)));
aLineLayout.HorizontalAlignFrames(aLine->mBounds, isLastLine);
// XXX: not only bidi: right alignment can be broken after
// RelativePositionFrames!!!
// XXXldb Is something here considering relatively positioned frames at

View File

@ -530,8 +530,8 @@ protected:
const nsLineList* aLineList = nsnull);
// XXX where to go
bool ShouldJustifyLine(nsBlockReflowState& aState,
line_iterator aLine);
bool IsLastLine(nsBlockReflowState& aState,
line_iterator aLine);
void DeleteLine(nsBlockReflowState& aState,
nsLineList::iterator aLine,

View File

@ -113,7 +113,6 @@ nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
// Stash away some style data that we need
mStyleText = aOuterReflowState->frame->GetStyleText();
mTextAlign = mStyleText->mTextAlign;
mLineNumber = 0;
mFlags = 0; // default all flags to false except those that follow here...
mTotalPlacedFrames = 0;
@ -2493,8 +2492,12 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState
void
nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
bool aAllowJustify)
bool aIsLastLine)
{
/**
* NOTE: aIsLastLine ain't necessarily so: it is correctly set by caller
* only in cases where the last line needs special handling.
*/
PerSpanData* psd = mRootSpan;
NS_WARN_IF_FALSE(psd->mRightEdge != NS_UNCONSTRAINEDSIZE,
"have unconstrained width; this should only result from "
@ -2510,29 +2513,44 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
nscoord dx = 0;
if (remainingWidth > 0) {
switch (mTextAlign) {
case NS_STYLE_TEXT_ALIGN_JUSTIFY:
// If this is not the last line then go ahead and justify the
// frames in the line.
if (aAllowJustify) {
PRInt32 numSpaces;
PRInt32 numLetters;
ComputeJustificationWeights(psd, &numSpaces, &numLetters);
PRUint8 textAlign = mStyleText->mTextAlign;
if (numSpaces > 0) {
FrameJustificationState state =
{ numSpaces, numLetters, remainingWidth, 0, 0, 0, 0, 0 };
// Apply the justification, and make sure to update our linebox
// width to account for it.
aLineBounds.width += ApplyFrameJustification(psd, &state);
remainingWidth = availWidth - aLineBounds.width;
break;
}
/*
* 'text-align-last: auto' is equivalent to the value of the 'text-align'
* property except when 'text-align' is set to 'justify', in which case it
* is 'justify' when 'text-justify' is 'distribute' and 'start' otherwise.
*
* XXX: the code below will have to change when we implement text-justify
*/
if (aIsLastLine) {
if (mStyleText->mTextAlignLast == NS_STYLE_TEXT_ALIGN_AUTO) {
if (textAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY) {
textAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
}
// Fall through to the default case if we were told not to
// justify anything or could not justify to fill the space.
} else {
textAlign = mStyleText->mTextAlignLast;
}
}
switch (textAlign) {
case NS_STYLE_TEXT_ALIGN_JUSTIFY:
PRInt32 numSpaces;
PRInt32 numLetters;
ComputeJustificationWeights(psd, &numSpaces, &numLetters);
if (numSpaces > 0) {
FrameJustificationState state =
{ numSpaces, numLetters, remainingWidth, 0, 0, 0, 0, 0 };
// Apply the justification, and make sure to update our linebox
// width to account for it.
aLineBounds.width += ApplyFrameJustification(psd, &state);
remainingWidth = availWidth - aLineBounds.width;
break;
}
// Fall through to the default case if we could not justify to fill
// the space.
case NS_STYLE_TEXT_ALIGN_DEFAULT:
if (NS_STYLE_DIRECTION_LTR == psd->mDirection) {

View File

@ -134,7 +134,7 @@ public:
bool TrimTrailingWhiteSpace();
void HorizontalAlignFrames(nsRect& aLineBounds, bool aAllowJustify);
void HorizontalAlignFrames(nsRect& aLineBounds, bool aIsLastLine);
/**
* Handle all the relative positioning in the line, compute the
@ -568,8 +568,6 @@ protected:
PRUint32 mFlags;
PRUint8 mTextAlign;
nsresult NewPerFrameData(PerFrameData** aResult);
nsresult NewPerSpanData(PerSpanData** aResult);

View File

@ -1765,7 +1765,8 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
PRUint32 nextBreakIndex = 0;
nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex);
bool enabledJustification = mLineContainer &&
mLineContainer->GetStyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY;
(mLineContainer->GetStyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
mLineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY);
PRUint32 i;
const nsStyleText* textStyle = nsnull;
@ -7674,7 +7675,8 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
// Compute space and letter counts for justification, if required
if (!textStyle->WhiteSpaceIsSignificant() &&
lineContainer->GetStyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY) {
(lineContainer->GetStyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
lineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY)) {
AddStateBits(TEXT_JUSTIFICATION_ENABLED); // This will include a space for trailing whitespace, if any is present.
// This is corrected for in nsLineLayout::TrimWhiteSpaceIn.
PRInt32 numJustifiableCharacters =

View File

@ -2208,6 +2208,15 @@ CSS_PROP_TEXT(
kTextAlignKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_TEXT(
-moz-text-align-last,
text_align_last,
CSS_PROP_DOMPROP_PREFIXED(TextAlignLast),
CSS_PROPERTY_PARSE_VALUE,
VARIANT_HK,
kTextAlignLastKTable,
offsetof(nsStyleText, mTextAlignLast),
eStyleAnimType_None)
CSS_PROP_SHORTHAND(
text-decoration,
text_decoration,

View File

@ -1200,6 +1200,17 @@ const PRInt32 nsCSSProps::kTextAlignKTable[] = {
eCSSKeyword_UNKNOWN,-1
};
const PRInt32 nsCSSProps::kTextAlignLastKTable[] = {
eCSSKeyword_auto, NS_STYLE_TEXT_ALIGN_AUTO,
eCSSKeyword_left, NS_STYLE_TEXT_ALIGN_LEFT,
eCSSKeyword_right, NS_STYLE_TEXT_ALIGN_RIGHT,
eCSSKeyword_center, NS_STYLE_TEXT_ALIGN_CENTER,
eCSSKeyword_justify, NS_STYLE_TEXT_ALIGN_JUSTIFY,
eCSSKeyword_start, NS_STYLE_TEXT_ALIGN_DEFAULT,
eCSSKeyword_end, NS_STYLE_TEXT_ALIGN_END,
eCSSKeyword_UNKNOWN,-1
};
const PRInt32 nsCSSProps::kTextBlinkKTable[] = {
eCSSKeyword_none, NS_STYLE_TEXT_BLINK_NONE,
eCSSKeyword_blink, NS_STYLE_TEXT_BLINK_BLINK,

View File

@ -408,6 +408,7 @@ public:
static const PRInt32 kStackSizingKTable[];
static const PRInt32 kTableLayoutKTable[];
static const PRInt32 kTextAlignKTable[];
static const PRInt32 kTextAlignLastKTable[];
static const PRInt32 kTextBlinkKTable[];
static const PRInt32 kTextDecorationLineKTable[];
static const PRInt32 kTextDecorationStyleKTable[];

View File

@ -2401,6 +2401,16 @@ nsComputedDOMStyle::DoGetTextAlign()
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetTextAlignLast()
{
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(GetStyleText()->mTextAlignLast,
nsCSSProps::kTextAlignLastKTable));
return val;
}
nsIDOMCSSValue*
nsComputedDOMStyle::DoGetMozTextBlink()
{
@ -4647,6 +4657,7 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength)
COMPUTED_STYLE_MAP_ENTRY_LAYOUT(perspective_origin, MozPerspectiveOrigin),
COMPUTED_STYLE_MAP_ENTRY(stack_sizing, StackSizing),
COMPUTED_STYLE_MAP_ENTRY(_moz_tab_size, MozTabSize),
COMPUTED_STYLE_MAP_ENTRY(text_align_last, TextAlignLast),
COMPUTED_STYLE_MAP_ENTRY(text_blink, MozTextBlink),
COMPUTED_STYLE_MAP_ENTRY(text_decoration_color, MozTextDecorationColor),
COMPUTED_STYLE_MAP_ENTRY(text_decoration_line, MozTextDecorationLine),

View File

@ -313,6 +313,7 @@ private:
/* Text Properties */
nsIDOMCSSValue* DoGetLineHeight();
nsIDOMCSSValue* DoGetTextAlign();
nsIDOMCSSValue* DoGetTextAlignLast();
nsIDOMCSSValue* DoGetMozTextBlink();
nsIDOMCSSValue* DoGetTextDecoration();
nsIDOMCSSValue* DoGetMozTextDecorationColor();

View File

@ -3365,6 +3365,11 @@ nsRuleNode::ComputeTextData(void* aStartStruct,
NS_STYLE_TEXT_ALIGN_DEFAULT,
0, 0, 0, 0);
// text-align-last: enum, inherit, initial
SetDiscrete(*aRuleData->ValueForTextAlignLast(), text->mTextAlignLast,
canStoreInRuleTree, SETDSC_ENUMERATED, parentText->mTextAlignLast,
NS_STYLE_TEXT_ALIGN_AUTO, 0, 0, 0, 0);
// text-indent: length, percent, calc, inherit, initial
SetCoord(*aRuleData->ValueForTextIndent(), text->mTextIndent, parentText->mTextIndent,
SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,

View File

@ -2814,6 +2814,7 @@ nsStyleText::nsStyleText(void)
{
MOZ_COUNT_CTOR(nsStyleText);
mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
mTextAlignLast = NS_STYLE_TEXT_ALIGN_AUTO;
mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
@ -2831,6 +2832,7 @@ nsStyleText::nsStyleText(void)
nsStyleText::nsStyleText(const nsStyleText& aSource)
: mTextAlign(aSource.mTextAlign),
mTextAlignLast(aSource.mTextAlignLast),
mTextTransform(aSource.mTextTransform),
mWhiteSpace(aSource.mWhiteSpace),
mWordWrap(aSource.mWordWrap),
@ -2859,6 +2861,7 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
}
if ((mTextAlign != aOther.mTextAlign) ||
(mTextAlignLast != aOther.mTextAlignLast) ||
(mTextTransform != aOther.mTextTransform) ||
(mWhiteSpace != aOther.mWhiteSpace) ||
(mWordWrap != aOther.mWordWrap) ||

View File

@ -1277,6 +1277,7 @@ struct nsStyleText {
static bool ForceCompare() { return false; }
PRUint8 mTextAlign; // [inherited] see nsStyleConsts.h
PRUint8 mTextAlignLast; // [inherited] see nsStyleConsts.h
PRUint8 mTextTransform; // [inherited] see nsStyleConsts.h
PRUint8 mWhiteSpace; // [inherited] see nsStyleConsts.h
PRUint8 mWordWrap; // [inherited] see nsStyleConsts.h

View File

@ -2646,6 +2646,14 @@ var gCSSProperties = {
other_values: [ "center", "justify", "end" ],
invalid_values: []
},
"-moz-text-align-last": {
domProp: "MozTextAlignLast",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "auto" ],
other_values: [ "center", "justify", "start", "end", "left", "right" ],
invalid_values: []
},
"-moz-text-blink": {
domProp: "MozTextBlink",
inherited: false,