From dedc74de85a7fe283841058e3cf378bd10572f19 Mon Sep 17 00:00:00 2001 From: "longsonr%gmail.com" Date: Mon, 12 Jun 2006 15:50:31 +0000 Subject: [PATCH] Bug 339039 - Text spans return incorrect number of characters with getNumberOfChars(). r=tor,sr=roc --- layout/svg/base/src/nsISVGGlyphFragmentLeaf.h | 7 +- layout/svg/base/src/nsISVGGlyphFragmentNode.h | 8 +- layout/svg/base/src/nsSVGGlyphFrame.cpp | 91 +++-- layout/svg/base/src/nsSVGGlyphFrame.h | 9 +- layout/svg/base/src/nsSVGTSpanFrame.cpp | 112 ++---- layout/svg/base/src/nsSVGTSpanFrame.h | 9 +- layout/svg/base/src/nsSVGTextFrame.cpp | 87 +---- layout/svg/base/src/nsSVGUtils.cpp | 341 ++++++++++-------- layout/svg/base/src/nsSVGUtils.h | 51 ++- .../public/nsISVGGlyphMetricsSource.idl | 10 +- .../src/cairo/nsSVGCairoGlyphMetrics.cpp | 62 ++-- 11 files changed, 399 insertions(+), 388 deletions(-) diff --git a/layout/svg/base/src/nsISVGGlyphFragmentLeaf.h b/layout/svg/base/src/nsISVGGlyphFragmentLeaf.h index 525fc7e72ef2..b4cff323b55e 100644 --- a/layout/svg/base/src/nsISVGGlyphFragmentLeaf.h +++ b/layout/svg/base/src/nsISVGGlyphFragmentLeaf.h @@ -44,8 +44,9 @@ class nsISVGRendererGlyphMetrics; +// {33397E2B-C1DC-49f0-9738-4891FE083C92} #define NS_ISVGGLYPHFRAGMENTLEAF_IID \ -{ 0x7e8500f1, 0xb3a5, 0x4e8a, { 0x90, 0x78, 0x03, 0x34, 0xc7, 0xcb, 0x30, 0x16 } } +{ 0x33397e2b, 0xc1dc, 0x49f0, { 0x97, 0x38, 0x48, 0x91, 0xfe, 0x8, 0x3c, 0x92 } } class nsISVGGlyphFragmentLeaf : public nsISVGGlyphFragmentNode { @@ -54,13 +55,9 @@ public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISVGGLYPHFRAGMENTLEAF_IID) NS_IMETHOD_(void) SetGlyphPosition(float x, float y)=0; - NS_IMETHOD_(float) GetGlyphPositionX()=0; - NS_IMETHOD_(float) GetGlyphPositionY()=0; NS_IMETHOD GetGlyphMetrics(nsISVGRendererGlyphMetrics** metrics)=0; NS_IMETHOD_(PRBool) IsStartOfChunk()=0; // == is new absolutely positioned chunk. NS_IMETHOD_(void) GetAdjustedPosition(/* inout */ float &x, /* inout */ float &y)=0; - NS_IMETHOD_(PRUint32) GetNumberOfChars()=0; - NS_IMETHOD_(PRUint32) GetCharNumberOffset()=0; NS_IMETHOD_(already_AddRefed) GetX()=0; NS_IMETHOD_(already_AddRefed) GetY()=0; diff --git a/layout/svg/base/src/nsISVGGlyphFragmentNode.h b/layout/svg/base/src/nsISVGGlyphFragmentNode.h index d3d4bf0442a1..fa5ebc8619d0 100644 --- a/layout/svg/base/src/nsISVGGlyphFragmentNode.h +++ b/layout/svg/base/src/nsISVGGlyphFragmentNode.h @@ -44,9 +44,9 @@ class nsISVGGlyphFragmentLeaf; -// {5A3A3929-9F98-4756-8C85-9689EB05983B} +// {AEEE492E-AF86-4c6a-AF14-88E224DD10E5} #define NS_ISVGGLYPHFRAGMENTNODE_IID \ -{ 0x5a3a3929, 0x9f98, 0x4756, { 0x8c, 0x85, 0x96, 0x89, 0xeb, 0x05, 0x98, 0x3b } } +{ 0xaeee492e, 0xaf86, 0x4c6a, { 0xaf, 0x14, 0x88, 0xe2, 0x24, 0xdd, 0x10, 0xe5 } } class nsISVGGlyphFragmentNode : public nsISupports { @@ -54,6 +54,10 @@ public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISVGGLYPHFRAGMENTNODE_IID) + NS_IMETHOD_(PRUint32) GetNumberOfChars()=0; + NS_IMETHOD_(float) GetComputedTextLength()=0; + NS_IMETHOD_(float) GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars)=0; + NS_IMETHOD_(PRInt32) GetCharNumAtPosition(nsIDOMSVGPoint *point)=0; NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment()=0; NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment()=0; NS_IMETHOD_(PRUint32) BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch)=0; diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 5f51c372206d..020daf163f08 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -83,7 +83,6 @@ NS_NewSVGGlyphFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame* pa nsSVGGlyphFrame::nsSVGGlyphFrame(nsStyleContext* aContext) : nsSVGGlyphFrameBase(aContext), - mCharOffset(0), mFragmentTreeDirty(PR_FALSE) { } @@ -145,7 +144,7 @@ nsSVGGlyphFrame::CharacterDataChanged(nsPresContext* aPresContext, nsIContent* aChild, PRBool aAppend) { - return UpdateGraphic(); + return UpdateGraphic(); } nsresult @@ -458,7 +457,7 @@ FindPoint(nsSVGPathData *data, } } -/* readonly attribute nsSVGCharacterPostion characterPosition; */ +/* void GetCharacterPosition (out nsSVGCharacterPosition aCP); */ NS_IMETHODIMP nsSVGGlyphFrame::GetCharacterPosition(nsSVGCharacterPosition **aCharacterPosition) { @@ -466,11 +465,16 @@ nsSVGGlyphFrame::GetCharacterPosition(nsSVGCharacterPosition **aCharacterPositio nsISVGPathFlatten *textPath = nsnull; /* check if we're the child of a textPath */ - for (nsIFrame *frame = this; frame != nsnull; frame = frame->GetParent()) + for (nsIFrame *frame = GetParent(); + frame != nsnull; + frame = frame->GetParent()) { if (frame->GetType() == nsLayoutAtoms::svgTextPathFrame) { - frame->QueryInterface(NS_GET_IID(nsISVGPathFlatten), (void **)&textPath); + CallQueryInterface(frame, &textPath); break; } + if (frame->GetType() == nsLayoutAtoms::svgTextFrame) + break; + } /* we're an ordinary fragment - return */ /* XXX: we might want to use this for individual x/y/dx/dy adjustment */ @@ -520,6 +524,15 @@ nsSVGGlyphFrame::GetCharacterPosition(nsSVGCharacterPosition **aCharacterPositio return NS_OK; } +/* void GetGlyphPosition (out float aGlyphPositionX, out float aGlyphPositionY); */ +NS_IMETHODIMP +nsSVGGlyphFrame::GetGlyphPosition(float *aGlyphPositionX, float *aGlyphPositionY) +{ + *aGlyphPositionX = mX; + *aGlyphPositionY = mY; + return NS_OK; +} + /* readonly attribute unsigned short textRendering; */ NS_IMETHODIMP nsSVGGlyphFrame::GetTextRendering(PRUint16 *aTextRendering) @@ -716,19 +729,6 @@ nsSVGGlyphFrame::SetGlyphPosition(float x, float y) UpdateGeometry(PR_TRUE, PR_FALSE); } -NS_IMETHODIMP_(float) -nsSVGGlyphFrame::GetGlyphPositionX() -{ - return mX; -} - -NS_IMETHODIMP_(float) -nsSVGGlyphFrame::GetGlyphPositionY() -{ - return mY; -} - - NS_IMETHODIMP nsSVGGlyphFrame::GetGlyphMetrics(nsISVGRendererGlyphMetrics** metrics) { @@ -752,18 +752,6 @@ nsSVGGlyphFrame::GetAdjustedPosition(/* inout */ float &x, /* inout */ float &y) { } -NS_IMETHODIMP_(PRUint32) -nsSVGGlyphFrame::GetNumberOfChars() -{ - return mCharacterData.Length(); -} - -NS_IMETHODIMP_(PRUint32) -nsSVGGlyphFrame::GetCharNumberOffset() -{ - return mCharOffset; -} - NS_IMETHODIMP_(already_AddRefed) nsSVGGlyphFrame::GetX() { @@ -819,7 +807,7 @@ nsSVGGlyphFrame::IsAbsolutelyPositioned() { nsIFrame *lastFrame = this; - for (nsIFrame *frame = this->GetParent(); + for (nsIFrame *frame = GetParent(); frame != nsnull; lastFrame = frame, frame = frame->GetParent()) { @@ -848,6 +836,42 @@ nsSVGGlyphFrame::IsAbsolutelyPositioned() //---------------------------------------------------------------------- // nsISVGGlyphFragmentNode interface: +NS_IMETHODIMP_(PRUint32) +nsSVGGlyphFrame::GetNumberOfChars() +{ + return mCharacterData.Length(); +} + +NS_IMETHODIMP_(float) +nsSVGGlyphFrame::GetComputedTextLength() +{ + if (mCharacterData.IsEmpty()) { + return 0.0f; + } + + float fragmentLength; + mMetrics->GetComputedTextLength(&fragmentLength); + return fragmentLength; +} + +NS_IMETHODIMP_(float) +nsSVGGlyphFrame::GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars) +{ + float fragmentLength; + mMetrics->GetSubStringLength(charnum, + fragmentChars, + &fragmentLength); + return fragmentLength; +} + +NS_IMETHODIMP_(PRInt32) +nsSVGGlyphFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point) +{ + PRInt32 index; + mMetrics->GetCharNumAtPosition(point, &index); + return index; +} + NS_IMETHODIMP_(nsISVGGlyphFragmentLeaf *) nsSVGGlyphFrame::GetFirstGlyphFragment() { @@ -880,7 +904,6 @@ nsSVGGlyphFrame::BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch) // XXX actually we should be building a new fragment for each chunk here... - mCharOffset = charNum; nsCOMPtr tc = do_QueryInterface(mContent); if (tc->TextLength() == 0) { @@ -893,9 +916,9 @@ nsSVGGlyphFrame::BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch) mCharacterData.Truncate(); tc->AppendTextTo(mCharacterData); - mCharacterData.CompressWhitespace(charNum==0, lastBranch); + mCharacterData.CompressWhitespace(charNum == 0, lastBranch); - return charNum+mCharacterData.Length(); + return charNum + mCharacterData.Length(); } NS_IMETHODIMP_(void) diff --git a/layout/svg/base/src/nsSVGGlyphFrame.h b/layout/svg/base/src/nsSVGGlyphFrame.h index 728b896da5ee..3f1c12283865 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.h +++ b/layout/svg/base/src/nsSVGGlyphFrame.h @@ -124,13 +124,9 @@ public: // nsISVGGlyphFragmentLeaf interface: NS_IMETHOD_(void) SetGlyphPosition(float x, float y); - NS_IMETHOD_(float) GetGlyphPositionX(); - NS_IMETHOD_(float) GetGlyphPositionY(); NS_IMETHOD GetGlyphMetrics(nsISVGRendererGlyphMetrics** metrics); NS_IMETHOD_(PRBool) IsStartOfChunk(); // == is new absolutely positioned chunk. NS_IMETHOD_(void) GetAdjustedPosition(/* inout */ float &x, /* inout */ float &y); - NS_IMETHOD_(PRUint32) GetNumberOfChars(); - NS_IMETHOD_(PRUint32) GetCharNumberOffset(); NS_IMETHOD_(already_AddRefed) GetX(); NS_IMETHOD_(already_AddRefed) GetY(); @@ -140,6 +136,10 @@ public: NS_IMETHOD_(PRBool) IsAbsolutelyPositioned(); // nsISVGGlyphFragmentNode interface: + NS_IMETHOD_(PRUint32) GetNumberOfChars(); + NS_IMETHOD_(float) GetComputedTextLength(); + NS_IMETHOD_(float) GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars); + NS_IMETHOD_(PRInt32) GetCharNumAtPosition(nsIDOMSVGPoint *point); NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment(); NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment(); NS_IMETHOD_(PRUint32) BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch); @@ -158,7 +158,6 @@ protected: nsCOMPtr mGeometry; nsCOMPtr mMetrics; float mX, mY; - PRUint32 mCharOffset; PRPackedBool mFragmentTreeDirty; }; diff --git a/layout/svg/base/src/nsSVGTSpanFrame.cpp b/layout/svg/base/src/nsSVGTSpanFrame.cpp index 3027e6e9f21e..56ee78355213 100644 --- a/layout/svg/base/src/nsSVGTSpanFrame.cpp +++ b/layout/svg/base/src/nsSVGTSpanFrame.cpp @@ -38,7 +38,6 @@ #include "nsSVGTSpanFrame.h" #include "nsSVGUtils.h" -#include "nsDOMError.h" //---------------------------------------------------------------------- // Implementation @@ -68,7 +67,7 @@ NS_NewSVGTSpanFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsSVGTSpanFrame::nsSVGTSpanFrame(nsStyleContext* aContext) : nsSVGTSpanFrameBase(aContext), - mCharOffset(0), mFragmentTreeDirty(PR_FALSE), mPropagateTransform(PR_TRUE) + mFragmentTreeDirty(PR_FALSE), mPropagateTransform(PR_TRUE) { } @@ -131,80 +130,54 @@ nsSVGTSpanFrame::AttributeChanged(PRInt32 aNameSpaceID, NS_IMETHODIMP nsSVGTSpanFrame::GetNumberOfChars(PRInt32 *_retval) { - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); + *_retval = nsSVGUtils::GetNumberOfChars(&mFrames); - if (node) - return nsSVGUtils::GetNumberOfChars(node, _retval); - - *_retval = 0; return NS_OK; } NS_IMETHODIMP nsSVGTSpanFrame::GetComputedTextLength(float *_retval) { - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); + *_retval = nsSVGUtils::GetComputedTextLength(&mFrames); - if (node) - return nsSVGUtils::GetComputedTextLength(node, _retval); - - *_retval = 0.0; return NS_OK; } NS_IMETHODIMP nsSVGTSpanFrame::GetSubStringLength(PRUint32 charnum, PRUint32 nchars, float *_retval) { - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - - if (node) - return nsSVGUtils::GetSubStringLength(node, charnum, nchars, _retval); - - *_retval = 0.0; - return NS_OK; + return nsSVGUtils::GetSubStringLength(&mFrames, charnum, nchars, _retval); } NS_IMETHODIMP nsSVGTSpanFrame::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval) { - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (!node) return NS_ERROR_DOM_INDEX_SIZE_ERR; - return nsSVGUtils::GetStartPositionOfChar(node, charnum, _retval); + return nsSVGUtils::GetStartPositionOfChar(&mFrames, charnum, _retval); } NS_IMETHODIMP nsSVGTSpanFrame::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval) { - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (!node) return NS_ERROR_DOM_INDEX_SIZE_ERR; - return nsSVGUtils::GetEndPositionOfChar(node, charnum, _retval); + return nsSVGUtils::GetEndPositionOfChar(&mFrames, charnum, _retval); } NS_IMETHODIMP nsSVGTSpanFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval) { - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (!node) return NS_ERROR_DOM_INDEX_SIZE_ERR; - return nsSVGUtils::GetExtentOfChar(node, charnum, _retval); + return nsSVGUtils::GetExtentOfChar(&mFrames, charnum, _retval); } NS_IMETHODIMP nsSVGTSpanFrame::GetRotationOfChar(PRUint32 charnum, float *_retval) { - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (!node) return NS_ERROR_DOM_INDEX_SIZE_ERR; - return nsSVGUtils::GetRotationOfChar(node, charnum, _retval); + return nsSVGUtils::GetRotationOfChar(&mFrames, charnum, _retval); } NS_IMETHODIMP nsSVGTSpanFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point, PRInt32 *_retval) { - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); + *_retval = nsSVGUtils::GetCharNumAtPosition(&mFrames, point); - if (node) - return nsSVGUtils::GetCharNumAtPosition(node, point, _retval); - - *_retval = -1; return NS_OK; } @@ -307,6 +280,30 @@ nsSVGTSpanFrame::GetRelativePositionAdjustmentY(float &dy, PRUint32 charNum) //---------------------------------------------------------------------- // nsISVGGlyphFragmentNode methods: +NS_IMETHODIMP_(PRUint32) +nsSVGTSpanFrame::GetNumberOfChars() +{ + return nsSVGUtils::GetNumberOfChars(&mFrames); +} + +NS_IMETHODIMP_(float) +nsSVGTSpanFrame::GetComputedTextLength() +{ + return nsSVGUtils::GetComputedTextLength(&mFrames); +} + +NS_IMETHODIMP_(float) +nsSVGTSpanFrame::GetSubStringLength(PRUint32 charnum, PRUint32 nchars) +{ + return nsSVGUtils::GetSubStringLengthNoValidation(&mFrames, charnum, nchars); +} + +NS_IMETHODIMP_(PRInt32) +nsSVGTSpanFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point) +{ + return nsSVGUtils::GetCharNumAtPosition(&mFrames, point); +} + NS_IMETHODIMP_(nsISVGGlyphFragmentLeaf *) nsSVGTSpanFrame::GetFirstGlyphFragment() { @@ -348,21 +345,9 @@ nsSVGTSpanFrame::GetNextGlyphFragment() NS_IMETHODIMP_(PRUint32) nsSVGTSpanFrame::BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch) { - mCharOffset = charNum; - - // init children: - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - nsISVGGlyphFragmentNode* next; - while (node) { - next = GetNextGlyphFragmentChildNode(node); - charNum = node->BuildGlyphFragmentTree(charNum, lastBranch && !next); - node = next; - } - - return charNum; + return nsSVGUtils::BuildGlyphFragmentTree(&mFrames, charNum, lastBranch); } - NS_IMETHODIMP_(void) nsSVGTSpanFrame::NotifyMetricsSuspended() { @@ -488,32 +473,3 @@ nsSVGTSpanFrame::GetDy() animLengthList->GetAnimVal(&retval); return retval; } - -nsISVGGlyphFragmentNode * -nsSVGTSpanFrame::GetFirstGlyphFragmentChildNode() -{ - nsISVGGlyphFragmentNode* retval = nsnull; - nsIFrame* frame = mFrames.FirstChild(); - while (frame) { - frame->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&retval); - if (retval) break; - frame = frame->GetNextSibling(); - } - return retval; -} - -nsISVGGlyphFragmentNode * -nsSVGTSpanFrame::GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode*node) -{ - nsISVGGlyphFragmentNode* retval = nsnull; - nsIFrame* frame = nsnull; - node->QueryInterface(NS_GET_IID(nsIFrame), (void**)&frame); - NS_ASSERTION(frame, "interface not implemented"); - frame = frame->GetNextSibling(); - while (frame) { - frame->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&retval); - if (retval) break; - frame = frame->GetNextSibling(); - } - return retval; -} diff --git a/layout/svg/base/src/nsSVGTSpanFrame.h b/layout/svg/base/src/nsSVGTSpanFrame.h index cc877f189fea..16ef35ee3fe2 100644 --- a/layout/svg/base/src/nsSVGTSpanFrame.h +++ b/layout/svg/base/src/nsSVGTSpanFrame.h @@ -137,6 +137,10 @@ public: NS_IMETHOD_(already_AddRefed) GetDy(); // nsISVGGlyphFragmentNode interface: + NS_IMETHOD_(PRUint32) GetNumberOfChars(); + NS_IMETHOD_(float) GetComputedTextLength(); + NS_IMETHOD_(float) GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars); + NS_IMETHOD_(PRInt32) GetCharNumAtPosition(nsIDOMSVGPoint *point); NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment(); NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment(); NS_IMETHOD_(PRUint32) BuildGlyphFragmentTree(PRUint32 charNum, PRBool lastBranch); @@ -145,13 +149,8 @@ public: NS_IMETHOD_(void) NotifyGlyphFragmentTreeSuspended(); NS_IMETHOD_(void) NotifyGlyphFragmentTreeUnsuspended(); -protected: - nsISVGGlyphFragmentNode *GetFirstGlyphFragmentChildNode(); - nsISVGGlyphFragmentNode *GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode*node); - private: nsCOMPtr mOverrideCTM; - PRUint32 mCharOffset; // index of first character of this node relative to the enclosing -element PRPackedBool mFragmentTreeDirty; PRPackedBool mPropagateTransform; }; diff --git a/layout/svg/base/src/nsSVGTextFrame.cpp b/layout/svg/base/src/nsSVGTextFrame.cpp index ea68f5a05355..ec8902795fa6 100644 --- a/layout/svg/base/src/nsSVGTextFrame.cpp +++ b/layout/svg/base/src/nsSVGTextFrame.cpp @@ -63,7 +63,6 @@ #include "nsISVGPathFlatten.h" #include "nsSVGUtils.h" #include "nsSVGUtils.h" -#include "nsDOMError.h" #include "nsSVGClipPathFrame.h" #include "nsISVGRendererSurface.h" #include "nsINameSpaceManager.h" @@ -165,8 +164,6 @@ protected: void EnsureFragmentTreeUpToDate(); void UpdateFragmentTree(); void UpdateGlyphPositioning(); - nsISVGGlyphFragmentNode *GetFirstGlyphFragmentChildNode(); - nsISVGGlyphFragmentNode *GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode*node); enum UpdateState{ unsuspended, @@ -323,12 +320,8 @@ nsSVGTextFrame::GetNumberOfChars(PRInt32 *_retval) { EnsureFragmentTreeUpToDate(); - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); + *_retval = nsSVGUtils::GetNumberOfChars(&mFrames); - if (node) - return nsSVGUtils::GetNumberOfChars(node, _retval); - - *_retval = 0; return NS_OK; } @@ -337,12 +330,8 @@ nsSVGTextFrame::GetComputedTextLength(float *_retval) { EnsureFragmentTreeUpToDate(); - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); + *_retval = nsSVGUtils::GetComputedTextLength(&mFrames); - if (node) - return nsSVGUtils::GetComputedTextLength(node, _retval); - - *_retval = 0.0; return NS_OK; } @@ -351,13 +340,7 @@ nsSVGTextFrame::GetSubStringLength(PRUint32 charnum, PRUint32 nchars, float *_re { EnsureFragmentTreeUpToDate(); - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - - if (node) - return nsSVGUtils::GetSubStringLength(node, charnum, nchars, _retval); - - *_retval = 0.0; - return NS_OK; + return nsSVGUtils::GetSubStringLength(&mFrames, charnum, nchars, _retval); } NS_IMETHODIMP @@ -365,9 +348,7 @@ nsSVGTextFrame::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retva { EnsureFragmentTreeUpToDate(); - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (!node) return NS_ERROR_DOM_INDEX_SIZE_ERR; - return nsSVGUtils::GetStartPositionOfChar(node, charnum, _retval); + return nsSVGUtils::GetStartPositionOfChar(&mFrames, charnum, _retval); } NS_IMETHODIMP @@ -375,9 +356,7 @@ nsSVGTextFrame::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval) { EnsureFragmentTreeUpToDate(); - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (!node) return NS_ERROR_DOM_INDEX_SIZE_ERR; - return nsSVGUtils::GetEndPositionOfChar(node, charnum, _retval); + return nsSVGUtils::GetEndPositionOfChar(&mFrames, charnum, _retval); } NS_IMETHODIMP @@ -385,9 +364,7 @@ nsSVGTextFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval) { EnsureFragmentTreeUpToDate(); - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (!node) return NS_ERROR_DOM_INDEX_SIZE_ERR; - return nsSVGUtils::GetExtentOfChar(node, charnum, _retval); + return nsSVGUtils::GetExtentOfChar(&mFrames, charnum, _retval); } NS_IMETHODIMP @@ -395,9 +372,7 @@ nsSVGTextFrame::GetRotationOfChar(PRUint32 charnum, float *_retval) { EnsureFragmentTreeUpToDate(); - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (!node) return NS_ERROR_DOM_INDEX_SIZE_ERR; - return nsSVGUtils::GetRotationOfChar(node, charnum, _retval); + return nsSVGUtils::GetRotationOfChar(&mFrames, charnum, _retval); } NS_IMETHODIMP @@ -405,11 +380,8 @@ nsSVGTextFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point, PRInt32 *_retval) { EnsureFragmentTreeUpToDate(); - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - if (node) - return nsSVGUtils::GetCharNumAtPosition(node, point, _retval); + *_retval = nsSVGUtils::GetCharNumAtPosition(&mFrames, point); - *_retval = -1; return NS_OK; } @@ -704,15 +676,7 @@ nsSVGTextFrame::UpdateFragmentTree() { NS_ASSERTION(mFragmentTreeState == unsuspended, "updating during suspension!"); - PRUint32 charNum = 0; - - nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(); - nsISVGGlyphFragmentNode* next; - while (node) { - next = GetNextGlyphFragmentChildNode(node); - charNum = node->BuildGlyphFragmentTree(charNum, !next); - node = next; - } + nsSVGUtils::BuildGlyphFragmentTree(&mFrames, 0, PR_TRUE); mFragmentTreeDirty = PR_FALSE; @@ -777,7 +741,8 @@ nsSVGTextFrame::UpdateGlyphPositioning() { NS_ASSERTION(mMetricsState == unsuspended, "updating during suspension"); - nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode(); + nsISVGGlyphFragmentNode* node; + node = nsSVGUtils::GetFirstGlyphFragmentChildNode(&mFrames); if (!node) return; // we'll align every fragment in this chunk on the dominant-baseline: @@ -957,33 +922,3 @@ nsSVGTextFrame::GetDy() animLengthList->GetAnimVal(&retval); return retval; } - -nsISVGGlyphFragmentNode * -nsSVGTextFrame::GetFirstGlyphFragmentChildNode() -{ - nsISVGGlyphFragmentNode* retval = nsnull; - nsIFrame* frame = mFrames.FirstChild(); - while (frame) { - frame->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&retval); - if (retval) break; - frame = frame->GetNextSibling(); - } - return retval; -} - -nsISVGGlyphFragmentNode * -nsSVGTextFrame::GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode*node) -{ - nsISVGGlyphFragmentNode* retval = nsnull; - nsIFrame* frame = nsnull; - node->QueryInterface(NS_GET_IID(nsIFrame), (void**)&frame); - NS_ASSERTION(frame, "interface not implemented"); - frame = frame->GetNextSibling(); - while (frame) { - frame->QueryInterface(NS_GET_IID(nsISVGGlyphFragmentNode),(void**)&retval); - if (retval) break; - frame = frame->GetNextSibling(); - } - return retval; -} - diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 71e97ab5bd7c..516b4aadb961 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -235,226 +235,278 @@ nsSVGUtils::GetBBox(nsFrameList *aFrames, nsIDOMSVGRect **_retval) return NS_ERROR_FAILURE; } -nsresult -nsSVGUtils::GetNumberOfChars(nsISVGGlyphFragmentNode* node, - PRInt32 *_retval) +nsISVGGlyphFragmentNode * +nsSVGUtils::GetFirstGlyphFragmentChildNode(nsFrameList *aFrames) +{ + nsISVGGlyphFragmentNode *retval = nsnull; + nsIFrame* kid = aFrames->FirstChild(); + while (kid) { + CallQueryInterface(kid, &retval); + if (retval) break; + kid = kid->GetNextSibling(); + } + return retval; +} + +nsISVGGlyphFragmentNode * +nsSVGUtils::GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode *node) +{ + nsISVGGlyphFragmentNode *retval = nsnull; + nsIFrame *frame = nsnull; + CallQueryInterface(node, &frame); + NS_ASSERTION(frame, "interface not implemented"); + frame = frame->GetNextSibling(); + while (frame) { + CallQueryInterface(frame, &retval); + if (retval) break; + frame = frame->GetNextSibling(); + } + return retval; +} + +PRUint32 +nsSVGUtils::BuildGlyphFragmentTree(nsFrameList *aFrames, + PRUint32 charNum, + PRBool lastBranch) +{ + // init children: + nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode(aFrames); + nsISVGGlyphFragmentNode* next; + while (node) { + next = GetNextGlyphFragmentChildNode(node); + charNum = node->BuildGlyphFragmentTree(charNum, lastBranch && !next); + node = next; + } + + return charNum; +} + +PRUint32 +nsSVGUtils::GetNumberOfChars(nsFrameList *aFrames) { PRUint32 nchars = 0; - nsISVGGlyphFragmentLeaf *fragment = node->GetFirstGlyphFragment(); + nsISVGGlyphFragmentNode* node; + node = GetFirstGlyphFragmentChildNode(aFrames); - while (fragment) { - nchars += fragment->GetNumberOfChars(); - fragment = fragment->GetNextGlyphFragment(); + while (node) { + nchars += node->GetNumberOfChars(); + node = GetNextGlyphFragmentChildNode(node); } - *_retval = nchars; - return NS_OK; + return nchars; } -nsresult -nsSVGUtils::GetComputedTextLength(nsISVGGlyphFragmentNode* node, - float *_retval) +float +nsSVGUtils::GetComputedTextLength(nsFrameList *aFrames) { - float length = 0.0; - nsISVGGlyphFragmentLeaf *fragment = node->GetFirstGlyphFragment(); + float length = 0.0f; + nsISVGGlyphFragmentNode* node; + node = GetFirstGlyphFragmentChildNode(aFrames); - while (fragment) { - if (fragment->GetNumberOfChars() > 0) { - // query the renderer metrics for the length of each fragment - nsCOMPtr metrics; - fragment->GetGlyphMetrics(getter_AddRefs(metrics)); - if (!metrics) return NS_ERROR_FAILURE; - float fragmentLength; - nsresult rv = metrics->GetComputedTextLength(&fragmentLength); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - length += fragmentLength; - } - - fragment = fragment->GetNextGlyphFragment(); + while (node) { + length += node->GetComputedTextLength(); + node = GetNextGlyphFragmentChildNode(node); } - *_retval = length; - return NS_OK; + return length; } nsresult -nsSVGUtils::GetSubStringLength(nsISVGGlyphFragmentNode* node, +nsSVGUtils::GetSubStringLength(nsFrameList *aFrames, PRUint32 charnum, PRUint32 nchars, float *_retval) { - float length = 0.0; - nsISVGGlyphFragmentLeaf *fragment = node->GetFirstGlyphFragment(); - - while (fragment && nchars) { - PRUint32 count = fragment->GetNumberOfChars(); + if (nchars == 0) { + *_retval = 0.0f; + return NS_OK; + } + + if (charnum + nchars > nsSVGUtils::GetNumberOfChars(aFrames)) { + *_retval = 0.0f; + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + *_retval = GetSubStringLengthNoValidation(aFrames, charnum, nchars); + + return NS_OK; +} + +float +nsSVGUtils::GetSubStringLengthNoValidation(nsFrameList *aFrames, + PRUint32 charnum, + PRUint32 nchars) +{ + float length = 0.0f; + nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode(aFrames); + + while (node) { + PRUint32 count = node->GetNumberOfChars(); if (count > charnum) { - // query the renderer metrics for the length of the substring in each fragment - nsCOMPtr metrics; - fragment->GetGlyphMetrics(getter_AddRefs(metrics)); - if (!metrics) return NS_ERROR_FAILURE; PRUint32 fragmentChars = PR_MIN(nchars, count); - float fragmentLength; - nsresult rv = metrics->GetSubStringLength(charnum, - fragmentChars, - &fragmentLength); - if (NS_FAILED(rv)) break; + float fragmentLength = node->GetSubStringLength(charnum, fragmentChars); length += fragmentLength; nchars -= fragmentChars; if (nchars == 0) break; } charnum -= PR_MIN(charnum, count); - fragment = fragment->GetNextGlyphFragment(); + node = GetNextGlyphFragmentChildNode(node); } - // substring too long - if (nchars != 0) return NS_ERROR_DOM_INDEX_SIZE_ERR; - - *_retval = length; - return NS_OK; + return length; } nsresult -nsSVGUtils::GetStartPositionOfChar(nsISVGGlyphFragmentNode* node, +nsSVGUtils::GetStartPositionOfChar(nsFrameList *aFrames, PRUint32 charnum, nsIDOMSVGPoint **_retval) { *_retval = nsnull; - nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(node, charnum); - if (!fragment) return NS_ERROR_DOM_INDEX_SIZE_ERR; + if (charnum >= nsSVGUtils::GetNumberOfChars(aFrames)) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode(aFrames); + if (!node) { + return NS_ERROR_FAILURE; + } + + PRUint32 offset; + nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(node, charnum, &offset); + if (!fragment) { + return NS_ERROR_FAILURE; + } // query the renderer metrics for the start position of the character nsCOMPtr metrics; fragment->GetGlyphMetrics(getter_AddRefs(metrics)); - if (!metrics) return NS_ERROR_FAILURE; - nsresult rv = metrics->GetStartPositionOfChar(charnum-fragment->GetCharNumberOffset(), - _retval); - if (NS_FAILED(rv)) return NS_ERROR_DOM_INDEX_SIZE_ERR; + if (!metrics) { + return NS_ERROR_FAILURE; + } - // offset the bounds by the position of the fragment: - float x,y; - (*_retval)->GetX(&x); - (*_retval)->GetY(&y); - (*_retval)->SetX(x + fragment->GetGlyphPositionX()); - (*_retval)->SetY(y + fragment->GetGlyphPositionY()); - - return NS_OK; + return metrics->GetStartPositionOfChar(charnum - offset, _retval); } nsresult -nsSVGUtils::GetEndPositionOfChar(nsISVGGlyphFragmentNode* node, +nsSVGUtils::GetEndPositionOfChar(nsFrameList *aFrames, PRUint32 charnum, nsIDOMSVGPoint **_retval) { *_retval = nsnull; - nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(node, charnum); - if (!fragment) return NS_ERROR_DOM_INDEX_SIZE_ERR; + if (charnum >= nsSVGUtils::GetNumberOfChars(aFrames)) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode(aFrames); + if (!node) { + return NS_ERROR_FAILURE; + } + + PRUint32 offset; + nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(node, charnum, &offset); + if (!fragment) { + return NS_ERROR_FAILURE; + } // query the renderer metrics for the end position of the character nsCOMPtr metrics; fragment->GetGlyphMetrics(getter_AddRefs(metrics)); - if (!metrics) return NS_ERROR_FAILURE; - nsresult rv = metrics->GetEndPositionOfChar(charnum-fragment->GetCharNumberOffset(), - _retval); - if (NS_FAILED(rv)) return NS_ERROR_DOM_INDEX_SIZE_ERR; + if (!metrics) { + return NS_ERROR_FAILURE; + } - // offset the bounds by the position of the fragment: - float x,y; - (*_retval)->GetX(&x); - (*_retval)->GetY(&y); - (*_retval)->SetX(x + fragment->GetGlyphPositionX()); - (*_retval)->SetY(y + fragment->GetGlyphPositionY()); - - return NS_OK; + return metrics->GetEndPositionOfChar(charnum - offset, _retval); } nsresult -nsSVGUtils::GetExtentOfChar(nsISVGGlyphFragmentNode* node, +nsSVGUtils::GetExtentOfChar(nsFrameList *aFrames, PRUint32 charnum, nsIDOMSVGRect **_retval) { *_retval = nsnull; - nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(node, charnum); - if (!fragment) return NS_ERROR_DOM_INDEX_SIZE_ERR; + if (charnum >= nsSVGUtils::GetNumberOfChars(aFrames)) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode(aFrames); + if (!node) { + return NS_ERROR_FAILURE; + } + + PRUint32 offset; + nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(node, charnum, &offset); + if (!fragment) { + return NS_ERROR_FAILURE; + } // query the renderer metrics for the bounds of the character nsCOMPtr metrics; fragment->GetGlyphMetrics(getter_AddRefs(metrics)); - if (!metrics) return NS_ERROR_FAILURE; - nsresult rv = metrics->GetExtentOfChar(charnum-fragment->GetCharNumberOffset(), - _retval); - if (NS_FAILED(rv)) return NS_ERROR_DOM_INDEX_SIZE_ERR; + if (!metrics) { + return NS_ERROR_FAILURE; + } - // offset the bounds by the position of the fragment: - float x,y; - (*_retval)->GetX(&x); - (*_retval)->GetY(&y); - (*_retval)->SetX(x + fragment->GetGlyphPositionX()); - (*_retval)->SetY(y + fragment->GetGlyphPositionY()); - - return NS_OK; + return metrics->GetExtentOfChar(charnum - offset, _retval); } nsresult -nsSVGUtils::GetRotationOfChar(nsISVGGlyphFragmentNode* node, +nsSVGUtils::GetRotationOfChar(nsFrameList *aFrames, PRUint32 charnum, float *_retval) { - nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(node, charnum); - if (!fragment) return NS_ERROR_DOM_INDEX_SIZE_ERR; + *_retval = 0.0f; + + if (charnum >= nsSVGUtils::GetNumberOfChars(aFrames)) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode(aFrames); + if (!node) { + return NS_ERROR_FAILURE; + } + + PRUint32 offset; + nsISVGGlyphFragmentLeaf *fragment = GetGlyphFragmentAtCharNum(node, charnum, &offset); + if (!fragment) { + return NS_ERROR_FAILURE; + } // query the renderer metrics for the rotation of the character nsCOMPtr metrics; fragment->GetGlyphMetrics(getter_AddRefs(metrics)); - if (!metrics) return NS_ERROR_FAILURE; - nsresult rv = metrics->GetRotationOfChar(charnum-fragment->GetCharNumberOffset(), - _retval); - if (NS_FAILED(rv)) return NS_ERROR_DOM_INDEX_SIZE_ERR; - - return NS_OK; -} - -nsresult -nsSVGUtils::GetCharNumAtPosition(nsISVGGlyphFragmentNode* node, - nsIDOMSVGPoint *point, - PRInt32 *_retval) -{ - PRInt32 index = -1; - nsISVGGlyphFragmentLeaf *fragment = node->GetFirstGlyphFragment(); - - while (fragment) { - if (fragment->GetNumberOfChars() > 0) { - // query the renderer metrics for the character position - nsCOMPtr metrics; - fragment->GetGlyphMetrics(getter_AddRefs(metrics)); - if (!metrics) return NS_ERROR_FAILURE; - - // subtract the fragment offset from the position: - float x,y; - point->GetX(&x); - point->GetY(&y); - - nsCOMPtr position; - NS_NewSVGPoint(getter_AddRefs(position), - x - fragment->GetGlyphPositionX(), - y - fragment->GetGlyphPositionY()); - if (!position) - return NS_ERROR_FAILURE; - - nsresult rv = metrics->GetCharNumAtPosition(position, &index); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - - // Multiple characters may match, we must return the last one - // so no break here - } - fragment = fragment->GetNextGlyphFragment(); + if (!metrics) { + return NS_ERROR_FAILURE; } - *_retval = index; - return NS_OK; + return metrics->GetRotationOfChar(charnum - offset, _retval); +} + +PRInt32 +nsSVGUtils::GetCharNumAtPosition(nsFrameList *aFrames, + nsIDOMSVGPoint *point) +{ + PRInt32 index = -1; + PRInt32 offset = 0; + nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode(aFrames); + + while (node) { + PRUint32 count = node->GetNumberOfChars(); + if (count > 0) { + PRInt32 charnum = node->GetCharNumAtPosition(point); + if (charnum >= 0) { + index = charnum + offset; + } + offset += count; + // Keep going, multiple characters may match + // and we must return the last one + } + node = GetNextGlyphFragmentChildNode(node); + } + + return index; } nsRect @@ -551,15 +603,18 @@ nsSVGUtils::GetSurface(nsISVGOuterSVGFrame *aOuterSVGFrame, nsISVGGlyphFragmentLeaf * nsSVGUtils::GetGlyphFragmentAtCharNum(nsISVGGlyphFragmentNode* node, - PRUint32 charnum) + PRUint32 charnum, + PRUint32 *offset) { nsISVGGlyphFragmentLeaf *fragment = node->GetFirstGlyphFragment(); + *offset = 0; while (fragment) { PRUint32 count = fragment->GetNumberOfChars(); if (count > charnum) return fragment; charnum -= count; + *offset += count; fragment = fragment->GetNextGlyphFragment(); } diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index c45ab599f781..d072d53d9644 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -125,60 +125,84 @@ public: */ static nsresult GetBBox(nsFrameList *aFrames, nsIDOMSVGRect **_retval); + /* + * Returns the first child node for a frame + */ + static nsISVGGlyphFragmentNode * + GetFirstGlyphFragmentChildNode(nsFrameList *aFrames); + + /* + * Returns the next child node for a frame + */ + static nsISVGGlyphFragmentNode * + GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode *node); + + /* + * Build the glyph fragment tree + */ + static PRUint32 + nsSVGUtils::BuildGlyphFragmentTree(nsFrameList *aFrames, + PRUint32 charNum, + PRBool lastBranch); + /* * Returns the number of characters in a string */ - static nsresult GetNumberOfChars(nsISVGGlyphFragmentNode* node, - PRInt32 *_retval); + static PRUint32 GetNumberOfChars(nsFrameList *aFrames); /* * Determines the length of a string */ - static nsresult GetComputedTextLength(nsISVGGlyphFragmentNode* node, - float *_retval); + static float GetComputedTextLength(nsFrameList *aFrames); /* * Determines the length of a substring */ - static nsresult GetSubStringLength(nsISVGGlyphFragmentNode* node, + static nsresult GetSubStringLength(nsFrameList *aFrames, PRUint32 charnum, PRUint32 nchars, float *_retval); + /* + * Determines the length of a substring + */ + static float GetSubStringLengthNoValidation(nsFrameList *aFrames, + PRUint32 charnum, + PRUint32 nchars); + /* * Determines the start position of a character */ - static nsresult GetStartPositionOfChar(nsISVGGlyphFragmentNode* node, + static nsresult GetStartPositionOfChar(nsFrameList *aFrames, PRUint32 charnum, nsIDOMSVGPoint **_retval); /* * Determines the end position of a character */ - static nsresult GetEndPositionOfChar(nsISVGGlyphFragmentNode* node, + static nsresult GetEndPositionOfChar(nsFrameList *aFrames, PRUint32 charnum, nsIDOMSVGPoint **_retval); /* * Determines the bounds of a character */ - static nsresult GetExtentOfChar(nsISVGGlyphFragmentNode* node, + static nsresult GetExtentOfChar(nsFrameList *aFrames, PRUint32 charnum, nsIDOMSVGRect **_retval); /* * Determines the rotation of a character */ - static nsresult GetRotationOfChar(nsISVGGlyphFragmentNode* node, + static nsresult GetRotationOfChar(nsFrameList *aFrames, PRUint32 charnum, float *_retval); /* * Get the character at the specified position */ - static nsresult GetCharNumAtPosition(nsISVGGlyphFragmentNode* node, - nsIDOMSVGPoint *point, - PRInt32 *_retval); + static PRInt32 GetCharNumAtPosition(nsFrameList *aFrames, + nsIDOMSVGPoint *point); /* * Figures out the worst case invalidation area for a frame, taking @@ -297,7 +321,8 @@ private: */ static nsISVGGlyphFragmentLeaf * GetGlyphFragmentAtCharNum(nsISVGGlyphFragmentNode* node, - PRUint32 charnum); + PRUint32 charnum, + PRUint32 *offset); }; #endif diff --git a/layout/svg/renderer/public/nsISVGGlyphMetricsSource.idl b/layout/svg/renderer/public/nsISVGGlyphMetricsSource.idl index c6d2af573c91..dca6c7af914b 100644 --- a/layout/svg/renderer/public/nsISVGGlyphMetricsSource.idl +++ b/layout/svg/renderer/public/nsISVGGlyphMetricsSource.idl @@ -68,7 +68,7 @@ native nsFont(nsFont); * * @nosubgrouping */ -[uuid(06937879-37a4-4ffb-8b44-917f030f1651)] +[uuid(de843094-3dc6-4b4c-b754-a4b535397792)] interface nsISVGGlyphMetricsSource : nsISupports { /** @@ -92,6 +92,14 @@ interface nsISVGGlyphMetricsSource : nsISupports void GetCharacterPosition(out nsSVGCharacterPosition aCP); /** @} */ + /** + * @name String positioning information (if no character positions) + * @{ + */ + void GetGlyphPosition(out float glyphPositionX, out float glyphPositionY); + /** @} */ + + /** * @name Text rendering mode * @{ diff --git a/layout/svg/renderer/src/cairo/nsSVGCairoGlyphMetrics.cpp b/layout/svg/renderer/src/cairo/nsSVGCairoGlyphMetrics.cpp index 118cfd6bebbe..0cb223f59202 100644 --- a/layout/svg/renderer/src/cairo/nsSVGCairoGlyphMetrics.cpp +++ b/layout/svg/renderer/src/cairo/nsSVGCairoGlyphMetrics.cpp @@ -244,6 +244,8 @@ nsSVGCairoGlyphMetrics::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint y = cp[charnum].y; } else { + mSource->GetGlyphPosition(&x, &y); + if (charnum > 0) { cairo_text_extents_t extent; @@ -253,10 +255,8 @@ nsSVGCairoGlyphMetrics::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint charnum)).get(), &extent); - x = extent.x_advance; - y = extent.y_advance; - } else { - x = y = 0.0f; + x += extent.x_advance; + y += extent.y_advance; } } @@ -279,12 +279,12 @@ nsSVGCairoGlyphMetrics::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint ** SelectFont(mCT); + cairo_text_extents_t extent; + if (cp) { if (cp[charnum].draw == PR_FALSE) return NS_ERROR_DOM_INDEX_SIZE_ERR; - cairo_text_extents_t extent; - cairo_text_extents(mCT, NS_ConvertUTF16toUTF8(Substring(text, charnum, 1)).get(), &extent); @@ -296,14 +296,15 @@ nsSVGCairoGlyphMetrics::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint ** cp[charnum].x + extent.x_advance * c - extent.y_advance * s, cp[charnum].y + extent.y_advance * c + extent.x_advance * s); } - - cairo_text_extents_t extent; - + + float x, y; + mSource->GetGlyphPosition(&x, &y); + cairo_text_extents(mCT, NS_ConvertUTF16toUTF8(Substring(text, 0, charnum + 1)).get(), &extent); - return NS_NewSVGPoint(_retval, extent.x_advance, extent.y_advance); + return NS_NewSVGPoint(_retval, x + extent.x_advance, y + extent.y_advance); } /** Implements nsIDOMSVGRect getExtentOfChar(in unsigned long charnum); */ @@ -354,26 +355,28 @@ nsSVGCairoGlyphMetrics::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retva return NS_NewSVGRect(_retval, xmin, ymin, xmax - xmin, ymax - ymin); } + float x, y; + mSource->GetGlyphPosition(&x, &y); + + x += extent.x_bearing; + y += extent.y_bearing; + cairo_text_extents_t precedingExtent; if (charnum > 0) { + // add the space taken up by the text which comes before charnum + // to the position of the charnum character cairo_text_extents(mCT, NS_ConvertUTF16toUTF8(Substring(text, 0, charnum)).get(), &precedingExtent); - } else { - precedingExtent.x_advance = 0.0; - precedingExtent.y_advance = 0.0; + + x += precedingExtent.x_advance; + y += precedingExtent.y_advance; } - // add the space taken up by the text which comes before charnum - // to the position of the charnum character - return NS_NewSVGRect(_retval, - precedingExtent.x_advance + extent.x_bearing, - precedingExtent.y_advance + extent.y_bearing, - extent.width, - extent.height); + return NS_NewSVGRect(_retval, x, y, extent.width, extent.height); } /** Implements float getRotationOfChar(in unsigned long charnum); */ @@ -405,9 +408,11 @@ nsSVGCairoGlyphMetrics::GetRotationOfChar(PRUint32 charnum, float *_retval) NS_IMETHODIMP nsSVGCairoGlyphMetrics::GetCharNumAtPosition(nsIDOMSVGPoint *point, PRInt32 *_retval) { - float x,y; - point->GetX(&x); - point->GetY(&y); + *_retval = -1; + + float xPos, yPos; + point->GetX(&xPos); + point->GetY(&yPos); nsAutoString text; mSource->GetCharacterData(text); @@ -417,6 +422,11 @@ nsSVGCairoGlyphMetrics::GetCharNumAtPosition(nsIDOMSVGPoint *point, PRInt32 *_re if (NS_FAILED(mSource->GetCharacterPosition(getter_Transfers(cp)))) return NS_ERROR_FAILURE; + float x, y; + if (!cp) { + mSource->GetGlyphPosition(&x, &y); + } + for (PRUint32 charnum = 0; charnum < text.Length(); charnum++) { /* character actually on the path? */ if (cp && cp[charnum].draw == PR_FALSE) @@ -438,9 +448,9 @@ nsSVGCairoGlyphMetrics::GetCharNumAtPosition(nsIDOMSVGPoint *point, PRInt32 *_re 0, charnum)).get(), &extent); - cairo_move_to(mCT, extent.x_advance, extent.y_advance); + cairo_move_to(mCT, x + extent.x_advance, y + extent.y_advance); } else { - cairo_move_to(mCT, 0.0, 0.0); + cairo_move_to(mCT, x, y); } } cairo_text_extents_t extent; @@ -455,7 +465,7 @@ nsSVGCairoGlyphMetrics::GetCharNumAtPosition(nsIDOMSVGPoint *point, PRInt32 *_re cairo_close_path(mCT); cairo_identity_matrix(mCT); - if (cairo_in_fill(mCT, x, y)) + if (cairo_in_fill(mCT, xPos, yPos)) *_retval = charnum; cairo_set_matrix(mCT, &matrix);