summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2022-06-10 07:35:22 +0000
committerMoonchild <moonchild@palemoon.org>2022-06-10 07:35:22 +0000
commit9ad788853f6f2be403ec54d1c56e8bd608014f02 (patch)
tree60432437fd2c907483ede17e1f566b45792189a6
parentd8070a8e0d7f6df5ac864e4052bc293f5442b967 (diff)
downloaduxp-9ad788853f6f2be403ec54d1c56e8bd608014f02.tar.gz
Issue #1914 - Implement white-space: break-spaces
This also simplifies GetCSSWhitespaceToCompressionMode (FFS with the function names, Mozilla!) to be less fragile.
-rw-r--r--devtools/shared/css/generated/properties-db.js1
-rw-r--r--gfx/thebes/gfxTextRun.cpp16
-rw-r--r--gfx/thebes/gfxTextRun.h1
-rw-r--r--layout/generic/nsTextFrame.cpp52
-rw-r--r--layout/style/nsCSSKeywordList.h1
-rw-r--r--layout/style/nsCSSProps.cpp1
-rw-r--r--layout/style/nsStyleConsts.h13
-rw-r--r--layout/style/nsStyleStruct.h7
-rw-r--r--layout/style/test/property_database.js2
9 files changed, 57 insertions, 37 deletions
diff --git a/devtools/shared/css/generated/properties-db.js b/devtools/shared/css/generated/properties-db.js
index 5a7e6d815d..9ccebc8481 100644
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -9519,6 +9519,7 @@ exports.CSS_PROPERTIES = {
"supports": [],
"values": [
"-moz-pre-space",
+ "break-spaces",
"inherit",
"initial",
"normal",
diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp
index fd97615366..438f6f61ae 100644
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -851,6 +851,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
bool *aUsedHyphenation,
uint32_t *aLastBreak,
bool aCanWordWrap,
+ bool aCanWhitespaceWrap,
gfxBreakPriority *aBreakPriority)
{
aMaxLength = std::min(aMaxLength, GetLength() - aStart);
@@ -918,7 +919,15 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
aCanWordWrap && mCharacterGlyphs[i].IsClusterStart() &&
*aBreakPriority <= gfxBreakPriority::eWordWrapBreak;
- if (atBreak || wordWrapping) {
+ bool whitespaceWrapping = false;
+ if (i > aStart) {
+ // The spec says the breaking opportunity is *after* whitespace.
+ auto const& g = mCharacterGlyphs[i - 1];
+ whitespaceWrapping = aCanWhitespaceWrap &&
+ (g.CharIsSpace() || g.CharIsTab() || g.CharIsNewline());
+ }
+
+ if (atBreak || wordWrapping || whitespaceWrapping) {
gfxFloat hyphenatedAdvance = advance;
if (atHyphenationBreak) {
hyphenatedAdvance += aProvider->GetHyphenWidth();
@@ -930,8 +939,9 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
lastBreakTrimmableChars = trimmableChars;
lastBreakTrimmableAdvance = trimmableAdvance;
lastBreakUsedHyphenation = atHyphenationBreak;
- *aBreakPriority = atBreak ? gfxBreakPriority::eNormalBreak
- : gfxBreakPriority::eWordWrapBreak;
+ *aBreakPriority = (atBreak || whitespaceWrapping)
+ ? gfxBreakPriority::eNormalBreak
+ : gfxBreakPriority::eWordWrapBreak;
}
width += advance;
diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h
index d61992527b..2ef835f189 100644
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -409,6 +409,7 @@ public:
bool *aUsedHyphenation,
uint32_t *aLastBreak,
bool aCanWordWrap,
+ bool aCanWhitespaceWrap,
gfxBreakPriority *aBreakPriority);
// Utility getters
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index 07e7a36557..1fccf48a18 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1988,35 +1988,31 @@ GetHyphenTextRun(const gfxTextRun* aTextRun, DrawTarget* aDrawTarget,
MakeHyphenTextRun(dt, aTextRun->GetAppUnitsPerDevUnit());
}
-static_assert(NS_STYLE_WHITESPACE_NORMAL == 0, "Convention: NS_STYLE_WHITESPACE_NORMAL should be 0");
-static_assert(NS_STYLE_WHITESPACE_PRE == 1, "Convention: NS_STYLE_WHITESPACE_PRE should be 1");
-static_assert(NS_STYLE_WHITESPACE_NOWRAP == 2, "Convention: NS_STYLE_WHITESPACE_NOWRAP should be 2");
-static_assert(NS_STYLE_WHITESPACE_PRE_WRAP == 3, "Convention: NS_STYLE_WHITESPACE_PRE_WRAP should be 3");
-static_assert(NS_STYLE_WHITESPACE_PRE_LINE == 4, "Convention: NS_STYLE_WHITESPACE_PRE_LINE should be 4");
-static_assert(NS_STYLE_WHITESPACE_PRE_SPACE == 5, "Convention: NS_STYLE_WHITESPACE_PRE_SPACE should be 5");
-
static nsTextFrameUtils::CompressionMode
GetCSSWhitespaceToCompressionMode(nsTextFrame* aFrame,
const nsStyleText* aStyleText)
{
- static const nsTextFrameUtils::CompressionMode sModes[] =
- {
- nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE, // normal
- nsTextFrameUtils::COMPRESS_NONE, // pre
- nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE, // nowrap
- nsTextFrameUtils::COMPRESS_NONE, // pre-wrap
- nsTextFrameUtils::COMPRESS_WHITESPACE, // pre-line
- nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE // -moz-pre-space
- };
-
- auto compression = sModes[aStyleText->mWhiteSpace];
- if (compression == nsTextFrameUtils::COMPRESS_NONE &&
- !aStyleText->NewlineIsSignificant(aFrame)) {
- // If newline is set to be preserved, but then suppressed,
- // transform newline to space.
- compression = nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE;
+ switch (aStyleText->mWhiteSpace) {
+ case NS_STYLE_WHITESPACE_NORMAL:
+ case NS_STYLE_WHITESPACE_NOWRAP:
+ return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
+ case NS_STYLE_WHITESPACE_PRE:
+ case NS_STYLE_WHITESPACE_PRE_WRAP:
+ case NS_STYLE_WHITESPACE_BREAK_SPACES:
+ if (!aStyleText->NewlineIsSignificant(aFrame)) {
+ // If newline is set to be preserved, but then suppressed,
+ // transform newline to space.
+ return nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE;
+ }
+ return nsTextFrameUtils::COMPRESS_NONE;
+ case NS_STYLE_WHITESPACE_PRE_SPACE:
+ return nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE;
+ case NS_STYLE_WHITESPACE_PRE_LINE:
+ return nsTextFrameUtils::COMPRESS_WHITESPACE;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown white-space value");
+ return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
}
- return compression;
}
already_AddRefed<gfxTextRun>
@@ -9206,8 +9202,10 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
}
bool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() ||
(GetStateBits() & TEXT_IS_IN_TOKEN_MATHML);
+ bool isBreakSpaces = textStyle->mWhiteSpace == NS_STYLE_WHITESPACE_BREAK_SPACES;
// allow whitespace to overflow the container
- bool whitespaceCanHang = textStyle->WhiteSpaceCanWrapStyle() &&
+ bool whitespaceCanHang = !isBreakSpaces &&
+ textStyle->WhiteSpaceCanWrapStyle() &&
textStyle->WhiteSpaceIsSignificant();
gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority();
gfxTextRun::SuppressBreak suppressBreak = gfxTextRun::eNoSuppressBreak;
@@ -9227,7 +9225,9 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
&textMetrics, boundingBoxType,
aDrawTarget,
&usedHyphenation, &transformedLastBreak,
- textStyle->WordCanWrap(this), &breakPriority);
+ textStyle->WordCanWrap(this),
+ isBreakSpaces,
+ &breakPriority);
if (!length && !textMetrics.mAscent && !textMetrics.mDescent) {
// If we're measuring a zero-length piece of text, update
// the height manually.
diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h
index 7e661bc483..d6486b18cf 100644
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -171,6 +171,7 @@ CSS_KEY(both, both)
CSS_KEY(bottom, bottom)
CSS_KEY(bottom-outside, bottom_outside)
CSS_KEY(break-all, break_all)
+CSS_KEY(break-spaces, break_spaces)
CSS_KEY(break-word, break_word)
CSS_KEY(brightness, brightness)
CSS_KEY(browser, browser)
diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp
index 4aff3dc5bf..f084e45992 100644
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -2251,6 +2251,7 @@ const KTableEntry nsCSSProps::kWhitespaceKTable[] = {
{ eCSSKeyword_pre_wrap, NS_STYLE_WHITESPACE_PRE_WRAP },
{ eCSSKeyword_pre_line, NS_STYLE_WHITESPACE_PRE_LINE },
{ eCSSKeyword__moz_pre_space, NS_STYLE_WHITESPACE_PRE_SPACE },
+ { eCSSKeyword_break_spaces, NS_STYLE_WHITESPACE_BREAK_SPACES },
{ eCSSKeyword_UNKNOWN, -1 }
};
diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h
index 4d2043cc47..9cb3c9edea 100644
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -993,12 +993,13 @@ enum class StyleDisplay : uint8_t {
#define NS_STYLE_TABSIZE_INITIAL 8
// See nsStyleText
-#define NS_STYLE_WHITESPACE_NORMAL 0
-#define NS_STYLE_WHITESPACE_PRE 1
-#define NS_STYLE_WHITESPACE_NOWRAP 2
-#define NS_STYLE_WHITESPACE_PRE_WRAP 3
-#define NS_STYLE_WHITESPACE_PRE_LINE 4
-#define NS_STYLE_WHITESPACE_PRE_SPACE 5
+#define NS_STYLE_WHITESPACE_NORMAL 0
+#define NS_STYLE_WHITESPACE_PRE 1
+#define NS_STYLE_WHITESPACE_NOWRAP 2
+#define NS_STYLE_WHITESPACE_PRE_WRAP 3
+#define NS_STYLE_WHITESPACE_PRE_LINE 4
+#define NS_STYLE_WHITESPACE_PRE_SPACE 5
+#define NS_STYLE_WHITESPACE_BREAK_SPACES 6
// See nsStyleText
#define NS_STYLE_WORDBREAK_NORMAL 0
diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h
index a01685cc44..da9643594e 100644
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2105,30 +2105,35 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
bool WhiteSpaceIsSignificant() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
+ mWhiteSpace == NS_STYLE_WHITESPACE_BREAK_SPACES ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_SPACE;
}
bool NewlineIsSignificantStyle() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
+ mWhiteSpace == NS_STYLE_WHITESPACE_BREAK_SPACES ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_LINE;
}
bool WhiteSpaceOrNewlineIsSignificant() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
+ mWhiteSpace == NS_STYLE_WHITESPACE_BREAK_SPACES ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_LINE ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_SPACE;
}
bool TabIsSignificant() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
- mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP;
+ mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
+ mWhiteSpace == NS_STYLE_WHITESPACE_BREAK_SPACES;
}
bool WhiteSpaceCanWrapStyle() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_NORMAL ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
+ mWhiteSpace == NS_STYLE_WHITESPACE_BREAK_SPACES ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_LINE;
}
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
index 5c6e2f6d86..0abe930832 100644
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4052,7 +4052,7 @@ var gCSSProperties = {
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "normal" ],
- other_values: [ "pre", "nowrap", "pre-wrap", "pre-line", "-moz-pre-space" ],
+ other_values: [ "pre", "nowrap", "pre-wrap", "pre-line", "-moz-pre-space", "break-spaces" ],
invalid_values: []
},
"width": {