Bug 620286 - White space at beginning (end) of tspan should render when there is preceding (following) non-white space text. r=roc

This commit is contained in:
Robert Longson 2011-05-03 08:45:30 +01:00
Родитель e00a4a380d
Коммит 5617229cea
13 изменённых файлов: 125 добавлений и 111 удалений

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

@ -196,6 +196,7 @@ fails-if(Android) random-if(gtk2Widget) != text-language-01.xhtml text-language-
== text-layout-01.svg text-layout-01-ref.svg
== text-layout-02.svg text-layout-02-ref.svg
== text-layout-03.svg text-layout-03-ref.svg
== text-layout-04.svg text-layout-04-ref.svg
== text-scale-01.svg text-scale-01-ref.svg
== text-stroke-scaling-01.svg text-stroke-scaling-01-ref.svg
== stroke-linecap-square-w-zero-length-segs-01.svg pass.svg

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

@ -0,0 +1,11 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg xmlns="http://www.w3.org/2000/svg">
<title>Reference to check whitespace handling</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=620286 -->
<text x="10" y="50" font-size="50">A <tspan/>B</text>
</svg>

После

Ширина:  |  Высота:  |  Размер: 348 B

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

@ -0,0 +1,11 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg xmlns="http://www.w3.org/2000/svg">
<title>Testcase to check whitespace handling</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=620286 -->
<text x="10" y="50" font-size="50">A <tspan/> B</text>
</svg>

После

Ширина:  |  Высота:  |  Размер: 348 B

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

@ -87,6 +87,10 @@ public:
nsTArray<float> &aRotate)=0;
NS_IMETHOD_(PRUint16) GetTextAnchor()=0;
NS_IMETHOD_(PRBool) IsAbsolutelyPositioned()=0;
NS_IMETHOD_(void) SetTrimLeadingWhitespace(PRBool aTrimLeadingWhitespace)=0;
NS_IMETHOD_(void) SetTrimTrailingWhitespace(PRBool aTrimTrailingWhitespace)=0;
NS_IMETHOD_(PRBool) EndsWithWhitespace() const=0;
NS_IMETHOD_(PRBool) IsAllWhitespace() const=0;
};
#endif // __NS_ISVGGLYPHFRAGMENTLEAF_H__

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

@ -45,11 +45,6 @@
class nsISVGGlyphFragmentLeaf;
class nsIDOMSVGPoint;
#define PRESERVE_WHITESPACE 0x00
#define COMPRESS_WHITESPACE 0x01
#define TRIM_LEADING_WHITESPACE 0x02
#define TRIM_TRAILING_WHITESPACE 0x04
class nsISVGGlyphFragmentNode : public nsQueryFrame
{
public:
@ -61,8 +56,7 @@ public:
virtual PRInt32 GetCharNumAtPosition(nsIDOMSVGPoint *point)=0;
NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment()=0;
NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment()=0;
NS_IMETHOD_(void) SetWhitespaceHandling(PRUint8 aWhitespaceHandling)=0;
NS_IMETHOD_(PRBool) IsAllWhitespace()=0;
NS_IMETHOD_(void) SetWhitespaceCompression(PRBool aCompressWhitespace)=0;
};
#endif // __NS_ISVGGLYPHFRAGMENTNODE_H__

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

@ -669,12 +669,9 @@ nsSVGGlyphFrame::GetCharacterData(nsAString & aCharacterData)
nsAutoString characterData;
mContent->AppendTextTo(characterData);
if (mWhitespaceHandling & COMPRESS_WHITESPACE) {
PRBool trimLeadingWhitespace, trimTrailingWhitespace;
trimLeadingWhitespace = ((mWhitespaceHandling & TRIM_LEADING_WHITESPACE) != 0);
trimTrailingWhitespace = ((mWhitespaceHandling & TRIM_TRAILING_WHITESPACE) != 0);
characterData.CompressWhitespace(trimLeadingWhitespace,
trimTrailingWhitespace);
if (mCompressWhitespace) {
characterData.CompressWhitespace(mTrimLeadingWhitespace,
mTrimTrailingWhitespace);
} else {
nsAString::iterator start, end;
characterData.BeginWriting(start);
@ -1340,12 +1337,13 @@ nsSVGGlyphFrame::IsAbsolutelyPositioned()
PRUint32
nsSVGGlyphFrame::GetNumberOfChars()
{
if (mWhitespaceHandling == PRESERVE_WHITESPACE)
return mContent->TextLength();
if (mCompressWhitespace) {
nsAutoString text;
GetCharacterData(text);
return text.Length();
}
nsAutoString text;
GetCharacterData(text);
return text.Length();
return mContent->TextLength();
}
float
@ -1442,14 +1440,15 @@ nsSVGGlyphFrame::GetNextGlyphFragment()
return node ? node->GetNextGlyphFragment() : nsnull;
}
NS_IMETHODIMP_(void)
nsSVGGlyphFrame::SetWhitespaceHandling(PRUint8 aWhitespaceHandling)
NS_IMETHODIMP_(PRBool)
nsSVGGlyphFrame::EndsWithWhitespace() const
{
mWhitespaceHandling = aWhitespaceHandling;
const nsTextFragment* text = mContent->GetText();
return NS_IsAsciiWhitespace(text->CharAt(text->GetLength() - 1));
}
NS_IMETHODIMP_(PRBool)
nsSVGGlyphFrame::IsAllWhitespace()
nsSVGGlyphFrame::IsAllWhitespace() const
{
const nsTextFragment* text = mContent->GetText();

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

@ -66,7 +66,9 @@ protected:
: nsSVGGlyphFrameBase(aContext),
mTextRun(nsnull),
mStartIndex(0),
mWhitespaceHandling(COMPRESS_WHITESPACE),
mCompressWhitespace(PR_TRUE),
mTrimLeadingWhitespace(PR_FALSE),
mTrimTrailingWhitespace(PR_FALSE),
mPropagateTransform(PR_TRUE)
{}
~nsSVGGlyphFrame()
@ -160,6 +162,14 @@ public:
nsTArray<float> &aRotate);
NS_IMETHOD_(PRUint16) GetTextAnchor();
NS_IMETHOD_(PRBool) IsAbsolutelyPositioned();
NS_IMETHOD_(void) SetTrimLeadingWhitespace(PRBool aTrimLeadingWhitespace) {
mTrimLeadingWhitespace = aTrimLeadingWhitespace;
}
NS_IMETHOD_(void) SetTrimTrailingWhitespace(PRBool aTrimTrailingWhitespace) {
mTrimTrailingWhitespace = aTrimTrailingWhitespace;
}
NS_IMETHOD_(PRBool) EndsWithWhitespace() const;
NS_IMETHOD_(PRBool) IsAllWhitespace() const;
// nsISVGGlyphFragmentNode interface:
// These do not use the global transform if NS_STATE_NONDISPLAY_CHILD
@ -169,8 +179,9 @@ public:
virtual PRInt32 GetCharNumAtPosition(nsIDOMSVGPoint *point);
NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment();
NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment();
NS_IMETHOD_(void) SetWhitespaceHandling(PRUint8 aWhitespaceHandling);
NS_IMETHOD_(PRBool) IsAllWhitespace();
NS_IMETHOD_(void) SetWhitespaceCompression(PRBool aCompressWhitespace) {
mCompressWhitespace = aCompressWhitespace;
}
protected:
friend class CharacterIterator;
@ -227,7 +238,9 @@ protected:
gfxPoint mPosition;
// The start index into the position and rotation data
PRUint32 mStartIndex;
PRUint8 mWhitespaceHandling;
PRPackedBool mCompressWhitespace;
PRPackedBool mTrimLeadingWhitespace;
PRPackedBool mTrimTrailingWhitespace;
PRPackedBool mPropagateTransform;
};

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

@ -190,13 +190,7 @@ nsSVGTSpanFrame::GetNextGlyphFragment()
}
NS_IMETHODIMP_(void)
nsSVGTSpanFrame::SetWhitespaceHandling(PRUint8 aWhitespaceHandling)
nsSVGTSpanFrame::SetWhitespaceCompression(PRBool)
{
nsSVGTSpanFrameBase::SetWhitespaceHandling();
}
NS_IMETHODIMP_(PRBool)
nsSVGTSpanFrame::IsAllWhitespace()
{
return nsSVGTSpanFrameBase::IsAllWhitespace();
nsSVGTSpanFrameBase::SetWhitespaceCompression();
}

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

@ -92,8 +92,7 @@ public:
virtual PRInt32 GetCharNumAtPosition(nsIDOMSVGPoint *point);
NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment();
NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment();
NS_IMETHOD_(void) SetWhitespaceHandling(PRUint8 aWhitespaceHandling);
NS_IMETHOD_(PRBool) IsAllWhitespace();
NS_IMETHOD_(void) SetWhitespaceCompression(PRBool aCompressWhitespace);
};
#endif

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

@ -319,70 +319,6 @@ nsSVGTextContainerFrame::GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode *
return retval;
}
void
nsSVGTextContainerFrame::SetWhitespaceHandling()
{
PRUint8 whitespaceHandling = COMPRESS_WHITESPACE | TRIM_LEADING_WHITESPACE;
for (nsIFrame *frame = this; frame != nsnull; frame = frame->GetParent()) {
nsIContent *content = frame->GetContent();
static nsIContent::AttrValuesArray strings[] =
{&nsGkAtoms::preserve, &nsGkAtoms::_default, nsnull};
PRInt32 index = content->FindAttrValueIn(kNameSpaceID_XML,
nsGkAtoms::space,
strings, eCaseMatters);
if (index == 0) {
whitespaceHandling = PRESERVE_WHITESPACE;
break;
}
if (index != nsIContent::ATTR_MISSING ||
(frame->GetStateBits() & NS_STATE_IS_OUTER_SVG))
break;
}
nsISVGGlyphFragmentNode* firstNode = GetFirstGlyphFragmentChildNode();
nsISVGGlyphFragmentNode* lastNonWhitespaceNode = nsnull;
nsISVGGlyphFragmentNode* node;
if (whitespaceHandling != PRESERVE_WHITESPACE) {
lastNonWhitespaceNode = node = firstNode;
while (node) {
if (!node->IsAllWhitespace()) {
lastNonWhitespaceNode = node;
}
node = GetNextGlyphFragmentChildNode(node);
}
}
node = firstNode;
while (node) {
if (node == lastNonWhitespaceNode) {
whitespaceHandling |= TRIM_TRAILING_WHITESPACE;
}
node->SetWhitespaceHandling(whitespaceHandling);
if ((whitespaceHandling & TRIM_LEADING_WHITESPACE) &&
!node->IsAllWhitespace()) {
whitespaceHandling &= ~TRIM_LEADING_WHITESPACE;
}
node = GetNextGlyphFragmentChildNode(node);
}
}
PRBool
nsSVGTextContainerFrame::IsAllWhitespace()
{
nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
while (node) {
if (!node->IsAllWhitespace()) {
return PR_FALSE;
}
node = GetNextGlyphFragmentChildNode(node);
}
return PR_TRUE;
}
// -------------------------------------------------------------------------
// Private functions
// -------------------------------------------------------------------------
@ -547,3 +483,33 @@ nsSVGTextContainerFrame::GetEffectiveRotate(nsTArray<float> &aRotate)
{
aRotate.AppendElements(mRotate);
}
void
nsSVGTextContainerFrame::SetWhitespaceCompression()
{
PRBool compressWhitespace = PR_TRUE;
for (const nsIFrame *frame = this; frame != nsnull; frame = frame->GetParent()) {
static const nsIContent::AttrValuesArray strings[] =
{&nsGkAtoms::preserve, &nsGkAtoms::_default, nsnull};
PRInt32 index = frame->GetContent()->FindAttrValueIn(
kNameSpaceID_XML,
nsGkAtoms::space,
strings, eCaseMatters);
if (index == 0) {
compressWhitespace = PR_FALSE;
break;
}
if (index != nsIContent::ATTR_MISSING ||
(frame->GetStateBits() & NS_STATE_IS_OUTER_SVG))
break;
}
nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
while (node) {
node->SetWhitespaceCompression(compressWhitespace);
node = GetNextGlyphFragmentChildNode(node);
}
}

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

@ -45,16 +45,16 @@ class nsSVGTextFrame;
class nsSVGTextContainerFrame : public nsSVGDisplayContainerFrame
{
public:
protected:
nsSVGTextContainerFrame(nsStyleContext* aContext) :
nsSVGDisplayContainerFrame(aContext) {}
public:
void NotifyGlyphMetricsChange();
virtual void GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY);
virtual void GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy);
virtual const SVGNumberList *GetRotate();
public:
NS_DECL_QUERYFRAME_TARGET(nsSVGTextContainerFrame)
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS
@ -106,11 +106,6 @@ protected:
nsISVGGlyphFragmentNode *
GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode *node);
/*
* Set Whitespace handling
*/
void SetWhitespaceHandling();
PRBool IsAllWhitespace();
void CopyPositionList(nsTArray<float> *parentList,
SVGUserUnitList *selfList,
nsTArray<float> &dstList,
@ -121,6 +116,7 @@ protected:
PRUint32 aOffset);
PRUint32 BuildPositionList(PRUint32 aOffset, PRUint32 aDepth);
void SetWhitespaceCompression();
private:
/*
* Returns the glyph fragment containing a particular character

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

@ -294,18 +294,40 @@ nsSVGTextFrame::NotifyGlyphMetricsChange()
UpdateGlyphPositioning(PR_FALSE);
}
void
nsSVGTextFrame::SetWhitespaceHandling(
nsISVGGlyphFragmentLeaf *fragment)
{
SetWhitespaceCompression();
PRBool trimLeadingWhitespace = PR_TRUE;
nsISVGGlyphFragmentLeaf* lastNonWhitespaceFragment = fragment;
while (fragment) {
if (!fragment->IsAllWhitespace()) {
lastNonWhitespaceFragment = fragment;
}
fragment->SetTrimLeadingWhitespace(trimLeadingWhitespace);
trimLeadingWhitespace = fragment->EndsWithWhitespace();
fragment = fragment->GetNextGlyphFragment();
}
lastNonWhitespaceFragment->SetTrimTrailingWhitespace(PR_TRUE);
}
void
nsSVGTextFrame::UpdateGlyphPositioning(PRBool aForceGlobalTransform)
{
if (mMetricsState == suspended || !mPositioningDirty)
return;
SetWhitespaceHandling();
mPositioningDirty = PR_FALSE;
nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
if (!node) return;
mPositioningDirty = PR_FALSE;
if (!node)
return;
nsISVGGlyphFragmentLeaf *fragment, *firstFragment;
@ -314,6 +336,8 @@ nsSVGTextFrame::UpdateGlyphPositioning(PRBool aForceGlobalTransform)
return;
}
SetWhitespaceHandling(firstFragment);
BuildPositionList(0, 0);
gfxPoint ctp(0.0, 0.0);

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

@ -121,6 +121,8 @@ private:
*/
void UpdateGlyphPositioning(PRBool aForceGlobalTransform);
void SetWhitespaceHandling(nsISVGGlyphFragmentLeaf *fragment);
nsCOMPtr<nsIDOMSVGMatrix> mCanvasTM;
enum UpdateState { unsuspended, suspended };