Bug 1852478 - Convert CSS white-space into a shorthand that expands to white-space-collapse and text-wrap-mode longhands. r=firefox-style-system-reviewers,emilio
Note that although this builds, it would (by itself) result in some test breakage; this is resolved in the following patches that build on this. Differential Revision: https://phabricator.services.mozilla.com/D198790
This commit is contained in:
@@ -39267,6 +39267,7 @@ use.counter.css.doc:
|
|||||||
send_in_pings:
|
send_in_pings:
|
||||||
- use-counters
|
- use-counters
|
||||||
|
|
||||||
|
|
||||||
webkit_column_rule_color:
|
webkit_column_rule_color:
|
||||||
type: counter
|
type: counter
|
||||||
description: >
|
description: >
|
||||||
|
|||||||
@@ -38,8 +38,11 @@ void HTMLPreElement::MapAttributesIntoRule(
|
|||||||
MappedDeclarationsBuilder& aBuilder) {
|
MappedDeclarationsBuilder& aBuilder) {
|
||||||
// wrap: empty
|
// wrap: empty
|
||||||
if (aBuilder.GetAttr(nsGkAtoms::wrap)) {
|
if (aBuilder.GetAttr(nsGkAtoms::wrap)) {
|
||||||
aBuilder.SetKeywordValue(eCSSProperty_white_space,
|
// Equivalent to expanding `white-space: pre-wrap`
|
||||||
StyleWhiteSpace::PreWrap);
|
aBuilder.SetKeywordValue(eCSSProperty_white_space_collapse,
|
||||||
|
StyleWhiteSpaceCollapse::Preserve);
|
||||||
|
aBuilder.SetKeywordValue(eCSSProperty_text_wrap_mode,
|
||||||
|
StyleTextWrapMode::Wrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsGenericHTMLElement::MapCommonAttributesInto(aBuilder);
|
nsGenericHTMLElement::MapCommonAttributesInto(aBuilder);
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ void HTMLTableCellElement::MapAttributesIntoRule(
|
|||||||
MappedDeclarationsBuilder& aBuilder) {
|
MappedDeclarationsBuilder& aBuilder) {
|
||||||
MapImageSizeAttributesInto(aBuilder);
|
MapImageSizeAttributesInto(aBuilder);
|
||||||
|
|
||||||
if (!aBuilder.PropertyIsSet(eCSSProperty_white_space)) {
|
if (!aBuilder.PropertyIsSet(eCSSProperty_text_wrap_mode)) {
|
||||||
// nowrap: enum
|
// nowrap: enum
|
||||||
if (aBuilder.GetAttr(nsGkAtoms::nowrap)) {
|
if (aBuilder.GetAttr(nsGkAtoms::nowrap)) {
|
||||||
// See if our width is not a nonzero integer width.
|
// See if our width is not a nonzero integer width.
|
||||||
@@ -171,8 +171,8 @@ void HTMLTableCellElement::MapAttributesIntoRule(
|
|||||||
nsCompatibility mode = aBuilder.Document().GetCompatibilityMode();
|
nsCompatibility mode = aBuilder.Document().GetCompatibilityMode();
|
||||||
if (!value || value->Type() != nsAttrValue::eInteger ||
|
if (!value || value->Type() != nsAttrValue::eInteger ||
|
||||||
value->GetIntegerValue() == 0 || eCompatibility_NavQuirks != mode) {
|
value->GetIntegerValue() == 0 || eCompatibility_NavQuirks != mode) {
|
||||||
aBuilder.SetKeywordValue(eCSSProperty_white_space,
|
aBuilder.SetKeywordValue(eCSSProperty_text_wrap_mode,
|
||||||
StyleWhiteSpace::Nowrap);
|
StyleTextWrapMode::Nowrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,12 +365,14 @@ bool HTMLTextAreaElement::ParseAttribute(int32_t aNamespaceID,
|
|||||||
void HTMLTextAreaElement::MapAttributesIntoRule(
|
void HTMLTextAreaElement::MapAttributesIntoRule(
|
||||||
MappedDeclarationsBuilder& aBuilder) {
|
MappedDeclarationsBuilder& aBuilder) {
|
||||||
// wrap=off
|
// wrap=off
|
||||||
if (!aBuilder.PropertyIsSet(eCSSProperty_white_space)) {
|
const nsAttrValue* value = aBuilder.GetAttr(nsGkAtoms::wrap);
|
||||||
const nsAttrValue* value = aBuilder.GetAttr(nsGkAtoms::wrap);
|
if (value && value->Type() == nsAttrValue::eString &&
|
||||||
if (value && value->Type() == nsAttrValue::eString &&
|
value->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
|
||||||
value->Equals(nsGkAtoms::OFF, eIgnoreCase)) {
|
// Equivalent to expanding `white-space; pre`
|
||||||
aBuilder.SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Pre);
|
aBuilder.SetKeywordValue(eCSSProperty_white_space_collapse,
|
||||||
}
|
StyleWhiteSpaceCollapse::Preserve);
|
||||||
|
aBuilder.SetKeywordValue(eCSSProperty_text_wrap_mode,
|
||||||
|
StyleTextWrapMode::Nowrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsGenericHTMLFormControlElementWithState::MapDivAlignAttributeInto(aBuilder);
|
nsGenericHTMLFormControlElementWithState::MapDivAlignAttributeInto(aBuilder);
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ bool EditorUtils::IsDescendantOf(const nsINode& aNode, const nsINode& aParent,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Maybe<StyleWhiteSpace> EditorUtils::GetComputedWhiteSpaceStyle(
|
Maybe<std::pair<StyleWhiteSpaceCollapse, StyleTextWrapMode>>
|
||||||
const nsIContent& aContent) {
|
EditorUtils::GetComputedWhiteSpaceStyles(const nsIContent& aContent) {
|
||||||
if (MOZ_UNLIKELY(!aContent.IsElement() && !aContent.GetParentElement())) {
|
if (MOZ_UNLIKELY(!aContent.IsElement() && !aContent.GetParentElement())) {
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,9 @@ Maybe<StyleWhiteSpace> EditorUtils::GetComputedWhiteSpaceStyle(
|
|||||||
if (NS_WARN_IF(!elementStyle)) {
|
if (NS_WARN_IF(!elementStyle)) {
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
return Some(elementStyle->StyleText()->mWhiteSpace);
|
const auto* styleText = elementStyle->StyleText();
|
||||||
|
return Some(
|
||||||
|
std::pair(styleText->mWhiteSpaceCollapse, styleText->mTextWrapMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@@ -164,7 +166,8 @@ bool EditorUtils::IsOnlyNewLinePreformatted(const nsIContent& aContent) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return elementStyle->StyleText()->mWhiteSpace == StyleWhiteSpace::PreLine;
|
return elementStyle->StyleText()->mWhiteSpaceCollapse ==
|
||||||
|
StyleWhiteSpaceCollapse::PreserveBreaks;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|||||||
@@ -401,10 +401,10 @@ class EditorUtils final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get computed white-space style of aContent.
|
* Get the two longhands that make up computed white-space style of aContent.
|
||||||
*/
|
*/
|
||||||
static Maybe<StyleWhiteSpace> GetComputedWhiteSpaceStyle(
|
static Maybe<std::pair<StyleWhiteSpaceCollapse, StyleTextWrapMode>>
|
||||||
const nsIContent& aContent);
|
GetComputedWhiteSpaceStyles(const nsIContent& aContent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IsWhiteSpacePreformatted() checks the style info for the node for the
|
* IsWhiteSpacePreformatted() checks the style info for the node for the
|
||||||
@@ -421,7 +421,7 @@ class EditorUtils final {
|
|||||||
/**
|
/**
|
||||||
* IsOnlyNewLinePreformatted() checks whether the linefeed characters are
|
* IsOnlyNewLinePreformatted() checks whether the linefeed characters are
|
||||||
* preformated but white-spaces are collapsed, or otherwise. I.e., this
|
* preformated but white-spaces are collapsed, or otherwise. I.e., this
|
||||||
* returns true only when `white-space:pre-line`.
|
* returns true only when `white-space-collapse:pre-line`.
|
||||||
*/
|
*/
|
||||||
static bool IsOnlyNewLinePreformatted(const nsIContent& aContent);
|
static bool IsOnlyNewLinePreformatted(const nsIContent& aContent);
|
||||||
|
|
||||||
|
|||||||
@@ -5353,8 +5353,10 @@ HTMLEditor::AutoMoveOneLineHandler::ConsiderWhetherPreserveWhiteSpaceStyle(
|
|||||||
// If the content has different `white-space` style from <pre>, we
|
// If the content has different `white-space` style from <pre>, we
|
||||||
// shouldn't treat it as a descendant of <pre> because web apps or
|
// shouldn't treat it as a descendant of <pre> because web apps or
|
||||||
// the user intent to treat the white-spaces in aContent not as `pre`.
|
// the user intent to treat the white-spaces in aContent not as `pre`.
|
||||||
if (EditorUtils::GetComputedWhiteSpaceStyle(aContent).valueOr(
|
if (EditorUtils::GetComputedWhiteSpaceStyles(aContent).valueOr(std::pair(
|
||||||
StyleWhiteSpace::Normal) != StyleWhiteSpace::Pre) {
|
StyleWhiteSpaceCollapse::Collapse, StyleTextWrapMode::Wrap)) !=
|
||||||
|
std::pair(StyleWhiteSpaceCollapse::Preserve,
|
||||||
|
StyleTextWrapMode::Nowrap)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const Element* element :
|
for (const Element* element :
|
||||||
@@ -5801,52 +5803,67 @@ Result<MoveNodeResult, nsresult> HTMLEditor::MoveNodeOrChildrenWithTransaction(
|
|||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
MOZ_ASSERT(aPointToInsert.IsInContentNode());
|
MOZ_ASSERT(aPointToInsert.IsInContentNode());
|
||||||
|
|
||||||
const auto destWhiteSpaceStyle = [&]() -> Maybe<StyleWhiteSpace> {
|
const auto destWhiteSpaceStyles =
|
||||||
|
[&]() -> Maybe<std::pair<StyleWhiteSpaceCollapse, StyleTextWrapMode>> {
|
||||||
if (aPreserveWhiteSpaceStyle == PreserveWhiteSpaceStyle::No ||
|
if (aPreserveWhiteSpaceStyle == PreserveWhiteSpaceStyle::No ||
|
||||||
!aPointToInsert.IsInContentNode()) {
|
!aPointToInsert.IsInContentNode()) {
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
auto style = EditorUtils::GetComputedWhiteSpaceStyle(
|
auto styles = EditorUtils::GetComputedWhiteSpaceStyles(
|
||||||
*aPointToInsert.ContainerAs<nsIContent>());
|
*aPointToInsert.ContainerAs<nsIContent>());
|
||||||
if (NS_WARN_IF(style.isSome() &&
|
if (NS_WARN_IF(styles.isSome() &&
|
||||||
style.value() == StyleWhiteSpace::PreSpace)) {
|
styles.value().first ==
|
||||||
|
StyleWhiteSpaceCollapse::PreserveSpaces)) {
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
return style;
|
return styles;
|
||||||
}();
|
}();
|
||||||
const auto srcWhiteSpaceStyle = [&]() -> Maybe<StyleWhiteSpace> {
|
const auto srcWhiteSpaceStyles =
|
||||||
|
[&]() -> Maybe<std::pair<StyleWhiteSpaceCollapse, StyleTextWrapMode>> {
|
||||||
if (aPreserveWhiteSpaceStyle == PreserveWhiteSpaceStyle::No) {
|
if (aPreserveWhiteSpaceStyle == PreserveWhiteSpaceStyle::No) {
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
auto style = EditorUtils::GetComputedWhiteSpaceStyle(aContentToMove);
|
auto styles = EditorUtils::GetComputedWhiteSpaceStyles(aContentToMove);
|
||||||
if (NS_WARN_IF(style.isSome() &&
|
if (NS_WARN_IF(styles.isSome() &&
|
||||||
style.value() == StyleWhiteSpace::PreSpace)) {
|
styles.value().first ==
|
||||||
|
StyleWhiteSpaceCollapse::PreserveSpaces)) {
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
return style;
|
return styles;
|
||||||
}();
|
}();
|
||||||
const auto GetWhiteSpaceStyleValue = [](StyleWhiteSpace aStyleWhiteSpace) {
|
// Get the `white-space` shorthand form for the given collapse + mode pair.
|
||||||
switch (aStyleWhiteSpace) {
|
const auto GetWhiteSpaceStyleValue =
|
||||||
case StyleWhiteSpace::Normal:
|
[](std::pair<StyleWhiteSpaceCollapse, StyleTextWrapMode> aStyles) {
|
||||||
|
if (aStyles.second == StyleTextWrapMode::Wrap) {
|
||||||
|
switch (aStyles.first) {
|
||||||
|
case StyleWhiteSpaceCollapse::Collapse:
|
||||||
|
return u"normal"_ns;
|
||||||
|
case StyleWhiteSpaceCollapse::Preserve:
|
||||||
|
return u"pre-wrap"_ns;
|
||||||
|
case StyleWhiteSpaceCollapse::PreserveBreaks:
|
||||||
|
return u"pre-line"_ns;
|
||||||
|
case StyleWhiteSpaceCollapse::PreserveSpaces:
|
||||||
|
return u"preserve-spaces"_ns;
|
||||||
|
case StyleWhiteSpaceCollapse::BreakSpaces:
|
||||||
|
return u"break-spaces"_ns;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (aStyles.first) {
|
||||||
|
case StyleWhiteSpaceCollapse::Collapse:
|
||||||
|
return u"nowrap"_ns;
|
||||||
|
case StyleWhiteSpaceCollapse::Preserve:
|
||||||
|
return u"pre"_ns;
|
||||||
|
case StyleWhiteSpaceCollapse::PreserveBreaks:
|
||||||
|
return u"nowrap preserve-breaks"_ns;
|
||||||
|
case StyleWhiteSpaceCollapse::PreserveSpaces:
|
||||||
|
return u"nowrap preserve-spaces"_ns;
|
||||||
|
case StyleWhiteSpaceCollapse::BreakSpaces:
|
||||||
|
return u"nowrap break-spaces"_ns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MOZ_ASSERT_UNREACHABLE("all values should be handled above!");
|
||||||
return u"normal"_ns;
|
return u"normal"_ns;
|
||||||
case StyleWhiteSpace::Pre:
|
};
|
||||||
return u"pre"_ns;
|
|
||||||
case StyleWhiteSpace::Nowrap:
|
|
||||||
return u"nowrap"_ns;
|
|
||||||
case StyleWhiteSpace::PreWrap:
|
|
||||||
return u"pre-wrap"_ns;
|
|
||||||
case StyleWhiteSpace::PreLine:
|
|
||||||
return u"pre-line"_ns;
|
|
||||||
case StyleWhiteSpace::BreakSpaces:
|
|
||||||
return u"break-spaces"_ns;
|
|
||||||
case StyleWhiteSpace::PreSpace:
|
|
||||||
MOZ_ASSERT_UNREACHABLE("Don't handle -moz-pre-space");
|
|
||||||
return u""_ns;
|
|
||||||
default:
|
|
||||||
MOZ_ASSERT_UNREACHABLE("Handle the new white-space value");
|
|
||||||
return u""_ns;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (aRemoveIfCommentNode == RemoveIfCommentNode::Yes &&
|
if (aRemoveIfCommentNode == RemoveIfCommentNode::Yes &&
|
||||||
aContentToMove.IsComment()) {
|
aContentToMove.IsComment()) {
|
||||||
@@ -5872,15 +5889,15 @@ Result<MoveNodeResult, nsresult> HTMLEditor::MoveNodeOrChildrenWithTransaction(
|
|||||||
// Preserve white-space in the new position with using `style` attribute.
|
// Preserve white-space in the new position with using `style` attribute.
|
||||||
// This is additional path from point of view of our traditional behavior.
|
// This is additional path from point of view of our traditional behavior.
|
||||||
// Therefore, ignore errors especially if we got unexpected DOM tree.
|
// Therefore, ignore errors especially if we got unexpected DOM tree.
|
||||||
if (destWhiteSpaceStyle.isSome() && srcWhiteSpaceStyle.isSome() &&
|
if (destWhiteSpaceStyles.isSome() && srcWhiteSpaceStyles.isSome() &&
|
||||||
destWhiteSpaceStyle.value() != srcWhiteSpaceStyle.value()) {
|
destWhiteSpaceStyles.value() != srcWhiteSpaceStyles.value()) {
|
||||||
// Set `white-space` with `style` attribute if it's nsStyledElement.
|
// Set `white-space` with `style` attribute if it's nsStyledElement.
|
||||||
if (nsStyledElement* styledElement =
|
if (nsStyledElement* styledElement =
|
||||||
nsStyledElement::FromNode(&aContentToMove)) {
|
nsStyledElement::FromNode(&aContentToMove)) {
|
||||||
DebugOnly<nsresult> rvIgnored =
|
DebugOnly<nsresult> rvIgnored =
|
||||||
CSSEditUtils::SetCSSPropertyWithTransaction(
|
CSSEditUtils::SetCSSPropertyWithTransaction(
|
||||||
*this, MOZ_KnownLive(*styledElement), *nsGkAtoms::white_space,
|
*this, MOZ_KnownLive(*styledElement), *nsGkAtoms::white_space,
|
||||||
GetWhiteSpaceStyleValue(srcWhiteSpaceStyle.value()));
|
GetWhiteSpaceStyleValue(srcWhiteSpaceStyles.value()));
|
||||||
if (NS_WARN_IF(Destroyed())) {
|
if (NS_WARN_IF(Destroyed())) {
|
||||||
return Err(NS_ERROR_EDITOR_DESTROYED);
|
return Err(NS_ERROR_EDITOR_DESTROYED);
|
||||||
}
|
}
|
||||||
@@ -5900,7 +5917,7 @@ Result<MoveNodeResult, nsresult> HTMLEditor::MoveNodeOrChildrenWithTransaction(
|
|||||||
}
|
}
|
||||||
nsAutoString styleAttrValue(u"white-space: "_ns);
|
nsAutoString styleAttrValue(u"white-space: "_ns);
|
||||||
styleAttrValue.Append(
|
styleAttrValue.Append(
|
||||||
GetWhiteSpaceStyleValue(srcWhiteSpaceStyle.value()));
|
GetWhiteSpaceStyleValue(srcWhiteSpaceStyles.value()));
|
||||||
IgnoredErrorResult error;
|
IgnoredErrorResult error;
|
||||||
newSpanElement->SetAttr(nsGkAtoms::style, styleAttrValue, error);
|
newSpanElement->SetAttr(nsGkAtoms::style, styleAttrValue, error);
|
||||||
NS_WARNING_ASSERTION(!error.Failed(),
|
NS_WARNING_ASSERTION(!error.Failed(),
|
||||||
|
|||||||
@@ -724,8 +724,8 @@ Result<EditActionResult, nsresult> WhiteSpaceVisibilityKeeper::
|
|||||||
// a bug to manage only the change.
|
// a bug to manage only the change.
|
||||||
(aLeftBlockElement.NodeInfo()->NameAtom() ==
|
(aLeftBlockElement.NodeInfo()->NameAtom() ==
|
||||||
aRightBlockElement.NodeInfo()->NameAtom() &&
|
aRightBlockElement.NodeInfo()->NameAtom() &&
|
||||||
EditorUtils::GetComputedWhiteSpaceStyle(aLeftBlockElement) ==
|
EditorUtils::GetComputedWhiteSpaceStyles(aLeftBlockElement) ==
|
||||||
EditorUtils::GetComputedWhiteSpaceStyle(aRightBlockElement))) {
|
EditorUtils::GetComputedWhiteSpaceStyles(aRightBlockElement))) {
|
||||||
// Nodes are same type. merge them.
|
// Nodes are same type. merge them.
|
||||||
EditorDOMPoint atFirstChildOfRightNode;
|
EditorDOMPoint atFirstChildOfRightNode;
|
||||||
nsresult rv = aHTMLEditor.JoinNearestEditableNodesWithTransaction(
|
nsresult rv = aHTMLEditor.JoinNearestEditableNodesWithTransaction(
|
||||||
|
|||||||
@@ -9128,8 +9128,8 @@ nsresult nsIFrame::PeekOffsetForWord(PeekOffsetStruct* aPos, int32_t aOffset) {
|
|||||||
// significant.
|
// significant.
|
||||||
if (next.mJumpedLine && wordSelectEatSpace &&
|
if (next.mJumpedLine && wordSelectEatSpace &&
|
||||||
current.mFrame->HasSignificantTerminalNewline() &&
|
current.mFrame->HasSignificantTerminalNewline() &&
|
||||||
current.mFrame->StyleText()->mWhiteSpace !=
|
current.mFrame->StyleText()->mWhiteSpaceCollapse !=
|
||||||
StyleWhiteSpace::PreLine) {
|
StyleWhiteSpaceCollapse::PreserveBreaks) {
|
||||||
current.mOffset -= 1;
|
current.mOffset -= 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -781,7 +781,8 @@ static bool IsTrimmableSpace(const nsTextFragment* aFrag, uint32_t aPos,
|
|||||||
!IsSpaceCombiningSequenceTail(aFrag, aPos + 1);
|
!IsSpaceCombiningSequenceTail(aFrag, aPos + 1);
|
||||||
case '\n':
|
case '\n':
|
||||||
return !aStyleText->NewlineIsSignificantStyle() &&
|
return !aStyleText->NewlineIsSignificantStyle() &&
|
||||||
aStyleText->mWhiteSpace != mozilla::StyleWhiteSpace::PreSpace;
|
aStyleText->mWhiteSpaceCollapse !=
|
||||||
|
StyleWhiteSpaceCollapse::PreserveSpaces;
|
||||||
case '\t':
|
case '\t':
|
||||||
case '\r':
|
case '\r':
|
||||||
case '\f':
|
case '\f':
|
||||||
@@ -1171,27 +1172,23 @@ static bool TextContainsLineBreakerWhiteSpace(const void* aText,
|
|||||||
|
|
||||||
static nsTextFrameUtils::CompressionMode GetCSSWhitespaceToCompressionMode(
|
static nsTextFrameUtils::CompressionMode GetCSSWhitespaceToCompressionMode(
|
||||||
nsTextFrame* aFrame, const nsStyleText* aStyleText) {
|
nsTextFrame* aFrame, const nsStyleText* aStyleText) {
|
||||||
switch (aStyleText->mWhiteSpace) {
|
switch (aStyleText->mWhiteSpaceCollapse) {
|
||||||
case StyleWhiteSpace::Normal:
|
case StyleWhiteSpaceCollapse::Collapse:
|
||||||
case StyleWhiteSpace::Nowrap:
|
|
||||||
return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
|
return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
|
||||||
case StyleWhiteSpace::Pre:
|
case StyleWhiteSpaceCollapse::PreserveBreaks:
|
||||||
case StyleWhiteSpace::PreWrap:
|
return nsTextFrameUtils::COMPRESS_WHITESPACE;
|
||||||
case StyleWhiteSpace::BreakSpaces:
|
case StyleWhiteSpaceCollapse::Preserve:
|
||||||
|
case StyleWhiteSpaceCollapse::PreserveSpaces:
|
||||||
|
case StyleWhiteSpaceCollapse::BreakSpaces:
|
||||||
if (!aStyleText->NewlineIsSignificant(aFrame)) {
|
if (!aStyleText->NewlineIsSignificant(aFrame)) {
|
||||||
// If newline is set to be preserved, but then suppressed,
|
// If newline is set to be preserved, but then suppressed,
|
||||||
// transform newline to space.
|
// transform newline to space.
|
||||||
return nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE;
|
return nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE;
|
||||||
}
|
}
|
||||||
return nsTextFrameUtils::COMPRESS_NONE;
|
return nsTextFrameUtils::COMPRESS_NONE;
|
||||||
case StyleWhiteSpace::PreSpace:
|
|
||||||
return nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE;
|
|
||||||
case StyleWhiteSpace::PreLine:
|
|
||||||
return nsTextFrameUtils::COMPRESS_WHITESPACE;
|
|
||||||
default:
|
|
||||||
MOZ_ASSERT_UNREACHABLE("Unknown white-space value");
|
|
||||||
return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
|
|
||||||
}
|
}
|
||||||
|
MOZ_ASSERT_UNREACHABLE("Unknown white-space-collapse value");
|
||||||
|
return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FrameTextTraversal {
|
struct FrameTextTraversal {
|
||||||
@@ -9539,7 +9536,8 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||||||
}
|
}
|
||||||
bool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() ||
|
bool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() ||
|
||||||
HasAnyStateBits(TEXT_IS_IN_TOKEN_MATHML);
|
HasAnyStateBits(TEXT_IS_IN_TOKEN_MATHML);
|
||||||
bool isBreakSpaces = textStyle->mWhiteSpace == StyleWhiteSpace::BreakSpaces;
|
bool isBreakSpaces =
|
||||||
|
textStyle->mWhiteSpaceCollapse == StyleWhiteSpaceCollapse::BreakSpaces;
|
||||||
// allow whitespace to overflow the container
|
// allow whitespace to overflow the container
|
||||||
bool whitespaceCanHang = textStyle->WhiteSpaceCanHangOrVisuallyCollapse();
|
bool whitespaceCanHang = textStyle->WhiteSpaceCanHangOrVisuallyCollapse();
|
||||||
gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority();
|
gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority();
|
||||||
@@ -10307,9 +10305,9 @@ bool nsTextFrame::IsEmpty() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEmpty =
|
bool isEmpty = IsAllWhitespace(TextFragment(),
|
||||||
IsAllWhitespace(TextFragment(), textStyle->mWhiteSpace !=
|
textStyle->mWhiteSpaceCollapse !=
|
||||||
mozilla::StyleWhiteSpace::PreLine);
|
StyleWhiteSpaceCollapse::PreserveBreaks);
|
||||||
AddStateBits(isEmpty ? TEXT_IS_ONLY_WHITESPACE : TEXT_ISNOT_ONLY_WHITESPACE);
|
AddStateBits(isEmpty ? TEXT_IS_ONLY_WHITESPACE : TEXT_ISNOT_ONLY_WHITESPACE);
|
||||||
return isEmpty;
|
return isEmpty;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,8 @@ rusty-enums = [
|
|||||||
"mozilla::StyleListStylePosition",
|
"mozilla::StyleListStylePosition",
|
||||||
"mozilla::StylePointerEvents",
|
"mozilla::StylePointerEvents",
|
||||||
"mozilla::StyleScrollbarWidth",
|
"mozilla::StyleScrollbarWidth",
|
||||||
"mozilla::StyleWhiteSpace",
|
"mozilla::StyleWhiteSpaceCollapse",
|
||||||
|
"mozilla::StyleTextWrapMode",
|
||||||
"mozilla::StyleTextRendering",
|
"mozilla::StyleTextRendering",
|
||||||
"mozilla::StyleFlexDirection",
|
"mozilla::StyleFlexDirection",
|
||||||
"mozilla::StyleStrokeLinecap",
|
"mozilla::StyleStrokeLinecap",
|
||||||
|
|||||||
@@ -389,16 +389,21 @@ enum class StyleVisibility : uint8_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// See nsStyleText
|
// See nsStyleText
|
||||||
enum class StyleWhiteSpace : uint8_t {
|
enum class StyleWhiteSpaceCollapse : uint8_t {
|
||||||
Normal = 0,
|
Collapse = 0,
|
||||||
Pre,
|
// TODO: Discard not yet supported
|
||||||
Nowrap,
|
Preserve,
|
||||||
PreWrap,
|
PreserveBreaks,
|
||||||
PreLine,
|
PreserveSpaces,
|
||||||
PreSpace,
|
|
||||||
BreakSpaces,
|
BreakSpaces,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// See nsStyleText
|
||||||
|
enum class StyleTextWrapMode : uint8_t {
|
||||||
|
Wrap = 0,
|
||||||
|
Nowrap,
|
||||||
|
};
|
||||||
|
|
||||||
// See nsStyleText
|
// See nsStyleText
|
||||||
// TODO: this will become StyleTextWrapStyle when we turn text-wrap
|
// TODO: this will become StyleTextWrapStyle when we turn text-wrap
|
||||||
// (see https://bugzilla.mozilla.org/show_bug.cgi?id=1758391) and
|
// (see https://bugzilla.mozilla.org/show_bug.cgi?id=1758391) and
|
||||||
|
|||||||
@@ -2791,7 +2791,6 @@ nsStyleText::nsStyleText(const Document& aDocument)
|
|||||||
mTextAlign(StyleTextAlign::Start),
|
mTextAlign(StyleTextAlign::Start),
|
||||||
mTextAlignLast(StyleTextAlignLast::Auto),
|
mTextAlignLast(StyleTextAlignLast::Auto),
|
||||||
mTextJustify(StyleTextJustify::Auto),
|
mTextJustify(StyleTextJustify::Auto),
|
||||||
mWhiteSpace(StyleWhiteSpace::Normal),
|
|
||||||
mHyphens(StyleHyphens::Manual),
|
mHyphens(StyleHyphens::Manual),
|
||||||
mRubyAlign(StyleRubyAlign::SpaceAround),
|
mRubyAlign(StyleRubyAlign::SpaceAround),
|
||||||
mRubyPosition(StyleRubyPosition::AlternateOver),
|
mRubyPosition(StyleRubyPosition::AlternateOver),
|
||||||
@@ -2828,7 +2827,8 @@ nsStyleText::nsStyleText(const nsStyleText& aSource)
|
|||||||
mTextAlign(aSource.mTextAlign),
|
mTextAlign(aSource.mTextAlign),
|
||||||
mTextAlignLast(aSource.mTextAlignLast),
|
mTextAlignLast(aSource.mTextAlignLast),
|
||||||
mTextJustify(aSource.mTextJustify),
|
mTextJustify(aSource.mTextJustify),
|
||||||
mWhiteSpace(aSource.mWhiteSpace),
|
mWhiteSpaceCollapse(aSource.mWhiteSpaceCollapse),
|
||||||
|
mTextWrapMode(aSource.mTextWrapMode),
|
||||||
mLineBreak(aSource.mLineBreak),
|
mLineBreak(aSource.mLineBreak),
|
||||||
mWordBreak(aSource.mWordBreak),
|
mWordBreak(aSource.mWordBreak),
|
||||||
mOverflowWrap(aSource.mOverflowWrap),
|
mOverflowWrap(aSource.mOverflowWrap),
|
||||||
@@ -2875,7 +2875,8 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aNewData) const {
|
|||||||
if ((mTextAlign != aNewData.mTextAlign) ||
|
if ((mTextAlign != aNewData.mTextAlign) ||
|
||||||
(mTextAlignLast != aNewData.mTextAlignLast) ||
|
(mTextAlignLast != aNewData.mTextAlignLast) ||
|
||||||
(mTextTransform != aNewData.mTextTransform) ||
|
(mTextTransform != aNewData.mTextTransform) ||
|
||||||
(mWhiteSpace != aNewData.mWhiteSpace) ||
|
(mWhiteSpaceCollapse != aNewData.mWhiteSpaceCollapse) ||
|
||||||
|
(mTextWrapMode != aNewData.mTextWrapMode) ||
|
||||||
(mLineBreak != aNewData.mLineBreak) ||
|
(mLineBreak != aNewData.mLineBreak) ||
|
||||||
(mWordBreak != aNewData.mWordBreak) ||
|
(mWordBreak != aNewData.mWordBreak) ||
|
||||||
(mOverflowWrap != aNewData.mOverflowWrap) ||
|
(mOverflowWrap != aNewData.mOverflowWrap) ||
|
||||||
|
|||||||
@@ -845,7 +845,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
|
|||||||
mozilla::StyleTextAlign mTextAlign;
|
mozilla::StyleTextAlign mTextAlign;
|
||||||
mozilla::StyleTextAlignLast mTextAlignLast;
|
mozilla::StyleTextAlignLast mTextAlignLast;
|
||||||
mozilla::StyleTextJustify mTextJustify;
|
mozilla::StyleTextJustify mTextJustify;
|
||||||
mozilla::StyleWhiteSpace mWhiteSpace;
|
mozilla::StyleWhiteSpaceCollapse mWhiteSpaceCollapse =
|
||||||
|
mozilla::StyleWhiteSpaceCollapse::Collapse;
|
||||||
|
mozilla::StyleTextWrapMode mTextWrapMode = mozilla::StyleTextWrapMode::Wrap;
|
||||||
mozilla::StyleLineBreak mLineBreak = mozilla::StyleLineBreak::Auto;
|
mozilla::StyleLineBreak mLineBreak = mozilla::StyleLineBreak::Auto;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -918,10 +920,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WhiteSpaceIsSignificant() const {
|
bool WhiteSpaceIsSignificant() const {
|
||||||
return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
|
return mWhiteSpaceCollapse != mozilla::StyleWhiteSpaceCollapse::Collapse &&
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
|
mWhiteSpaceCollapse !=
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces ||
|
mozilla::StyleWhiteSpaceCollapse::PreserveBreaks;
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreSpace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WhiteSpaceCanHangOrVisuallyCollapse() const {
|
bool WhiteSpaceCanHangOrVisuallyCollapse() const {
|
||||||
@@ -930,35 +931,28 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
|
|||||||
// WhiteSpaceCanWrapStyle() &&
|
// WhiteSpaceCanWrapStyle() &&
|
||||||
// WhiteSpaceIsSignificant()
|
// WhiteSpaceIsSignificant()
|
||||||
// which simplifies to:
|
// which simplifies to:
|
||||||
return mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap;
|
return mTextWrapMode == mozilla::StyleTextWrapMode::Wrap &&
|
||||||
|
mWhiteSpaceCollapse != mozilla::StyleWhiteSpaceCollapse::BreakSpaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewlineIsSignificantStyle() const {
|
bool NewlineIsSignificantStyle() const {
|
||||||
return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
|
return mWhiteSpaceCollapse == mozilla::StyleWhiteSpaceCollapse::Preserve ||
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
|
mWhiteSpaceCollapse ==
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces ||
|
mozilla::StyleWhiteSpaceCollapse::PreserveBreaks ||
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreLine;
|
mWhiteSpaceCollapse == mozilla::StyleWhiteSpaceCollapse::BreakSpaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WhiteSpaceOrNewlineIsSignificant() const {
|
bool WhiteSpaceOrNewlineIsSignificant() const {
|
||||||
return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
|
return NewlineIsSignificantStyle() || WhiteSpaceIsSignificant();
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
|
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces ||
|
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreLine ||
|
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreSpace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TabIsSignificant() const {
|
bool TabIsSignificant() const {
|
||||||
return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
|
return mWhiteSpaceCollapse == mozilla::StyleWhiteSpaceCollapse::Preserve ||
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
|
mWhiteSpaceCollapse == mozilla::StyleWhiteSpaceCollapse::BreakSpaces;
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WhiteSpaceCanWrapStyle() const {
|
bool WhiteSpaceCanWrapStyle() const {
|
||||||
return mWhiteSpace == mozilla::StyleWhiteSpace::Normal ||
|
return mTextWrapMode == mozilla::StyleTextWrapMode::Wrap;
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
|
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces ||
|
|
||||||
mWhiteSpace == mozilla::StyleWhiteSpace::PreLine;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WordCanWrapStyle() const {
|
bool WordCanWrapStyle() const {
|
||||||
|
|||||||
@@ -880,8 +880,8 @@ def _remove_common_first_line_and_first_letter_properties(props, engine):
|
|||||||
props.remove("overflow-wrap")
|
props.remove("overflow-wrap")
|
||||||
props.remove("text-align")
|
props.remove("text-align")
|
||||||
props.remove("text-justify")
|
props.remove("text-justify")
|
||||||
props.remove("white-space")
|
props.remove("white-space-collapse")
|
||||||
props.remove("text-wrap")
|
props.remove("text-wrap-mode")
|
||||||
props.remove("word-break")
|
props.remove("word-break")
|
||||||
props.remove("text-indent")
|
props.remove("text-indent")
|
||||||
|
|
||||||
@@ -983,11 +983,12 @@ class PropertyRestrictions:
|
|||||||
def placeholder(data):
|
def placeholder(data):
|
||||||
props = PropertyRestrictions.first_line(data)
|
props = PropertyRestrictions.first_line(data)
|
||||||
props.add("opacity")
|
props.add("opacity")
|
||||||
props.add("white-space")
|
|
||||||
props.add("text-wrap")
|
props.add("text-wrap")
|
||||||
props.add("text-overflow")
|
props.add("text-overflow")
|
||||||
props.add("text-align")
|
props.add("text-align")
|
||||||
props.add("text-justify")
|
props.add("text-justify")
|
||||||
|
for p in PropertyRestrictions.shorthand(data, "white-space"):
|
||||||
|
props.add(p)
|
||||||
return props
|
return props
|
||||||
|
|
||||||
# https://drafts.csswg.org/css-pseudo/#marker-pseudo
|
# https://drafts.csswg.org/css-pseudo/#marker-pseudo
|
||||||
@@ -995,7 +996,6 @@ class PropertyRestrictions:
|
|||||||
def marker(data):
|
def marker(data):
|
||||||
return set(
|
return set(
|
||||||
[
|
[
|
||||||
"white-space",
|
|
||||||
"text-wrap",
|
"text-wrap",
|
||||||
"color",
|
"color",
|
||||||
"text-combine-upright",
|
"text-combine-upright",
|
||||||
@@ -1006,6 +1006,7 @@ class PropertyRestrictions:
|
|||||||
"line-height",
|
"line-height",
|
||||||
"-moz-osx-font-smoothing",
|
"-moz-osx-font-smoothing",
|
||||||
]
|
]
|
||||||
|
+ PropertyRestrictions.shorthand(data, "white-space")
|
||||||
+ PropertyRestrictions.spec(data, "css-fonts")
|
+ PropertyRestrictions.spec(data, "css-fonts")
|
||||||
+ PropertyRestrictions.spec(data, "css-animations")
|
+ PropertyRestrictions.spec(data, "css-animations")
|
||||||
+ PropertyRestrictions.spec(data, "css-transitions")
|
+ PropertyRestrictions.spec(data, "css-transitions")
|
||||||
@@ -1020,7 +1021,6 @@ class PropertyRestrictions:
|
|||||||
"opacity",
|
"opacity",
|
||||||
"visibility",
|
"visibility",
|
||||||
"text-shadow",
|
"text-shadow",
|
||||||
"white-space",
|
|
||||||
"text-wrap",
|
"text-wrap",
|
||||||
"text-combine-upright",
|
"text-combine-upright",
|
||||||
"ruby-position",
|
"ruby-position",
|
||||||
@@ -1032,6 +1032,7 @@ class PropertyRestrictions:
|
|||||||
"background-blend-mode",
|
"background-blend-mode",
|
||||||
]
|
]
|
||||||
+ PropertyRestrictions.shorthand(data, "text-decoration")
|
+ PropertyRestrictions.shorthand(data, "text-decoration")
|
||||||
|
+ PropertyRestrictions.shorthand(data, "white-space")
|
||||||
+ PropertyRestrictions.shorthand(data, "background")
|
+ PropertyRestrictions.shorthand(data, "background")
|
||||||
+ PropertyRestrictions.shorthand(data, "outline")
|
+ PropertyRestrictions.shorthand(data, "outline")
|
||||||
+ PropertyRestrictions.shorthand(data, "font")
|
+ PropertyRestrictions.shorthand(data, "font")
|
||||||
|
|||||||
@@ -149,52 +149,26 @@ ${helpers.predefined_type(
|
|||||||
affects="layout",
|
affects="layout",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<%helpers:single_keyword
|
// TODO: `white-space-collapse: discard` not yet supported
|
||||||
name="white-space"
|
${helpers.single_keyword(
|
||||||
values="normal pre nowrap pre-wrap pre-line"
|
name="white-space-collapse",
|
||||||
engines="gecko servo-2013 servo-2020",
|
values="collapse preserve preserve-breaks preserve-spaces break-spaces",
|
||||||
extra_gecko_values="break-spaces -moz-pre-space"
|
engines="gecko",
|
||||||
gecko_enum_prefix="StyleWhiteSpace"
|
gecko_enum_prefix="StyleWhiteSpaceCollapse",
|
||||||
needs_conversion="True"
|
animation_value_type="discrete",
|
||||||
animation_value_type="discrete"
|
spec="https://drafts.csswg.org/css-text-4/#propdef-white-space-collapse",
|
||||||
spec="https://drafts.csswg.org/css-text/#propdef-white-space"
|
affects="layout",
|
||||||
servo_restyle_damage="rebuild_and_reflow"
|
)}
|
||||||
affects="layout"
|
|
||||||
>
|
|
||||||
% if engine in ["servo-2013", "servo-2020"]:
|
|
||||||
impl SpecifiedValue {
|
|
||||||
pub fn allow_wrap(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
SpecifiedValue::Nowrap |
|
|
||||||
SpecifiedValue::Pre => false,
|
|
||||||
SpecifiedValue::Normal |
|
|
||||||
SpecifiedValue::PreWrap |
|
|
||||||
SpecifiedValue::PreLine => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn preserve_newlines(&self) -> bool {
|
${helpers.single_keyword(
|
||||||
match *self {
|
name="text-wrap-mode",
|
||||||
SpecifiedValue::Normal |
|
values="wrap nowrap",
|
||||||
SpecifiedValue::Nowrap => false,
|
engines="gecko",
|
||||||
SpecifiedValue::Pre |
|
gecko_enum_prefix="StyleTextWrapMode",
|
||||||
SpecifiedValue::PreWrap |
|
animation_value_type="discrete",
|
||||||
SpecifiedValue::PreLine => true,
|
spec="https://drafts.csswg.org/css-text-4/#propdef-text-wrap-mode",
|
||||||
}
|
affects="layout",
|
||||||
}
|
)}
|
||||||
|
|
||||||
pub fn preserve_spaces(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
SpecifiedValue::Normal |
|
|
||||||
SpecifiedValue::Nowrap |
|
|
||||||
SpecifiedValue::PreLine => false,
|
|
||||||
SpecifiedValue::Pre |
|
|
||||||
SpecifiedValue::PreWrap => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
% endif
|
|
||||||
</%helpers:single_keyword>
|
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"text-shadow",
|
"text-shadow",
|
||||||
|
|||||||
@@ -46,6 +46,110 @@
|
|||||||
}
|
}
|
||||||
</%helpers:shorthand>
|
</%helpers:shorthand>
|
||||||
|
|
||||||
|
<%helpers:shorthand
|
||||||
|
name="white-space"
|
||||||
|
engines="gecko"
|
||||||
|
sub_properties="text-wrap-mode white-space-collapse"
|
||||||
|
spec="https://www.w3.org/TR/css-text-4/#white-space-property"
|
||||||
|
>
|
||||||
|
use crate::properties::longhands::{text_wrap_mode, white_space_collapse};
|
||||||
|
|
||||||
|
pub fn parse_value<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Longhands, ParseError<'i>> {
|
||||||
|
use white_space_collapse::computed_value::T as Collapse;
|
||||||
|
use text_wrap_mode::computed_value::T as Wrap;
|
||||||
|
|
||||||
|
fn parse_special_shorthands<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Longhands, ParseError<'i>> {
|
||||||
|
let (mode, collapse) = try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"normal" => (Wrap::Wrap, Collapse::Collapse),
|
||||||
|
"pre" => (Wrap::Nowrap, Collapse::Preserve),
|
||||||
|
"pre-wrap" => (Wrap::Wrap, Collapse::Preserve),
|
||||||
|
"pre-line" => (Wrap::Wrap, Collapse::PreserveBreaks),
|
||||||
|
// TODO: deprecate/remove -moz-pre-space; the white-space-collapse: preserve-spaces value
|
||||||
|
// should serve this purpose?
|
||||||
|
"-moz-pre-space" => (Wrap::Wrap, Collapse::PreserveSpaces),
|
||||||
|
};
|
||||||
|
Ok(expanded! {
|
||||||
|
text_wrap_mode: mode,
|
||||||
|
white_space_collapse: collapse,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(result) = input.try_parse(parse_special_shorthands) {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut wrap = None;
|
||||||
|
let mut collapse = None;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if wrap.is_none() {
|
||||||
|
if let Ok(value) = input.try_parse(|input| text_wrap_mode::parse(context, input)) {
|
||||||
|
wrap = Some(value);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if collapse.is_none() {
|
||||||
|
if let Ok(value) = input.try_parse(|input| white_space_collapse::parse(context, input)) {
|
||||||
|
collapse = Some(value);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if wrap.is_some() || collapse.is_some() {
|
||||||
|
Ok(expanded! {
|
||||||
|
text_wrap_mode: unwrap_or_initial!(text_wrap_mode, wrap),
|
||||||
|
white_space_collapse: unwrap_or_initial!(white_space_collapse, collapse),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
|
||||||
|
use white_space_collapse::computed_value::T as Collapse;
|
||||||
|
use text_wrap_mode::computed_value::T as Wrap;
|
||||||
|
|
||||||
|
match *self.text_wrap_mode {
|
||||||
|
Wrap::Wrap => {
|
||||||
|
match *self.white_space_collapse {
|
||||||
|
Collapse::Collapse => return dest.write_str("normal"),
|
||||||
|
Collapse::Preserve => return dest.write_str("pre-wrap"),
|
||||||
|
Collapse::PreserveBreaks => return dest.write_str("pre-line"),
|
||||||
|
Collapse::PreserveSpaces => return dest.write_str("-moz-pre-space"),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Wrap::Nowrap => {
|
||||||
|
if let Collapse::Preserve = *self.white_space_collapse {
|
||||||
|
return dest.write_str("pre");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut has_value = false;
|
||||||
|
if *self.white_space_collapse != Collapse::Collapse {
|
||||||
|
self.white_space_collapse.to_css(dest)?;
|
||||||
|
has_value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if *self.text_wrap_mode != Wrap::Wrap {
|
||||||
|
if has_value {
|
||||||
|
dest.write_char(' ')?;
|
||||||
|
}
|
||||||
|
self.text_wrap_mode.to_css(dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%helpers:shorthand>
|
||||||
|
|
||||||
// CSS Compatibility
|
// CSS Compatibility
|
||||||
// https://compat.spec.whatwg.org/
|
// https://compat.spec.whatwg.org/
|
||||||
<%helpers:shorthand name="-webkit-text-stroke"
|
<%helpers:shorthand name="-webkit-text-stroke"
|
||||||
|
|||||||
@@ -5311,7 +5311,8 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
|
|||||||
ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
|
ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
|
||||||
MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
|
MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
|
||||||
MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
|
MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
|
||||||
WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
|
WhiteSpaceCollapse => get_from_computed::<longhands::white_space_collapse::SpecifiedValue>(value),
|
||||||
|
TextWrapMode => get_from_computed::<longhands::text_wrap_mode::SpecifiedValue>(value),
|
||||||
CaptionSide => get_from_computed::<CaptionSide>(value),
|
CaptionSide => get_from_computed::<CaptionSide>(value),
|
||||||
BorderTopStyle => get_from_computed::<BorderStyle>(value),
|
BorderTopStyle => get_from_computed::<BorderStyle>(value),
|
||||||
BorderRightStyle => get_from_computed::<BorderStyle>(value),
|
BorderRightStyle => get_from_computed::<BorderStyle>(value),
|
||||||
|
|||||||
Reference in New Issue
Block a user