зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
42dc21cbe6
Коммит
6e18f8dd1b
|
@ -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 };
|
||||
|
|
Загрузка…
Ссылка в новой задаче