LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGTextFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 151 0 0.0 %
Date: 2012-06-02 Functions: 25 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
      18                 :  * Crocodile Clips Ltd..
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2002
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsIDOMSVGTextElement.h"
      40                 : #include "nsSVGTextFrame.h"
      41                 : #include "SVGLengthList.h"
      42                 : #include "nsIDOMSVGLength.h"
      43                 : #include "nsIDOMSVGAnimatedNumber.h"
      44                 : #include "nsISVGGlyphFragmentNode.h"
      45                 : #include "nsSVGGlyphFrame.h"
      46                 : #include "nsSVGOuterSVGFrame.h"
      47                 : #include "nsIDOMSVGRect.h"
      48                 : #include "nsSVGRect.h"
      49                 : #include "nsGkAtoms.h"
      50                 : #include "nsSVGTextPathFrame.h"
      51                 : #include "nsSVGPathElement.h"
      52                 : #include "nsSVGUtils.h"
      53                 : #include "nsSVGGraphicElement.h"
      54                 : 
      55                 : using namespace mozilla;
      56                 : 
      57                 : //----------------------------------------------------------------------
      58                 : // Implementation
      59                 : 
      60                 : nsIFrame*
      61               0 : NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
      62                 : {
      63               0 :   return new (aPresShell) nsSVGTextFrame(aContext);
      64                 : }
      65                 : 
      66               0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGTextFrame)
      67                 : 
      68                 : //----------------------------------------------------------------------
      69                 : // nsIFrame methods
      70                 : #ifdef DEBUG
      71                 : NS_IMETHODIMP
      72               0 : nsSVGTextFrame::Init(nsIContent* aContent,
      73                 :                      nsIFrame* aParent,
      74                 :                      nsIFrame* aPrevInFlow)
      75                 : {
      76               0 :   nsCOMPtr<nsIDOMSVGTextElement> text = do_QueryInterface(aContent);
      77               0 :   NS_ASSERTION(text, "Content is not an SVG text");
      78                 : 
      79               0 :   return nsSVGTextFrameBase::Init(aContent, aParent, aPrevInFlow);
      80                 : }
      81                 : #endif /* DEBUG */
      82                 : 
      83                 : NS_IMETHODIMP
      84               0 : nsSVGTextFrame::AttributeChanged(PRInt32         aNameSpaceID,
      85                 :                                  nsIAtom*        aAttribute,
      86                 :                                  PRInt32         aModType)
      87                 : {
      88               0 :   if (aNameSpaceID != kNameSpaceID_None)
      89               0 :     return NS_OK;
      90                 : 
      91               0 :   if (aAttribute == nsGkAtoms::transform) {
      92                 : 
      93               0 :     NotifySVGChanged(TRANSFORM_CHANGED);
      94                 :    
      95               0 :   } else if (aAttribute == nsGkAtoms::x ||
      96                 :              aAttribute == nsGkAtoms::y ||
      97                 :              aAttribute == nsGkAtoms::dx ||
      98                 :              aAttribute == nsGkAtoms::dy ||
      99                 :              aAttribute == nsGkAtoms::rotate) {
     100               0 :     NotifyGlyphMetricsChange();
     101                 :   }
     102                 : 
     103               0 :  return NS_OK;
     104                 : }
     105                 : 
     106                 : nsIAtom *
     107               0 : nsSVGTextFrame::GetType() const
     108                 : {
     109               0 :   return nsGkAtoms::svgTextFrame;
     110                 : }
     111                 : 
     112                 : //----------------------------------------------------------------------
     113                 : // nsSVGTextContainerFrame
     114                 : PRUint32
     115               0 : nsSVGTextFrame::GetNumberOfChars()
     116                 : {
     117               0 :   UpdateGlyphPositioning(false);
     118                 : 
     119               0 :   return nsSVGTextFrameBase::GetNumberOfChars();
     120                 : }
     121                 : 
     122                 : float
     123               0 : nsSVGTextFrame::GetComputedTextLength()
     124                 : {
     125               0 :   UpdateGlyphPositioning(false);
     126                 : 
     127               0 :   return nsSVGTextFrameBase::GetComputedTextLength();
     128                 : }
     129                 : 
     130                 : float
     131               0 : nsSVGTextFrame::GetSubStringLength(PRUint32 charnum, PRUint32 nchars)
     132                 : {
     133               0 :   UpdateGlyphPositioning(false);
     134                 : 
     135               0 :   return nsSVGTextFrameBase::GetSubStringLength(charnum, nchars);
     136                 : }
     137                 : 
     138                 : PRInt32
     139               0 : nsSVGTextFrame::GetCharNumAtPosition(nsIDOMSVGPoint *point)
     140                 : {
     141               0 :   UpdateGlyphPositioning(false);
     142                 : 
     143               0 :   return nsSVGTextFrameBase::GetCharNumAtPosition(point);
     144                 : }
     145                 : 
     146                 : NS_IMETHODIMP
     147               0 : nsSVGTextFrame::GetStartPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval)
     148                 : {
     149               0 :   UpdateGlyphPositioning(false);
     150                 : 
     151               0 :   return nsSVGTextFrameBase::GetStartPositionOfChar(charnum,  _retval);
     152                 : }
     153                 : 
     154                 : NS_IMETHODIMP
     155               0 : nsSVGTextFrame::GetEndPositionOfChar(PRUint32 charnum, nsIDOMSVGPoint **_retval)
     156                 : {
     157               0 :   UpdateGlyphPositioning(false);
     158                 : 
     159               0 :   return nsSVGTextFrameBase::GetEndPositionOfChar(charnum,  _retval);
     160                 : }
     161                 : 
     162                 : NS_IMETHODIMP
     163               0 : nsSVGTextFrame::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
     164                 : {
     165               0 :   UpdateGlyphPositioning(false);
     166                 : 
     167               0 :   return nsSVGTextFrameBase::GetExtentOfChar(charnum,  _retval);
     168                 : }
     169                 : 
     170                 : NS_IMETHODIMP
     171               0 : nsSVGTextFrame::GetRotationOfChar(PRUint32 charnum, float *_retval)
     172                 : {
     173               0 :   UpdateGlyphPositioning(false);
     174                 : 
     175               0 :   return nsSVGTextFrameBase::GetRotationOfChar(charnum,  _retval);
     176                 : }
     177                 : 
     178                 : //----------------------------------------------------------------------
     179                 : // nsISVGChildFrame methods
     180                 : 
     181                 : void
     182               0 : nsSVGTextFrame::NotifySVGChanged(PRUint32 aFlags)
     183                 : {
     184               0 :   NS_ABORT_IF_FALSE(!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS) ||
     185                 :                     (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
     186                 :                     "Must be NS_STATE_SVG_NONDISPLAY_CHILD!");
     187                 : 
     188               0 :   NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
     189                 :                     "Invalidation logic may need adjusting");
     190                 : 
     191               0 :   bool updateGlyphMetrics = false;
     192                 :   
     193               0 :   if (aFlags & COORD_CONTEXT_CHANGED) {
     194               0 :     updateGlyphMetrics = true;
     195                 :   }
     196                 : 
     197               0 :   if (aFlags & TRANSFORM_CHANGED) {
     198               0 :     if (mCanvasTM && mCanvasTM->IsSingular()) {
     199                 :       // We won't have calculated the glyph positions correctly
     200               0 :       updateGlyphMetrics = true;
     201                 :     }
     202                 :     // make sure our cached transform matrix gets (lazily) updated
     203               0 :     mCanvasTM = nsnull;
     204                 :   }
     205                 : 
     206               0 :   nsSVGTextFrameBase::NotifySVGChanged(aFlags);
     207                 : 
     208               0 :   if (updateGlyphMetrics) {
     209                 :     // If we are positioned using percentage values we need to update our
     210                 :     // position whenever our viewport's dimensions change.
     211                 : 
     212                 :     // XXX We could check here whether the text frame or any of its children
     213                 :     // have any percentage co-ordinates and only update if they don't. This
     214                 :     // may not be worth it as we might need to check each glyph
     215               0 :     NotifyGlyphMetricsChange();
     216                 :   }
     217               0 : }
     218                 : 
     219                 : void
     220               0 : nsSVGTextFrame::NotifyRedrawUnsuspended()
     221                 : {
     222               0 :   RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED);
     223                 : 
     224               0 :   UpdateGlyphPositioning(false);
     225               0 :   nsSVGTextFrameBase::NotifyRedrawUnsuspended();
     226               0 : }
     227                 : 
     228                 : NS_IMETHODIMP
     229               0 : nsSVGTextFrame::PaintSVG(nsRenderingContext* aContext,
     230                 :                          const nsIntRect *aDirtyRect)
     231                 : {
     232               0 :   UpdateGlyphPositioning(true);
     233                 :   
     234               0 :   return nsSVGTextFrameBase::PaintSVG(aContext, aDirtyRect);
     235                 : }
     236                 : 
     237                 : NS_IMETHODIMP_(nsIFrame*)
     238               0 : nsSVGTextFrame::GetFrameForPoint(const nsPoint &aPoint)
     239                 : {
     240               0 :   UpdateGlyphPositioning(true);
     241                 :   
     242               0 :   return nsSVGTextFrameBase::GetFrameForPoint(aPoint);
     243                 : }
     244                 : 
     245                 : NS_IMETHODIMP
     246               0 : nsSVGTextFrame::UpdateCoveredRegion()
     247                 : {
     248               0 :   UpdateGlyphPositioning(true);
     249                 :   
     250               0 :   return nsSVGTextFrameBase::UpdateCoveredRegion();
     251                 : }
     252                 : 
     253                 : NS_IMETHODIMP
     254               0 : nsSVGTextFrame::InitialUpdate()
     255                 : {
     256               0 :   nsresult rv = nsSVGTextFrameBase::InitialUpdate();
     257                 :   
     258               0 :   UpdateGlyphPositioning(false);
     259                 : 
     260               0 :   return rv;
     261                 : }  
     262                 : 
     263                 : gfxRect
     264               0 : nsSVGTextFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
     265                 :                                     PRUint32 aFlags)
     266                 : {
     267               0 :   UpdateGlyphPositioning(true);
     268                 : 
     269               0 :   return nsSVGTextFrameBase::GetBBoxContribution(aToBBoxUserspace, aFlags);
     270                 : }
     271                 : 
     272                 : //----------------------------------------------------------------------
     273                 : // nsSVGContainerFrame methods:
     274                 : 
     275                 : gfxMatrix
     276               0 : nsSVGTextFrame::GetCanvasTM()
     277                 : {
     278               0 :   if (!mCanvasTM) {
     279               0 :     NS_ASSERTION(mParent, "null parent");
     280                 : 
     281               0 :     nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(mParent);
     282               0 :     nsSVGGraphicElement *content = static_cast<nsSVGGraphicElement*>(mContent);
     283                 : 
     284               0 :     gfxMatrix tm = content->PrependLocalTransformsTo(parent->GetCanvasTM());
     285                 : 
     286               0 :     mCanvasTM = new gfxMatrix(tm);
     287                 :   }
     288                 : 
     289               0 :   return *mCanvasTM;
     290                 : }
     291                 : 
     292                 : //----------------------------------------------------------------------
     293                 : //
     294                 : 
     295                 : void
     296               0 : nsSVGTextFrame::NotifyGlyphMetricsChange()
     297                 : {
     298               0 :   mPositioningDirty = true;
     299               0 :   UpdateGlyphPositioning(false);
     300               0 : }
     301                 : 
     302                 : void
     303               0 : nsSVGTextFrame::SetWhitespaceHandling(nsSVGGlyphFrame *aFrame)
     304                 : {
     305               0 :   SetWhitespaceCompression();
     306                 : 
     307               0 :   nsSVGGlyphFrame* firstFrame = aFrame;
     308               0 :   bool trimLeadingWhitespace = true;
     309               0 :   nsSVGGlyphFrame* lastNonWhitespaceFrame = aFrame;
     310                 : 
     311                 :   // If the previous frame ended with whitespace
     312                 :   // then display of leading whitespace should be suppressed
     313                 :   // when we are compressing whitespace.
     314               0 :   while (aFrame) {
     315               0 :     if (!aFrame->IsAllWhitespace()) {
     316               0 :       lastNonWhitespaceFrame = aFrame;
     317                 :     }
     318                 : 
     319               0 :     aFrame->SetTrimLeadingWhitespace(trimLeadingWhitespace);
     320               0 :     trimLeadingWhitespace = aFrame->EndsWithWhitespace();
     321                 : 
     322               0 :     aFrame = aFrame->GetNextGlyphFrame();
     323                 :   }
     324                 : 
     325                 :   // When there is only whitespace left we need to trim off
     326                 :   // the end of the last frame that isn't entirely whitespace.
     327                 :   // Making sure that we reset earlier frames as they may once
     328                 :   // have been the last non-whitespace frame.
     329               0 :   aFrame = firstFrame;
     330               0 :   while (aFrame != lastNonWhitespaceFrame) {
     331               0 :     aFrame->SetTrimTrailingWhitespace(false);
     332               0 :     aFrame = aFrame->GetNextGlyphFrame();
     333                 :   }
     334                 : 
     335                 :   // We're at the last non-whitespace frame so trim off the end
     336                 :   // and make sure we set one of the trim bits so that any
     337                 :   // further whitespace is compressed to nothing
     338               0 :   while (aFrame) {
     339               0 :     aFrame->SetTrimTrailingWhitespace(true);
     340               0 :     aFrame = aFrame->GetNextGlyphFrame();
     341                 :   }
     342               0 : }
     343                 : 
     344                 : void
     345               0 : nsSVGTextFrame::UpdateGlyphPositioning(bool aForceGlobalTransform)
     346                 : {
     347               0 :   if ((GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED) || !mPositioningDirty)
     348               0 :     return;
     349                 : 
     350               0 :   mPositioningDirty = false;
     351                 : 
     352               0 :   nsISVGGlyphFragmentNode* node = GetFirstGlyphFragmentChildNode();
     353               0 :   if (!node)
     354               0 :     return;
     355                 : 
     356                 :   nsSVGGlyphFrame *frame, *firstFrame;
     357                 : 
     358               0 :   firstFrame = node->GetFirstGlyphFrame();
     359               0 :   if (!firstFrame) {
     360               0 :     return;
     361                 :   }
     362                 : 
     363               0 :   SetWhitespaceHandling(firstFrame);
     364                 : 
     365               0 :   BuildPositionList(0, 0);
     366                 : 
     367               0 :   gfxPoint ctp(0.0, 0.0);
     368                 : 
     369                 :   // loop over chunks
     370               0 :   while (firstFrame) {
     371               0 :     nsSVGTextPathFrame *textPath = firstFrame->FindTextPathParent();
     372                 : 
     373               0 :     nsTArray<float> effectiveXList, effectiveYList;
     374               0 :     firstFrame->GetEffectiveXY(firstFrame->GetNumberOfChars(),
     375               0 :                                effectiveXList, effectiveYList);
     376               0 :     if (!effectiveXList.IsEmpty()) ctp.x = effectiveXList[0];
     377               0 :     if (!textPath && !effectiveYList.IsEmpty()) ctp.y = effectiveYList[0];
     378                 : 
     379                 :     // check for startOffset on textPath
     380               0 :     if (textPath) {
     381               0 :       if (!textPath->GetPathFrame()) {
     382                 :         // invalid text path, give up
     383                 :         return;
     384                 :       }
     385               0 :       ctp.x = textPath->GetStartOffset();
     386                 :     }
     387                 : 
     388                 :     // determine x offset based on text_anchor:
     389                 :   
     390               0 :     PRUint8 anchor = firstFrame->GetTextAnchor();
     391                 : 
     392                 :     /**
     393                 :      * XXXsmontagu: The SVG spec is very vague as to how 'text-anchor'
     394                 :      *  interacts with bidirectional text. It says:
     395                 :      *
     396                 :      *   "For scripts that are inherently right to left such as Hebrew and
     397                 :      *   Arabic [text-anchor: start] is equivalent to right alignment."
     398                 :      * and
     399                 :      *   "For scripts that are inherently right to left such as Hebrew and
     400                 :      *   Arabic, [text-anchor: end] is equivalent to left alignment.
     401                 :      *
     402                 :      * It's not clear how this should be implemented in terms of defined
     403                 :      * properties, i.e. how one should determine that a particular element
     404                 :      * contains a script that is inherently right to left.
     405                 :      *
     406                 :      * The code below follows http://www.w3.org/TR/SVGTiny12/text.html#TextAnchorProperty
     407                 :      * and swaps the values of text-anchor: end and  text-anchor: start
     408                 :      * whenever the 'direction' property is rtl.
     409                 :      *
     410                 :      * This is probably the "right" thing to do, but other browsers don't do it,
     411                 :      * so I am leaving it inside #if 0 for now for interoperability.
     412                 :      *
     413                 :      * See also XXXsmontagu comments in nsSVGGlyphFrame::EnsureTextRun
     414                 :      */
     415                 : #if 0
     416                 :     if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
     417                 :       if (anchor == NS_STYLE_TEXT_ANCHOR_END) {
     418                 :         anchor = NS_STYLE_TEXT_ANCHOR_START;
     419                 :       } else if (anchor == NS_STYLE_TEXT_ANCHOR_START) {
     420                 :         anchor = NS_STYLE_TEXT_ANCHOR_END;
     421                 :       }
     422                 :     }
     423                 : #endif
     424                 : 
     425               0 :     float chunkLength = 0.0f;
     426               0 :     if (anchor != NS_STYLE_TEXT_ANCHOR_START) {
     427                 :       // need to get the total chunk length
     428                 :     
     429               0 :       frame = firstFrame;
     430               0 :       while (frame) {
     431               0 :         chunkLength += frame->GetAdvance(aForceGlobalTransform);
     432               0 :         frame = frame->GetNextGlyphFrame();
     433               0 :         if (frame && frame->IsAbsolutelyPositioned())
     434               0 :           break;
     435                 :       }
     436                 :     }
     437                 : 
     438               0 :     if (anchor == NS_STYLE_TEXT_ANCHOR_MIDDLE)
     439               0 :       ctp.x -= chunkLength/2.0f;
     440               0 :     else if (anchor == NS_STYLE_TEXT_ANCHOR_END)
     441               0 :       ctp.x -= chunkLength;
     442                 :   
     443                 :     // set position of each frame in this chunk:
     444                 :   
     445               0 :     frame = firstFrame;
     446               0 :     while (frame) {
     447                 : 
     448               0 :       frame->SetGlyphPosition(&ctp, aForceGlobalTransform);
     449               0 :       frame = frame->GetNextGlyphFrame();
     450               0 :       if (frame && frame->IsAbsolutelyPositioned())
     451               0 :         break;
     452                 :     }
     453               0 :     firstFrame = frame;
     454                 :   }
     455               0 :   nsSVGUtils::UpdateGraphic(this);
     456                 : }

Generated by: LCOV version 1.7