Bug 1019555 - Treat newlines and tabs as space characters in SVG xml:space="preserve" text. r=roc

This commit is contained in:
Cameron McCormack 2014-06-05 13:25:15 +10:00
Родитель 3fa67f89f1
Коммит 8311e3a117
13 изменённых файлов: 85 добавлений и 73 удалений

Просмотреть файл

@ -675,8 +675,7 @@ static bool IsCSSWordSpacingSpace(const nsTextFragment* aFrag,
return !IsSpaceCombiningSequenceTail(aFrag, aPos + 1);
case '\r':
case '\t': return !aStyleText->WhiteSpaceIsSignificant();
case '\n': return !aStyleText->NewlineIsSignificant() &&
!aStyleText->NewlineIsDiscarded();
case '\n': return !aStyleText->NewlineIsSignificant();
default: return false;
}
}
@ -709,7 +708,7 @@ static bool IsTrimmableSpace(const nsTextFragment* aFrag, uint32_t aPos,
case ' ': return !aStyleText->WhiteSpaceIsSignificant() &&
!IsSpaceCombiningSequenceTail(aFrag, aPos + 1);
case '\n': return !aStyleText->NewlineIsSignificant() &&
!aStyleText->NewlineIsDiscarded();
aStyleText->mWhiteSpace != NS_STYLE_WHITESPACE_PRE_SPACE;
case '\t':
case '\r':
case '\f': return !aStyleText->WhiteSpaceIsSignificant();
@ -773,21 +772,6 @@ IsAllWhitespace(const nsTextFragment* aFrag, bool aAllowNewline)
return true;
}
static bool
IsAllNewlines(const nsTextFragment* aFrag)
{
if (aFrag->Is2b())
return false;
int32_t len = aFrag->GetLength();
const char* str = aFrag->Get1b();
for (int32_t i = 0; i < len; ++i) {
char ch = str[i];
if (ch != '\n')
return false;
}
return true;
}
static void
CreateObserverForAnimatedGlyphs(nsTextFrame* aFrame, const nsTArray<gfxFont*>& aFonts)
{
@ -1816,16 +1800,16 @@ PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE == 1);
PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_NOWRAP == 2);
PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_WRAP == 3);
PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_LINE == 4);
PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES == 5);
PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_PRE_SPACE == 5);
static const nsTextFrameUtils::CompressionMode CSSWhitespaceToCompressionMode[] =
{
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::DISCARD_NEWLINE // -moz-pre-discard-newlines
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
};
gfxTextRun*
@ -7159,7 +7143,7 @@ nsTextFrame::AddInlinePrefWidthForFlow(nsRenderingContext *aRenderingContext,
bool collapseWhitespace = !textStyle->WhiteSpaceIsSignificant();
bool preformatNewlines = textStyle->NewlineIsSignificant();
bool preformatTabs = textStyle->WhiteSpaceIsSignificant();
bool preformatTabs = textStyle->TabIsSignificant();
gfxFloat tabWidth = -1;
uint32_t start =
FindStartAfterSkippingWhitespace(&provider, aData, textStyle, &iter, flowEndInTextRun);
@ -7175,8 +7159,8 @@ nsTextFrame::AddInlinePrefWidthForFlow(nsRenderingContext *aRenderingContext,
// XXXldb Shouldn't we be including the newline as part of the
// segment that it ends rather than part of the segment that it
// starts?
NS_ASSERTION(preformatNewlines || textStyle->NewlineIsDiscarded(),
"We can't be here unless newlines are hard breaks or are discarded");
NS_ASSERTION(preformatNewlines,
"We can't be here unless newlines are hard breaks");
preformattedNewline = preformatNewlines && textRun->CharIsNewline(i);
preformattedTab = preformatTabs && textRun->CharIsTab(i);
if (!preformattedNewline && !preformattedTab) {
@ -8270,8 +8254,10 @@ static char16_t TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun,
uint32_t aSkippedOffset, char16_t aChar)
{
if (aChar == '\n') {
return aStyle->NewlineIsSignificant() || aStyle->NewlineIsDiscarded() ?
aChar : ' ';
return aStyle->NewlineIsSignificant() ? aChar : ' ';
}
if (aChar == '\t') {
return aStyle->TabIsSignificant() ? aChar : ' ';
}
switch (aStyle->mTextTransform) {
case NS_STYLE_TEXT_TRANSFORM_LOWERCASE:
@ -8380,8 +8366,7 @@ nsTextFrame::IsEmpty()
// XXXldb Should this check compatibility mode as well???
const nsStyleText* textStyle = StyleText();
if (textStyle->WhiteSpaceIsSignificant() &&
textStyle->mWhiteSpace != NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES) {
if (textStyle->WhiteSpaceIsSignificant()) {
// XXX shouldn't we return true if the length is zero?
return false;
}
@ -8395,10 +8380,8 @@ nsTextFrame::IsEmpty()
}
bool isEmpty =
textStyle->mWhiteSpace == NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES ?
IsAllNewlines(mContent->GetText()) :
IsAllWhitespace(mContent->GetText(),
textStyle->mWhiteSpace != NS_STYLE_WHITESPACE_PRE_LINE);
IsAllWhitespace(mContent->GetText(),
textStyle->mWhiteSpace != NS_STYLE_WHITESPACE_PRE_LINE);
mState |= (isEmpty ? TEXT_IS_ONLY_WHITESPACE : TEXT_ISNOT_ONLY_WHITESPACE);
return isEmpty;
}

Просмотреть файл

@ -47,20 +47,27 @@ nsTextFrameUtils::TransformText(const char16_t* aText, uint32_t aLength,
bool lastCharArabic = false;
if (aCompression == COMPRESS_NONE ||
aCompression == DISCARD_NEWLINE) {
aCompression == COMPRESS_NONE_TRANSFORM_TO_SPACE) {
// Skip discardables.
uint32_t i;
for (i = 0; i < aLength; ++i) {
char16_t ch = *aText++;
if (IsDiscardable(ch, &flags) ||
(ch == '\n' && aCompression == DISCARD_NEWLINE)) {
if (IsDiscardable(ch, &flags)) {
aSkipChars->SkipChar();
} else {
aSkipChars->KeepChar();
if (ch > ' ') {
lastCharArabic = IS_ARABIC_CHAR(ch);
} else if (ch == '\t') {
flags |= TEXT_HAS_TAB;
} else if (aCompression == COMPRESS_NONE_TRANSFORM_TO_SPACE) {
if (ch == '\t' || ch == '\n') {
ch = ' ';
flags |= TEXT_WAS_TRANSFORMED;
}
} else {
// aCompression == COMPRESS_NONE
if (ch == '\t') {
flags |= TEXT_HAS_TAB;
}
}
*aOutput++ = ch;
}
@ -147,18 +154,25 @@ nsTextFrameUtils::TransformText(const uint8_t* aText, uint32_t aLength,
uint8_t* outputStart = aOutput;
if (aCompression == COMPRESS_NONE ||
aCompression == DISCARD_NEWLINE) {
aCompression == COMPRESS_NONE_TRANSFORM_TO_SPACE) {
// Skip discardables.
uint32_t i;
for (i = 0; i < aLength; ++i) {
uint8_t ch = *aText++;
if (IsDiscardable(ch, &flags) ||
(ch == '\n' && aCompression == DISCARD_NEWLINE)) {
if (IsDiscardable(ch, &flags)) {
aSkipChars->SkipChar();
} else {
aSkipChars->KeepChar();
if (ch == '\t') {
flags |= TEXT_HAS_TAB;
if (aCompression == COMPRESS_NONE_TRANSFORM_TO_SPACE) {
if (ch == '\t' || ch == '\n') {
ch = ' ';
flags |= TEXT_WAS_TRANSFORMED;
}
} else {
// aCompression == COMPRESS_NONE
if (ch == '\t') {
flags |= TEXT_HAS_TAB;
}
}
*aOutput++ = ch;
}

Просмотреть файл

@ -82,7 +82,7 @@ public:
COMPRESS_NONE,
COMPRESS_WHITESPACE,
COMPRESS_WHITESPACE_NEWLINE,
DISCARD_NEWLINE
COMPRESS_NONE_TRANSFORM_TO_SPACE
};
/**

Просмотреть файл

@ -1,13 +0,0 @@
<!DOCTYPE html>
<style>
p { font: 16px monospace; white-space: pre; }
span { background-color: lime }
</style>
<p><span>a b</span></p>
<p><span>ab</span></p>
<p><span>a b</span></p>
<p><span> a b</span></p>
<p><span>a </span></p>
<p><span></span></p>
<p><span> </span></p>
<p><span>. </span></p>

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE html>
<style>
p { font: 16px monospace; white-space: pre; }
span { background-color: lime }
</style>
<p><span>a b</span></p>
<p><span>a b</span></p>
<p><span>a b</span></p>
<p><span> a b </span></p>
<p><span>a </span></p>
<p><span> </span></p>
<p><span> </span></p>
<p><span>. </span></p>
<p><span>a b</span></p>
<p><span>a b</span></p>
<p><span> a b </span></p>
<p><span>a </span></p>
<p><span> </span></p>
<p><span> </span></p>
<p><span>. </span></p>

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html>
<style>
p { font: 16px monospace; white-space: -moz-pre-discard-newlines; }
p { font: 16px monospace; white-space: -moz-pre-space; }
span { background-color: lime }
</style>
<p><span>a b</span></p>
@ -11,3 +11,10 @@ span { background-color: lime }
<p><span>&#xA;&#xA;&#xA;</span></p>
<p><span> &#xA;&#xA;&#xA; </span></p>
<p><span>. &#xA;</span></p>
<p><span>a&#x9;b</span></p>
<p><span>a &#x9; b</span></p>
<p><span>&#x9; a&#x9; b&#x9;</span></p>
<p><span>a </span></p>
<p><span>&#x9;&#x9;&#x9;</span></p>
<p><span> &#x9;&#x9;&#x9; </span></p>
<p><span>. &#x9;</span></p>

Просмотреть файл

@ -29,7 +29,7 @@ fuzzy-if(Android,255,42) == pre-line-1.html pre-line-1-ref.html
== pre-line-2.html pre-line-2-ref.html
== pre-line-3.html pre-line-3-ref.html
== pre-line-4.html pre-line-4-ref.html
== pre-discard-newlines-1.html pre-discard-newlines-1-ref.html
== pre-space-1.html pre-space-1-ref.html
== soft-hyphens-1a.html soft-hyphens-1-ref.html
== soft-hyphens-1b.html soft-hyphens-1-ref.html
== soft-hyphens-1c.html soft-hyphens-1-ref.html

Просмотреть файл

@ -128,7 +128,7 @@ CSS_KEY(-moz-oriya, _moz_oriya)
CSS_KEY(-moz-persian, _moz_persian)
CSS_KEY(-moz-plaintext, _moz_plaintext)
CSS_KEY(-moz-popup, _moz_popup)
CSS_KEY(-moz-pre-discard-newlines, _moz_pre_discard_newlines)
CSS_KEY(-moz-pre-space, _moz_pre_space)
CSS_KEY(-moz-pull-down-menu, _moz_pull_down_menu)
CSS_KEY(-moz-right, _moz_right)
CSS_KEY(-moz-scrollbars-horizontal, _moz_scrollbars_horizontal)

Просмотреть файл

@ -1715,7 +1715,7 @@ const KTableValue nsCSSProps::kWhitespaceKTable[] = {
eCSSKeyword_nowrap, NS_STYLE_WHITESPACE_NOWRAP,
eCSSKeyword_pre_wrap, NS_STYLE_WHITESPACE_PRE_WRAP,
eCSSKeyword_pre_line, NS_STYLE_WHITESPACE_PRE_LINE,
eCSSKeyword__moz_pre_discard_newlines, NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES,
eCSSKeyword__moz_pre_space, NS_STYLE_WHITESPACE_PRE_SPACE,
eCSSKeyword_UNKNOWN,-1
};

Просмотреть файл

@ -822,7 +822,7 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#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_DISCARD_NEWLINES 5
#define NS_STYLE_WHITESPACE_PRE_SPACE 5
// See nsStyleText
#define NS_STYLE_WORDBREAK_NORMAL 0

Просмотреть файл

@ -1529,7 +1529,7 @@ struct nsStyleText {
bool WhiteSpaceIsSignificant() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES;
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_SPACE;
}
bool NewlineIsSignificant() const {
@ -1538,15 +1538,16 @@ struct nsStyleText {
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_LINE;
}
bool NewlineIsDiscarded() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES;
}
bool WhiteSpaceOrNewlineIsSignificant() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_LINE ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES;
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_SPACE;
}
bool TabIsSignificant() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP;
}
bool WhiteSpaceCanWrapStyle() const {

Просмотреть файл

@ -3335,7 +3335,7 @@ var gCSSProperties = {
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "normal" ],
other_values: [ "pre", "nowrap", "pre-wrap", "pre-line", "-moz-pre-discard-newlines" ],
other_values: [ "pre", "nowrap", "pre-wrap", "pre-line", "-moz-pre-space" ],
invalid_values: []
},
"widows": {

Просмотреть файл

@ -65,7 +65,7 @@ foreignObject {
}
*[xml|space=preserve] {
white-space: -moz-pre-discard-newlines;
white-space: -moz-pre-space;
}
*|*::-moz-svg-marker-anon-child {