LCOV - app.info - layout/svg/base/src/nsSVGTextFrame.cpp

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-04-21 | 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