LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGTextContainerFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 239 0 0.0 %
Date: 2012-06-02 Functions: 28 0 0.0 %

       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
       4                 :  *
       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/
       9                 :  *
      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
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla SVG project.
      16                 :  *
      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.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      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.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "nsSVGContainerFrame.h"
      38                 : #include "nsSVGTextFrame.h"
      39                 : #include "nsSVGUtils.h"
      40                 : #include "nsSVGOuterSVGFrame.h"
      41                 : #include "nsIDOMSVGTextElement.h"
      42                 : #include "nsIDOMSVGAnimatedLengthList.h"
      43                 : #include "SVGAnimatedNumberList.h"
      44                 : #include "SVGNumberList.h"
      45                 : #include "nsSVGGlyphFrame.h"
      46                 : #include "nsDOMError.h"
      47                 : #include "SVGLengthList.h"
      48                 : #include "nsSVGTextPositioningElement.h"
      49                 : 
      50                 : using namespace mozilla;
      51                 : 
      52                 : //----------------------------------------------------------------------
      53                 : // nsQueryFrame methods
      54                 : 
      55               0 : NS_QUERYFRAME_HEAD(nsSVGTextContainerFrame)
      56               0 :   NS_QUERYFRAME_ENTRY(nsSVGTextContainerFrame)
      57               0 : NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
      58                 : 
      59               0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGTextContainerFrame)
      60                 : 
      61                 : void
      62               0 : nsSVGTextContainerFrame::NotifyGlyphMetricsChange()
      63                 : {
      64               0 :   nsSVGTextFrame *textFrame = GetTextFrame();
      65               0 :   if (textFrame)
      66               0 :     textFrame->NotifyGlyphMetricsChange();
      67               0 : }
      68                 : 
      69                 : void
      70               0 : nsSVGTextContainerFrame::GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY)
      71                 : {
      72                 :   static_cast<nsSVGElement*>(mContent)->
      73               0 :     GetAnimatedLengthListValues(aX, aY, nsnull);
      74               0 : }
      75                 : 
      76                 : void
      77               0 : nsSVGTextContainerFrame::GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy)
      78                 : {
      79                 :   // SVGUserUnitList is lazy, so there's little overhead it getting the x
      80                 :   // and y lists even though we ignore them.
      81               0 :   SVGUserUnitList xLengthList, yLengthList;
      82                 :   static_cast<nsSVGElement*>(mContent)->
      83               0 :     GetAnimatedLengthListValues(&xLengthList, &yLengthList, aDx, aDy, nsnull);
      84               0 : }
      85                 : 
      86                 : const SVGNumberList*
      87               0 : nsSVGTextContainerFrame::GetRotate()
      88                 : {
      89                 :   SVGAnimatedNumberList *animList =
      90                 :     static_cast<nsSVGElement*>(mContent)->
      91               0 :       GetAnimatedNumberList(nsGkAtoms::rotate);
      92               0 :   return animList ? &animList->GetAnimValue() : nsnull;
      93                 : }
      94                 : 
      95                 : //----------------------------------------------------------------------
      96                 : // nsIFrame methods
      97                 : 
      98                 : NS_IMETHODIMP
      99               0 : nsSVGTextContainerFrame::InsertFrames(ChildListID aListID,
     100                 :                                       nsIFrame* aPrevFrame,
     101                 :                                       nsFrameList& aFrameList)
     102                 : {
     103                 :   nsresult rv = nsSVGDisplayContainerFrame::InsertFrames(aListID,
     104                 :                                                          aPrevFrame,
     105               0 :                                                          aFrameList);
     106                 : 
     107               0 :   NotifyGlyphMetricsChange();
     108               0 :   return rv;
     109                 : }
     110                 : 
     111                 : NS_IMETHODIMP
     112               0 : nsSVGTextContainerFrame::RemoveFrame(ChildListID aListID, nsIFrame *aOldFrame)
     113                 : {
     114               0 :   nsSVGTextFrame *textFrame = GetTextFrame();
     115                 : 
     116               0 :   nsresult rv = nsSVGDisplayContainerFrame::RemoveFrame(aListID, aOldFrame);
     117                 : 
     118               0 :   if (textFrame)
     119               0 :     textFrame->NotifyGlyphMetricsChange();
     120                 : 
     121               0 :   return rv;
     122                 : }
     123                 : 
     124                 : NS_IMETHODIMP
     125               0 : nsSVGTextContainerFrame::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval)
     126                 : {
     127               0 :   *_retval = nsnull;
     128                 : 
     129               0 :   if (charnum >= GetNumberOfChars()) {
     130               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     131                 :   }
     132                 : 
     133               0 :   nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode();
     134               0 :   if (!node) {
     135               0 :     return NS_ERROR_FAILURE;
     136                 :   }
     137                 : 
     138                 :   PRUint32 offset;
     139               0 :   nsSVGGlyphFrame *frame = GetGlyphFrameAtCharNum(node, charnum, &offset);
     140               0 :   if (!frame) {
     141               0 :     return NS_ERROR_FAILURE;
     142                 :   }
     143                 : 
     144               0 :   return frame->GetStartPositionOfChar(charnum - offset, _retval);
     145                 : }
     146                 : 
     147                 : NS_IMETHODIMP
     148               0 : nsSVGTextContainerFrame::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval)
     149                 : {
     150               0 :   *_retval = nsnull;
     151                 : 
     152               0 :   if (charnum >= GetNumberOfChars()) {
     153               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     154                 :   }
     155                 : 
     156               0 :   nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode();
     157               0 :   if (!node) {
     158               0 :     return NS_ERROR_FAILURE;
     159                 :   }
     160                 : 
     161                 :   PRUint32 offset;
     162               0 :   nsSVGGlyphFrame *frame = GetGlyphFrameAtCharNum(node, charnum, &offset);
     163               0 :   if (!frame) {
     164               0 :     return NS_ERROR_FAILURE;
     165                 :   }
     166                 : 
     167               0 :   return frame->GetEndPositionOfChar(charnum - offset, _retval);
     168                 : }
     169                 : 
     170                 : NS_IMETHODIMP
     171               0 : nsSVGTextContainerFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
     172                 : {
     173               0 :   *_retval = nsnull;
     174                 : 
     175               0 :   if (charnum >= GetNumberOfChars()) {
     176               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     177                 :   }
     178                 : 
     179               0 :   nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode();
     180               0 :   if (!node) {
     181               0 :     return NS_ERROR_FAILURE;
     182                 :   }
     183                 : 
     184                 :   PRUint32 offset;
     185               0 :   nsSVGGlyphFrame *frame = GetGlyphFrameAtCharNum(node, charnum, &offset);
     186               0 :   if (!frame) {
     187               0 :     return NS_ERROR_FAILURE;
     188                 :   }
     189                 : 
     190               0 :   return frame->GetExtentOfChar(charnum - offset, _retval);
     191                 : }
     192                 : 
     193                 : NS_IMETHODIMP
     194               0 : nsSVGTextContainerFrame::GetRotationOfChar(PRUint32 charnum, float *_retval)
     195                 : {
     196               0 :   *_retval = 0.0f;
     197                 : 
     198               0 :   if (charnum >= GetNumberOfChars()) {
     199               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
     200                 :   }
     201                 : 
     202               0 :   nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode();
     203               0 :   if (!node) {
     204               0 :     return NS_ERROR_FAILURE;
     205                 :   }
     206                 : 
     207                 :   PRUint32 offset;
     208               0 :   nsSVGGlyphFrame *frame = GetGlyphFrameAtCharNum(node, charnum, &offset);
     209               0 :   if (!frame) {
     210               0 :     return NS_ERROR_FAILURE;
     211                 :   }
     212                 : 
     213               0 :   return frame->GetRotationOfChar(charnum - offset, _retval);
     214                 : }
     215                 : 
     216                 : PRUint32
     217               0 : nsSVGTextContainerFrame::GetNumberOfChars()
     218                 : {
     219               0 :   PRUint32 nchars = 0;
     220               0 :   nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
     221                 : 
     222               0 :   while (node) {
     223               0 :     nchars += node->GetNumberOfChars();
     224               0 :     node = GetNextGlyphFragmentChildNode(node);
     225                 :   }
     226                 : 
     227               0 :   return nchars;
     228                 : }
     229                 : 
     230                 : float
     231               0 : nsSVGTextContainerFrame::GetComputedTextLength()
     232                 : {
     233               0 :   float length = 0.0f;
     234               0 :   nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
     235                 : 
     236               0 :   while (node) {
     237               0 :     length += node->GetComputedTextLength();
     238               0 :     node = GetNextGlyphFragmentChildNode(node);
     239                 :   }
     240                 : 
     241               0 :   return length;
     242                 : }
     243                 : 
     244                 : float
     245               0 : nsSVGTextContainerFrame::GetSubStringLength(PRUint32 charnum, PRUint32 nchars)
     246                 : {
     247               0 :   float length = 0.0f;
     248               0 :   nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode();
     249                 : 
     250               0 :   while (node) {
     251               0 :     PRUint32 count = node->GetNumberOfChars();
     252               0 :     if (count > charnum) {
     253               0 :       PRUint32 fragmentChars = NS_MIN(nchars, count);
     254               0 :       float fragmentLength = node->GetSubStringLength(charnum, fragmentChars);
     255               0 :       length += fragmentLength;
     256               0 :       nchars -= fragmentChars;
     257               0 :       if (nchars == 0) break;
     258                 :     }
     259               0 :     charnum -= NS_MIN(charnum, count);
     260               0 :     node = GetNextGlyphFragmentChildNode(node);
     261                 :   }
     262                 : 
     263               0 :   return length;
     264                 : }
     265                 : 
     266                 : PRInt32
     267               0 : nsSVGTextContainerFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point)
     268                 : {
     269               0 :   PRInt32 index = -1;
     270               0 :   PRInt32 offset = 0;
     271               0 :   nsISVGGlyphFragmentNode *node = GetFirstGlyphFragmentChildNode();
     272                 : 
     273               0 :   while (node) {
     274               0 :     PRUint32 count = node->GetNumberOfChars();
     275               0 :     if (count > 0) {
     276               0 :       PRInt32 charnum = node->GetCharNumAtPosition(point);
     277               0 :       if (charnum >= 0) {
     278               0 :         index = charnum + offset;
     279                 :       }
     280               0 :       offset += count;
     281                 :       // Keep going, multiple characters may match 
     282                 :       // and we must return the last one
     283                 :     }
     284               0 :     node = GetNextGlyphFragmentChildNode(node);
     285                 :   }
     286                 : 
     287               0 :   return index;
     288                 : }
     289                 : 
     290                 : // -------------------------------------------------------------------------
     291                 : // Protected functions
     292                 : // -------------------------------------------------------------------------
     293                 : 
     294                 : nsISVGGlyphFragmentNode *
     295               0 : nsSVGTextContainerFrame::GetFirstGlyphFragmentChildNode()
     296                 : {
     297               0 :   nsISVGGlyphFragmentNode *retval = nsnull;
     298               0 :   nsIFrame* kid = mFrames.FirstChild();
     299               0 :   while (kid) {
     300               0 :     retval = do_QueryFrame(kid);
     301               0 :     if (retval) break;
     302               0 :     kid = kid->GetNextSibling();
     303                 :   }
     304               0 :   return retval;
     305                 : }
     306                 : 
     307                 : nsISVGGlyphFragmentNode *
     308               0 : nsSVGTextContainerFrame::GetNextGlyphFragmentChildNode(nsISVGGlyphFragmentNode *node)
     309                 : {
     310               0 :   nsISVGGlyphFragmentNode *retval = nsnull;
     311               0 :   nsIFrame *frame = do_QueryFrame(node);
     312               0 :   NS_ASSERTION(frame, "interface not implemented");
     313               0 :   frame = frame->GetNextSibling();
     314               0 :   while (frame) {
     315               0 :     retval = do_QueryFrame(frame);
     316               0 :     if (retval) break;
     317               0 :     frame = frame->GetNextSibling();
     318                 :   }
     319               0 :   return retval;
     320                 : }
     321                 : 
     322                 : // -------------------------------------------------------------------------
     323                 : // Private functions
     324                 : // -------------------------------------------------------------------------
     325                 : 
     326                 : nsSVGGlyphFrame *
     327               0 : nsSVGTextContainerFrame::GetGlyphFrameAtCharNum(nsISVGGlyphFragmentNode* node,
     328                 :                                                 PRUint32 charnum,
     329                 :                                                 PRUint32 *offset)
     330                 : {
     331               0 :   nsSVGGlyphFrame *frame = node->GetFirstGlyphFrame();
     332               0 :   *offset = 0;
     333                 :   
     334               0 :   while (frame) {
     335               0 :     PRUint32 count = frame->GetNumberOfChars();
     336               0 :     if (count > charnum)
     337               0 :       return frame;
     338               0 :     charnum -= count;
     339               0 :     *offset += count;
     340               0 :     frame = frame->GetNextGlyphFrame();
     341                 :   }
     342                 : 
     343                 :   // not found
     344               0 :   return nsnull;
     345                 : }
     346                 : 
     347                 : nsSVGTextFrame *
     348               0 : nsSVGTextContainerFrame::GetTextFrame()
     349                 : {
     350               0 :   for (nsIFrame *frame = this; frame != nsnull; frame = frame->GetParent()) {
     351               0 :     if (frame->GetType() == nsGkAtoms::svgTextFrame) {
     352               0 :       return static_cast<nsSVGTextFrame*>(frame);
     353                 :     }
     354                 :   }
     355               0 :   return nsnull;
     356                 : }
     357                 : 
     358                 : void
     359               0 : nsSVGTextContainerFrame::CopyPositionList(nsTArray<float> *parentList,
     360                 :                                         SVGUserUnitList *selfList,
     361                 :                                         nsTArray<float> &dstList,
     362                 :                                         PRUint32 aOffset)
     363                 : {
     364               0 :   dstList.Clear();
     365                 : 
     366               0 :   PRUint32 strLength = GetNumberOfChars();
     367               0 :   PRUint32 parentCount = 0;
     368               0 :   if (parentList && parentList->Length() > aOffset) {
     369               0 :     parentCount = NS_MIN(parentList->Length() - aOffset, strLength);
     370                 :   }
     371                 : 
     372               0 :   PRUint32 selfCount = NS_MIN(selfList->Length(), strLength);
     373                 : 
     374               0 :   PRUint32 count = NS_MAX(parentCount, selfCount);
     375                 : 
     376               0 :   if (!dstList.SetLength(count))
     377               0 :     return;
     378                 : 
     379               0 :   for (PRUint32 i = 0; i < selfCount; i++) {
     380               0 :     dstList[i] = (*selfList)[i];
     381                 :   }
     382               0 :   for (PRUint32 i = selfCount; i < parentCount; i++) {
     383               0 :     dstList[i] = (*parentList)[aOffset + i];
     384                 :   }
     385                 : 
     386                 : }
     387                 : 
     388                 : void
     389               0 : nsSVGTextContainerFrame::CopyRotateList(nsTArray<float> *parentList,
     390                 :                                         const SVGNumberList *selfList,
     391                 :                                         nsTArray<float> &dstList,
     392                 :                                         PRUint32 aOffset)
     393                 : {
     394               0 :   dstList.Clear();
     395                 : 
     396               0 :   PRUint32 strLength = GetNumberOfChars();
     397               0 :   PRUint32 parentCount = 0;
     398               0 :   if (parentList && parentList->Length() > aOffset) {
     399               0 :     parentCount = NS_MIN(parentList->Length() - aOffset, strLength);
     400                 :   }
     401                 : 
     402               0 :   PRUint32 selfCount = NS_MIN(selfList ? selfList->Length() : 0, strLength);
     403               0 :   PRUint32 count = NS_MAX(parentCount, selfCount);
     404                 : 
     405               0 :   if (count > 0) {
     406               0 :     if (!dstList.SetLength(count))
     407               0 :       return;
     408               0 :     for (PRUint32 i = 0; i < selfCount; i++) {
     409               0 :       dstList[i] = (*selfList)[i];
     410                 :     }
     411               0 :     for (PRUint32 i = selfCount; i < parentCount; i++) {
     412               0 :       dstList[i] = (*parentList)[aOffset + i];
     413                 :     }
     414               0 :   } else if (parentList && !parentList->IsEmpty()) {
     415                 :     // rotate is applied to extra characters too
     416               0 :     dstList.AppendElement((*parentList)[parentList->Length() - 1]);
     417                 :   }
     418                 : }
     419                 : 
     420                 : PRUint32
     421               0 : nsSVGTextContainerFrame::BuildPositionList(PRUint32 aOffset,
     422                 :                                            PRUint32 aDepth)
     423                 : {
     424               0 :   nsSVGTextContainerFrame *parent = do_QueryFrame(mParent);
     425               0 :   nsTArray<float> *parentX = nsnull, *parentY = nsnull;
     426               0 :   nsTArray<float> *parentDx = nsnull, *parentDy = nsnull;
     427               0 :   nsTArray<float> *parentRotate = nsnull;
     428               0 :   if (parent) {
     429               0 :     parentX = &(parent->mX);
     430               0 :     parentY = &(parent->mY);
     431               0 :     parentDx = &(parent->mDx);
     432               0 :     parentDy = &(parent->mDy);
     433               0 :     parentRotate = &(parent->mRotate);
     434                 :   }
     435                 : 
     436               0 :   SVGUserUnitList x, y;
     437               0 :   GetXY(&x, &y);
     438               0 :   CopyPositionList(parentX, &x, mX, aOffset);
     439               0 :   CopyPositionList(parentY, &y, mY, aOffset);
     440                 : 
     441               0 :   SVGUserUnitList dx, dy;
     442               0 :   GetDxDy(&dx, &dy);
     443               0 :   CopyPositionList(parentDx, &dx, mDx, aOffset);
     444               0 :   CopyPositionList(parentDy, &dy, mDy, aOffset);
     445                 : 
     446               0 :   const SVGNumberList *rotate = GetRotate();
     447               0 :   CopyRotateList(parentRotate, rotate, mRotate, aOffset);
     448                 : 
     449               0 :   PRUint32 startIndex = 0;
     450               0 :   nsIFrame* kid = mFrames.FirstChild();
     451               0 :   while (kid) {
     452               0 :     nsSVGTextContainerFrame *text = do_QueryFrame(kid);
     453               0 :     if (text) {
     454               0 :       startIndex += text->BuildPositionList(startIndex, aDepth + 1);
     455               0 :     } else if (kid->GetType() == nsGkAtoms::svgGlyphFrame) {
     456               0 :       nsSVGGlyphFrame *leaf = static_cast<nsSVGGlyphFrame*>(kid);
     457               0 :       leaf->SetStartIndex(startIndex);
     458               0 :       startIndex += leaf->GetNumberOfChars();
     459                 :     }
     460               0 :     kid = kid->GetNextSibling();
     461                 :   }
     462               0 :   return startIndex;
     463                 : }
     464                 : 
     465                 : void
     466               0 : nsSVGTextContainerFrame::GetEffectiveXY(nsTArray<float> &aX,
     467                 :                                         nsTArray<float> &aY)
     468                 : {
     469               0 :   aX.AppendElements(mX);
     470               0 :   aY.AppendElements(mY);
     471               0 : }
     472                 : 
     473                 : void
     474               0 : nsSVGTextContainerFrame::GetEffectiveDxDy(nsTArray<float> &aDx,
     475                 :                                           nsTArray<float> &aDy)
     476                 : {
     477               0 :   aDx.AppendElements(mDx);
     478               0 :   aDy.AppendElements(mDy);
     479               0 : }
     480                 : 
     481                 : void
     482               0 : nsSVGTextContainerFrame::GetEffectiveRotate(nsTArray<float> &aRotate)
     483                 : {
     484               0 :   aRotate.AppendElements(mRotate);
     485               0 : }
     486                 : 
     487                 : void
     488               0 : nsSVGTextContainerFrame::SetWhitespaceCompression()
     489                 : {
     490               0 :   bool compressWhitespace = true;
     491                 : 
     492               0 :   for (const nsIFrame *frame = this; frame != nsnull; frame = frame->GetParent()) {
     493                 :     static const nsIContent::AttrValuesArray strings[] =
     494                 :       {&nsGkAtoms::preserve, &nsGkAtoms::_default, nsnull};
     495                 : 
     496               0 :     PRInt32 index = frame->GetContent()->FindAttrValueIn(
     497                 :                                            kNameSpaceID_XML,
     498                 :                                            nsGkAtoms::space,
     499               0 :                                            strings, eCaseMatters);
     500               0 :     if (index == 0) {
     501               0 :       compressWhitespace = false;
     502               0 :       break;
     503                 :     }
     504               0 :     if (index != nsIContent::ATTR_MISSING ||
     505               0 :         (frame->GetStateBits() & NS_STATE_IS_OUTER_SVG))
     506               0 :       break;
     507                 :   }
     508                 : 
     509               0 :   nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
     510                 : 
     511               0 :   while (node) {
     512               0 :     node->SetWhitespaceCompression(compressWhitespace);
     513               0 :     node = GetNextGlyphFragmentChildNode(node);
     514                 :   }
     515               0 : }

Generated by: LCOV version 1.7