1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Mozilla SVG project.
17 * The Initial Developer of the Original Code is IBM Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2006
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "nsSVGContainerFrame.h"
38 #include "nsSVGTextFrame.h"
39 #include "nsSVGUtils.h"
40 #include "nsSVGMatrix.h"
41 #include "nsSVGOuterSVGFrame.h"
42 #include "nsIDOMSVGTextElement.h"
43 #include "nsIDOMSVGAnimatedLengthList.h"
44 #include "nsISVGGlyphFragmentLeaf.h"
45 #include "nsDOMError.h"
47 //----------------------------------------------------------------------
48 // nsISupports methods
50 NS_INTERFACE_MAP_BEGIN(nsSVGTextContainerFrame
)
51 NS_INTERFACE_MAP_ENTRY(nsISVGTextContentMetrics
)
52 NS_INTERFACE_MAP_END_INHERITING(nsSVGDisplayContainerFrame
)
55 nsSVGTextContainerFrame::NotifyGlyphMetricsChange()
57 nsSVGTextFrame
*textFrame
= GetTextFrame();
59 textFrame
->NotifyGlyphMetricsChange();
62 NS_IMETHODIMP_(already_AddRefed
<nsIDOMSVGLengthList
>)
63 nsSVGTextContainerFrame::GetX()
65 nsCOMPtr
<nsIDOMSVGTextPositioningElement
> tpElement
=
66 do_QueryInterface(mContent
);
71 if (!mContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::x
))
74 nsCOMPtr
<nsIDOMSVGAnimatedLengthList
> animLengthList
;
75 tpElement
->GetX(getter_AddRefs(animLengthList
));
76 nsIDOMSVGLengthList
*retval
;
77 animLengthList
->GetAnimVal(&retval
);
81 NS_IMETHODIMP_(already_AddRefed
<nsIDOMSVGLengthList
>)
82 nsSVGTextContainerFrame::GetY()
84 nsCOMPtr
<nsIDOMSVGTextPositioningElement
> tpElement
=
85 do_QueryInterface(mContent
);
90 if (!mContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::y
))
93 nsCOMPtr
<nsIDOMSVGAnimatedLengthList
> animLengthList
;
94 tpElement
->GetY(getter_AddRefs(animLengthList
));
95 nsIDOMSVGLengthList
*retval
;
96 animLengthList
->GetAnimVal(&retval
);
100 NS_IMETHODIMP_(already_AddRefed
<nsIDOMSVGLengthList
>)
101 nsSVGTextContainerFrame::GetDx()
103 nsCOMPtr
<nsIDOMSVGTextPositioningElement
> tpElement
=
104 do_QueryInterface(mContent
);
109 nsCOMPtr
<nsIDOMSVGAnimatedLengthList
> animLengthList
;
110 tpElement
->GetDx(getter_AddRefs(animLengthList
));
111 nsIDOMSVGLengthList
*retval
;
112 animLengthList
->GetAnimVal(&retval
);
116 NS_IMETHODIMP_(already_AddRefed
<nsIDOMSVGLengthList
>)
117 nsSVGTextContainerFrame::GetDy()
119 nsCOMPtr
<nsIDOMSVGTextPositioningElement
> tpElement
=
120 do_QueryInterface(mContent
);
125 nsCOMPtr
<nsIDOMSVGAnimatedLengthList
> animLengthList
;
126 tpElement
->GetDy(getter_AddRefs(animLengthList
));
127 nsIDOMSVGLengthList
*retval
;
128 animLengthList
->GetAnimVal(&retval
);
132 //----------------------------------------------------------------------
136 nsSVGTextContainerFrame::InsertFrames(nsIAtom
* aListName
,
137 nsIFrame
* aPrevFrame
,
138 nsIFrame
* aFrameList
)
140 nsresult rv
= nsSVGDisplayContainerFrame::InsertFrames(aListName
,
144 NotifyGlyphMetricsChange();
149 nsSVGTextContainerFrame::RemoveFrame(nsIAtom
*aListName
, nsIFrame
*aOldFrame
)
151 nsSVGTextFrame
*textFrame
= GetTextFrame();
153 nsresult rv
= nsSVGDisplayContainerFrame::RemoveFrame(aListName
, aOldFrame
);
156 textFrame
->NotifyGlyphMetricsChange();
161 //----------------------------------------------------------------------
162 // nsISVGTextContentMetrics methods
165 nsSVGTextContainerFrame::GetNumberOfChars(PRInt32
*_retval
)
167 *_retval
= GetNumberOfChars();
173 nsSVGTextContainerFrame::GetComputedTextLength(float *_retval
)
175 *_retval
= GetComputedTextLength();
181 nsSVGTextContainerFrame::GetSubStringLength(PRUint32 charnum
,
185 PRUint32 charcount
= GetNumberOfChars();
186 if (charcount
<= charnum
|| nchars
> charcount
- charnum
) {
188 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
196 *_retval
= GetSubStringLengthNoValidation(charnum
, nchars
);
202 nsSVGTextContainerFrame::GetStartPositionOfChar(PRUint32 charnum
, nsIDOMSVGPoint
**_retval
)
206 if (charnum
>= GetNumberOfChars()) {
207 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
210 nsISVGGlyphFragmentNode
*node
= GetFirstGlyphFragmentChildNode();
212 return NS_ERROR_FAILURE
;
216 nsISVGGlyphFragmentLeaf
*fragment
= GetGlyphFragmentAtCharNum(node
, charnum
, &offset
);
218 return NS_ERROR_FAILURE
;
221 return fragment
->GetStartPositionOfChar(charnum
- offset
, _retval
);
225 nsSVGTextContainerFrame::GetEndPositionOfChar(PRUint32 charnum
, nsIDOMSVGPoint
**_retval
)
229 if (charnum
>= GetNumberOfChars()) {
230 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
233 nsISVGGlyphFragmentNode
*node
= GetFirstGlyphFragmentChildNode();
235 return NS_ERROR_FAILURE
;
239 nsISVGGlyphFragmentLeaf
*fragment
= GetGlyphFragmentAtCharNum(node
, charnum
, &offset
);
241 return NS_ERROR_FAILURE
;
244 return fragment
->GetEndPositionOfChar(charnum
- offset
, _retval
);
248 nsSVGTextContainerFrame::GetExtentOfChar(PRUint32 charnum
, nsIDOMSVGRect
**_retval
)
252 if (charnum
>= GetNumberOfChars()) {
253 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
256 nsISVGGlyphFragmentNode
*node
= GetFirstGlyphFragmentChildNode();
258 return NS_ERROR_FAILURE
;
262 nsISVGGlyphFragmentLeaf
*fragment
= GetGlyphFragmentAtCharNum(node
, charnum
, &offset
);
264 return NS_ERROR_FAILURE
;
267 return fragment
->GetExtentOfChar(charnum
- offset
, _retval
);
271 nsSVGTextContainerFrame::GetRotationOfChar(PRUint32 charnum
, float *_retval
)
275 if (charnum
>= GetNumberOfChars()) {
276 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
279 nsISVGGlyphFragmentNode
*node
= GetFirstGlyphFragmentChildNode();
281 return NS_ERROR_FAILURE
;
285 nsISVGGlyphFragmentLeaf
*fragment
= GetGlyphFragmentAtCharNum(node
, charnum
, &offset
);
287 return NS_ERROR_FAILURE
;
290 return fragment
->GetRotationOfChar(charnum
- offset
, _retval
);
294 nsSVGTextContainerFrame::GetCharNumAtPosition(nsIDOMSVGPoint
*point
, PRInt32
*_retval
)
296 *_retval
= GetCharNumAtPosition(point
);
301 // -------------------------------------------------------------------------
302 // Protected functions
303 // -------------------------------------------------------------------------
305 nsISVGGlyphFragmentNode
*
306 nsSVGTextContainerFrame::GetFirstGlyphFragmentChildNode()
308 nsISVGGlyphFragmentNode
*retval
= nsnull
;
309 nsIFrame
* kid
= mFrames
.FirstChild();
311 CallQueryInterface(kid
, &retval
);
313 kid
= kid
->GetNextSibling();
318 nsISVGGlyphFragmentNode
*
319 nsSVGTextContainerFrame::GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode
*node
)
321 nsISVGGlyphFragmentNode
*retval
= nsnull
;
322 nsIFrame
*frame
= nsnull
;
323 CallQueryInterface(node
, &frame
);
324 NS_ASSERTION(frame
, "interface not implemented");
325 frame
= frame
->GetNextSibling();
327 CallQueryInterface(frame
, &retval
);
329 frame
= frame
->GetNextSibling();
335 nsSVGTextContainerFrame::SetWhitespaceHandling()
338 nsISVGGlyphFragmentNode
* node
= GetFirstGlyphFragmentChildNode();
339 nsISVGGlyphFragmentNode
* next
;
341 PRUint8 whitespaceHandling
= COMPRESS_WHITESPACE
| TRIM_LEADING_WHITESPACE
;
343 for (nsIFrame
*frame
= this; frame
!= nsnull
; frame
= frame
->GetParent()) {
344 nsIContent
*content
= frame
->GetContent();
345 static nsIContent::AttrValuesArray strings
[] =
346 {&nsGkAtoms::preserve
, &nsGkAtoms::_default
, nsnull
};
348 PRInt32 index
= content
->FindAttrValueIn(kNameSpaceID_XML
,
350 strings
, eCaseMatters
);
352 whitespaceHandling
= PRESERVE_WHITESPACE
;
355 if (index
!= nsIContent::ATTR_MISSING
||
356 (frame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
))
361 next
= GetNextGlyphFragmentChildNode(node
);
362 if (!next
&& (whitespaceHandling
& COMPRESS_WHITESPACE
)) {
363 whitespaceHandling
|= TRIM_TRAILING_WHITESPACE
;
365 node
->SetWhitespaceHandling(whitespaceHandling
);
367 whitespaceHandling
&= ~TRIM_LEADING_WHITESPACE
;
372 nsSVGTextContainerFrame::GetNumberOfChars()
375 nsISVGGlyphFragmentNode
* node
;
376 node
= GetFirstGlyphFragmentChildNode();
379 nchars
+= node
->GetNumberOfChars();
380 node
= GetNextGlyphFragmentChildNode(node
);
387 nsSVGTextContainerFrame::GetComputedTextLength()
390 nsISVGGlyphFragmentNode
* node
= GetFirstGlyphFragmentChildNode();
393 length
+= node
->GetComputedTextLength();
394 node
= GetNextGlyphFragmentChildNode(node
);
401 nsSVGTextContainerFrame::GetSubStringLengthNoValidation(PRUint32 charnum
,
405 nsISVGGlyphFragmentNode
*node
= GetFirstGlyphFragmentChildNode();
408 PRUint32 count
= node
->GetNumberOfChars();
409 if (count
> charnum
) {
410 PRUint32 fragmentChars
= PR_MIN(nchars
, count
);
411 float fragmentLength
= node
->GetSubStringLength(charnum
, fragmentChars
);
412 length
+= fragmentLength
;
413 nchars
-= fragmentChars
;
414 if (nchars
== 0) break;
416 charnum
-= PR_MIN(charnum
, count
);
417 node
= GetNextGlyphFragmentChildNode(node
);
424 nsSVGTextContainerFrame::GetCharNumAtPosition(nsIDOMSVGPoint
*point
)
428 nsISVGGlyphFragmentNode
*node
= GetFirstGlyphFragmentChildNode();
431 PRUint32 count
= node
->GetNumberOfChars();
433 PRInt32 charnum
= node
->GetCharNumAtPosition(point
);
435 index
= charnum
+ offset
;
438 // Keep going, multiple characters may match
439 // and we must return the last one
441 node
= GetNextGlyphFragmentChildNode(node
);
447 // -------------------------------------------------------------------------
449 // -------------------------------------------------------------------------
451 nsISVGGlyphFragmentLeaf
*
452 nsSVGTextContainerFrame::GetGlyphFragmentAtCharNum(nsISVGGlyphFragmentNode
* node
,
456 nsISVGGlyphFragmentLeaf
*fragment
= node
->GetFirstGlyphFragment();
460 PRUint32 count
= fragment
->GetNumberOfChars();
465 fragment
= fragment
->GetNextGlyphFragment();
473 nsSVGTextContainerFrame::GetTextFrame()
475 for (nsIFrame
*frame
= this; frame
!= nsnull
; frame
= frame
->GetParent()) {
476 if (frame
->GetType() == nsGkAtoms::svgTextFrame
) {
477 return static_cast<nsSVGTextFrame
*>(frame
);