diff --git a/dom/interfaces/css/nsIDOMCSS2Properties.idl b/dom/interfaces/css/nsIDOMCSS2Properties.idl index b205723658bb..e724f97a8998 100644 --- a/dom/interfaces/css/nsIDOMCSS2Properties.idl +++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl @@ -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 diff --git a/layout/base/nsStyleConsts.h b/layout/base/nsStyleConsts.h index 05517fc22067..a573cef188ef 100644 --- a/layout/base/nsStyleConsts.h +++ b/layout/base/nsStyleConsts.h @@ -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 diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index a59b3680ecc3..e814bf7fc986 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -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 diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index 03629902a0b7..f65e84ac4ffd 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -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, diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 050d98fad261..0ed709dcf6a6 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -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) { diff --git a/layout/generic/nsLineLayout.h b/layout/generic/nsLineLayout.h index 18075d695f72..e737c7e585c9 100644 --- a/layout/generic/nsLineLayout.h +++ b/layout/generic/nsLineLayout.h @@ -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); diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 8917c44f4d4c..88ca52f27659 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -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 = diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index 37e999204dee..bf11b1e3dba4 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -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, diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index ed74f91b54f1..15085985d7b7 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -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, diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h index 66b15c8f7ca0..14847c10c801 100644 --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -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[]; diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 05f234c05f89..4c63fdc9dd7c 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -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() { @@ -4575,6 +4585,7 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength) //// COMPUTED_STYLE_MAP_ENTRY(size, Size), COMPUTED_STYLE_MAP_ENTRY(table_layout, TableLayout), COMPUTED_STYLE_MAP_ENTRY(text_align, TextAlign), + COMPUTED_STYLE_MAP_ENTRY(text_align_last, TextAlignLast), COMPUTED_STYLE_MAP_ENTRY(text_decoration, TextDecoration), COMPUTED_STYLE_MAP_ENTRY_LAYOUT(text_indent, TextIndent), COMPUTED_STYLE_MAP_ENTRY(text_overflow, TextOverflow), diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 8b5615a306e7..a5637befb2bb 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -313,6 +313,7 @@ private: /* Text Properties */ nsIDOMCSSValue* DoGetLineHeight(); nsIDOMCSSValue* DoGetTextAlign(); + nsIDOMCSSValue* DoGetTextAlignLast(); nsIDOMCSSValue* DoGetMozTextBlink(); nsIDOMCSSValue* DoGetTextDecoration(); nsIDOMCSSValue* DoGetMozTextDecorationColor(); diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 51bc2bfab760..6c423f8d4cbf 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -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, diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 7638aa3ea15c..7039897b601d 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -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) || diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 44dd079cb791..0bee9312e303 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -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 diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index fea2ce581a78..036cf0af0c18 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -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,