LCOV - code coverage report
Current view: directory - gfx/src - nsRenderingContext.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 251 0 0.0 %
Date: 2012-06-02 Functions: 37 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       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 mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * mozilla.org.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2004
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Stuart Parmenter <pavlov@pavlov.net>
      24                 :  *   Vladimir Vukicevic <vladimir@pobox.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "nsRenderingContext.h"
      41                 : #include "nsBoundingMetrics.h"
      42                 : #include "nsRegion.h"
      43                 : 
      44                 : // XXXTodo: rename FORM_TWIPS to FROM_APPUNITS
      45                 : #define FROM_TWIPS(_x)  ((gfxFloat)((_x)/(mP2A)))
      46                 : #define FROM_TWIPS_INT(_x)  (NSToIntRound((gfxFloat)((_x)/(mP2A))))
      47                 : #define TO_TWIPS(_x)    ((nscoord)((_x)*(mP2A)))
      48                 : #define GFX_RECT_FROM_TWIPS_RECT(_r)   (gfxRect(FROM_TWIPS((_r).x), FROM_TWIPS((_r).y), FROM_TWIPS((_r).width), FROM_TWIPS((_r).height)))
      49                 : 
      50                 : // Hard limit substring lengths to 8000 characters ... this lets us statically
      51                 : // size the cluster buffer array in FindSafeLength
      52                 : #define MAX_GFX_TEXT_BUF_SIZE 8000
      53                 : 
      54               0 : static PRInt32 FindSafeLength(const PRUnichar *aString, PRUint32 aLength,
      55                 :                               PRUint32 aMaxChunkLength)
      56                 : {
      57               0 :     if (aLength <= aMaxChunkLength)
      58               0 :         return aLength;
      59                 : 
      60               0 :     PRInt32 len = aMaxChunkLength;
      61                 : 
      62                 :     // Ensure that we don't break inside a surrogate pair
      63               0 :     while (len > 0 && NS_IS_LOW_SURROGATE(aString[len])) {
      64               0 :         len--;
      65                 :     }
      66               0 :     if (len == 0) {
      67                 :         // We don't want our caller to go into an infinite loop, so don't
      68                 :         // return zero. It's hard to imagine how we could actually get here
      69                 :         // unless there are languages that allow clusters of arbitrary size.
      70                 :         // If there are and someone feeds us a 500+ character cluster, too
      71                 :         // bad.
      72               0 :         return aMaxChunkLength;
      73                 :     }
      74               0 :     return len;
      75                 : }
      76                 : 
      77               0 : static PRInt32 FindSafeLength(const char *aString, PRUint32 aLength,
      78                 :                               PRUint32 aMaxChunkLength)
      79                 : {
      80                 :     // Since it's ASCII, we don't need to worry about clusters or RTL
      81               0 :     return NS_MIN(aLength, aMaxChunkLength);
      82                 : }
      83                 : 
      84                 : //////////////////////////////////////////////////////////////////////
      85                 : //// nsRenderingContext
      86                 : 
      87                 : void
      88               0 : nsRenderingContext::Init(nsDeviceContext* aContext,
      89                 :                          gfxASurface *aThebesSurface)
      90                 : {
      91               0 :     Init(aContext, new gfxContext(aThebesSurface));
      92               0 : }
      93                 : 
      94                 : void
      95               0 : nsRenderingContext::Init(nsDeviceContext* aContext,
      96                 :                          gfxContext *aThebesContext)
      97                 : {
      98               0 :     mDeviceContext = aContext;
      99               0 :     mThebes = aThebesContext;
     100                 : 
     101               0 :     mThebes->SetLineWidth(1.0);
     102               0 :     mP2A = mDeviceContext->AppUnitsPerDevPixel();
     103               0 : }
     104                 : 
     105                 : //
     106                 : // graphics state
     107                 : //
     108                 : 
     109                 : void
     110               0 : nsRenderingContext::PushState()
     111                 : {
     112               0 :     mThebes->Save();
     113               0 : }
     114                 : 
     115                 : void
     116               0 : nsRenderingContext::PopState()
     117                 : {
     118               0 :     mThebes->Restore();
     119               0 : }
     120                 : 
     121                 : void
     122               0 : nsRenderingContext::IntersectClip(const nsRect& aRect)
     123                 : {
     124               0 :     mThebes->NewPath();
     125               0 :     gfxRect clipRect(GFX_RECT_FROM_TWIPS_RECT(aRect));
     126               0 :     if (mThebes->UserToDevicePixelSnapped(clipRect, true)) {
     127               0 :         gfxMatrix mat(mThebes->CurrentMatrix());
     128               0 :         mat.Invert();
     129               0 :         clipRect = mat.Transform(clipRect);
     130               0 :         mThebes->Rectangle(clipRect);
     131                 :     } else {
     132               0 :         mThebes->Rectangle(clipRect);
     133                 :     }
     134                 : 
     135               0 :     mThebes->Clip();
     136               0 : }
     137                 : 
     138                 : void
     139               0 : nsRenderingContext::SetClip(const nsIntRegion& aRegion)
     140                 : {
     141                 :     // Region is in device coords, no transformation.  This should
     142                 :     // only be called when there is no transform in place, when we we
     143                 :     // just start painting a widget. The region is set by the platform
     144                 :     // paint routine.  Therefore, there is no option to intersect with
     145                 :     // an existing clip.
     146                 : 
     147               0 :     gfxMatrix mat = mThebes->CurrentMatrix();
     148               0 :     mThebes->IdentityMatrix();
     149                 : 
     150               0 :     mThebes->ResetClip();
     151                 : 
     152               0 :     mThebes->NewPath();
     153               0 :     nsIntRegionRectIterator iter(aRegion);
     154                 :     const nsIntRect* rect;
     155               0 :     while ((rect = iter.Next())) {
     156                 :         mThebes->Rectangle(gfxRect(rect->x, rect->y, rect->width, rect->height),
     157               0 :                            true);
     158                 :     }
     159               0 :     mThebes->Clip();
     160               0 :     mThebes->SetMatrix(mat);
     161               0 : }
     162                 : 
     163                 : void
     164               0 : nsRenderingContext::SetLineStyle(nsLineStyle aLineStyle)
     165                 : {
     166               0 :     switch (aLineStyle) {
     167                 :         case nsLineStyle_kSolid:
     168               0 :             mThebes->SetDash(gfxContext::gfxLineSolid);
     169               0 :             break;
     170                 :         case nsLineStyle_kDashed:
     171               0 :             mThebes->SetDash(gfxContext::gfxLineDashed);
     172               0 :             break;
     173                 :         case nsLineStyle_kDotted:
     174               0 :             mThebes->SetDash(gfxContext::gfxLineDotted);
     175               0 :             break;
     176                 :         case nsLineStyle_kNone:
     177                 :         default:
     178                 :             // nothing uses kNone
     179               0 :             NS_ERROR("SetLineStyle: Invalid line style");
     180               0 :             break;
     181                 :     }
     182               0 : }
     183                 : 
     184                 : 
     185                 : void
     186               0 : nsRenderingContext::SetColor(nscolor aColor)
     187                 : {
     188                 :     /* This sets the color assuming the sRGB color space, since that's
     189                 :      * what all CSS colors are defined to be in by the spec.
     190                 :      */
     191               0 :     mThebes->SetColor(gfxRGBA(aColor));
     192               0 : }
     193                 : 
     194                 : void
     195               0 : nsRenderingContext::Translate(const nsPoint& aPt)
     196                 : {
     197               0 :     mThebes->Translate(gfxPoint(FROM_TWIPS(aPt.x), FROM_TWIPS(aPt.y)));
     198               0 : }
     199                 : 
     200                 : void
     201               0 : nsRenderingContext::Scale(float aSx, float aSy)
     202                 : {
     203               0 :     mThebes->Scale(aSx, aSy);
     204               0 : }
     205                 : 
     206                 : //
     207                 : // shapes
     208                 : //
     209                 : 
     210                 : void
     211               0 : nsRenderingContext::DrawLine(const nsPoint& aStartPt, const nsPoint& aEndPt)
     212                 : {
     213               0 :     DrawLine(aStartPt.x, aStartPt.y, aEndPt.x, aEndPt.y);
     214               0 : }
     215                 : 
     216                 : void
     217               0 : nsRenderingContext::DrawLine(nscoord aX0, nscoord aY0,
     218                 :                              nscoord aX1, nscoord aY1)
     219                 : {
     220               0 :     gfxPoint p0 = gfxPoint(FROM_TWIPS(aX0), FROM_TWIPS(aY0));
     221               0 :     gfxPoint p1 = gfxPoint(FROM_TWIPS(aX1), FROM_TWIPS(aY1));
     222                 : 
     223                 :     // we can't draw thick lines with gfx, so we always assume we want
     224                 :     // pixel-aligned lines if the rendering context is at 1.0 scale
     225               0 :     gfxMatrix savedMatrix = mThebes->CurrentMatrix();
     226               0 :     if (!savedMatrix.HasNonTranslation()) {
     227               0 :         p0 = mThebes->UserToDevice(p0);
     228               0 :         p1 = mThebes->UserToDevice(p1);
     229                 : 
     230               0 :         p0.Round();
     231               0 :         p1.Round();
     232                 : 
     233               0 :         mThebes->IdentityMatrix();
     234                 : 
     235               0 :         mThebes->NewPath();
     236                 : 
     237                 :         // snap straight lines
     238               0 :         if (p0.x == p1.x) {
     239               0 :             mThebes->Line(p0 + gfxPoint(0.5, 0),
     240               0 :                           p1 + gfxPoint(0.5, 0));
     241               0 :         } else if (p0.y == p1.y) {
     242               0 :             mThebes->Line(p0 + gfxPoint(0, 0.5),
     243               0 :                           p1 + gfxPoint(0, 0.5));
     244                 :         } else {
     245               0 :             mThebes->Line(p0, p1);
     246                 :         }
     247                 : 
     248               0 :         mThebes->Stroke();
     249                 : 
     250               0 :         mThebes->SetMatrix(savedMatrix);
     251                 :     } else {
     252               0 :         mThebes->NewPath();
     253               0 :         mThebes->Line(p0, p1);
     254               0 :         mThebes->Stroke();
     255                 :     }
     256               0 : }
     257                 : 
     258                 : void
     259               0 : nsRenderingContext::DrawRect(const nsRect& aRect)
     260                 : {
     261               0 :     mThebes->NewPath();
     262               0 :     mThebes->Rectangle(GFX_RECT_FROM_TWIPS_RECT(aRect), true);
     263               0 :     mThebes->Stroke();
     264               0 : }
     265                 : 
     266                 : void
     267               0 : nsRenderingContext::DrawRect(nscoord aX, nscoord aY,
     268                 :                              nscoord aWidth, nscoord aHeight)
     269                 : {
     270               0 :     DrawRect(nsRect(aX, aY, aWidth, aHeight));
     271               0 : }
     272                 : 
     273                 : 
     274                 : /* Clamp r to (0,0) (2^23,2^23)
     275                 :  * these are to be device coordinates.
     276                 :  *
     277                 :  * Returns false if the rectangle is completely out of bounds,
     278                 :  * true otherwise.
     279                 :  *
     280                 :  * This function assumes that it will be called with a rectangle being
     281                 :  * drawn into a surface with an identity transformation matrix; that
     282                 :  * is, anything above or to the left of (0,0) will be offscreen.
     283                 :  *
     284                 :  * First it checks if the rectangle is entirely beyond
     285                 :  * CAIRO_COORD_MAX; if so, it can't ever appear on the screen --
     286                 :  * false is returned.
     287                 :  *
     288                 :  * Then it shifts any rectangles with x/y < 0 so that x and y are = 0,
     289                 :  * and adjusts the width and height appropriately.  For example, a
     290                 :  * rectangle from (0,-5) with dimensions (5,10) will become a
     291                 :  * rectangle from (0,0) with dimensions (5,5).
     292                 :  *
     293                 :  * If after negative x/y adjustment to 0, either the width or height
     294                 :  * is negative, then the rectangle is completely offscreen, and
     295                 :  * nothing is drawn -- false is returned.
     296                 :  *
     297                 :  * Finally, if x+width or y+height are greater than CAIRO_COORD_MAX,
     298                 :  * the width and height are clamped such x+width or y+height are equal
     299                 :  * to CAIRO_COORD_MAX, and true is returned.
     300                 :  */
     301                 : #define CAIRO_COORD_MAX (double(0x7fffff))
     302                 : 
     303                 : static bool
     304               0 : ConditionRect(gfxRect& r) {
     305                 :     // if either x or y is way out of bounds;
     306                 :     // note that we don't handle negative w/h here
     307               0 :     if (r.X() > CAIRO_COORD_MAX || r.Y() > CAIRO_COORD_MAX)
     308               0 :         return false;
     309                 : 
     310               0 :     if (r.X() < 0.0) {
     311               0 :         r.width += r.X();
     312               0 :         if (r.width < 0.0)
     313               0 :             return false;
     314               0 :         r.x = 0.0;
     315                 :     }
     316                 : 
     317               0 :     if (r.XMost() > CAIRO_COORD_MAX) {
     318               0 :         r.width = CAIRO_COORD_MAX - r.X();
     319                 :     }
     320                 : 
     321               0 :     if (r.Y() < 0.0) {
     322               0 :         r.height += r.Y();
     323               0 :         if (r.Height() < 0.0)
     324               0 :             return false;
     325                 : 
     326               0 :         r.y = 0.0;
     327                 :     }
     328                 : 
     329               0 :     if (r.YMost() > CAIRO_COORD_MAX) {
     330               0 :         r.height = CAIRO_COORD_MAX - r.Y();
     331                 :     }
     332               0 :     return true;
     333                 : }
     334                 : 
     335                 : void
     336               0 : nsRenderingContext::FillRect(const nsRect& aRect)
     337                 : {
     338               0 :     gfxRect r(GFX_RECT_FROM_TWIPS_RECT(aRect));
     339                 : 
     340                 :     /* Clamp coordinates to work around a design bug in cairo */
     341               0 :     nscoord bigval = (nscoord)(CAIRO_COORD_MAX*mP2A);
     342               0 :     if (aRect.width > bigval ||
     343                 :         aRect.height > bigval ||
     344                 :         aRect.x < -bigval ||
     345                 :         aRect.x > bigval ||
     346                 :         aRect.y < -bigval ||
     347                 :         aRect.y > bigval)
     348                 :     {
     349               0 :         gfxMatrix mat = mThebes->CurrentMatrix();
     350                 : 
     351               0 :         r = mat.Transform(r);
     352                 : 
     353               0 :         if (!ConditionRect(r))
     354               0 :             return;
     355                 : 
     356               0 :         mThebes->IdentityMatrix();
     357               0 :         mThebes->NewPath();
     358                 : 
     359               0 :         mThebes->Rectangle(r, true);
     360               0 :         mThebes->Fill();
     361               0 :         mThebes->SetMatrix(mat);
     362                 :     }
     363                 : 
     364               0 :     mThebes->NewPath();
     365               0 :     mThebes->Rectangle(r, true);
     366               0 :     mThebes->Fill();
     367                 : }
     368                 : 
     369                 : void
     370               0 : nsRenderingContext::FillRect(nscoord aX, nscoord aY,
     371                 :                              nscoord aWidth, nscoord aHeight)
     372                 : {
     373               0 :     FillRect(nsRect(aX, aY, aWidth, aHeight));
     374               0 : }
     375                 : 
     376                 : void
     377               0 : nsRenderingContext::InvertRect(const nsRect& aRect)
     378                 : {
     379               0 :     gfxContext::GraphicsOperator lastOp = mThebes->CurrentOperator();
     380                 : 
     381               0 :     mThebes->SetOperator(gfxContext::OPERATOR_XOR);
     382               0 :     FillRect(aRect);
     383               0 :     mThebes->SetOperator(lastOp);
     384               0 : }
     385                 : 
     386                 : void
     387               0 : nsRenderingContext::DrawEllipse(nscoord aX, nscoord aY,
     388                 :                                 nscoord aWidth, nscoord aHeight)
     389                 : {
     390               0 :     mThebes->NewPath();
     391                 :     mThebes->Ellipse(gfxPoint(FROM_TWIPS(aX) + FROM_TWIPS(aWidth)/2.0,
     392                 :                               FROM_TWIPS(aY) + FROM_TWIPS(aHeight)/2.0),
     393                 :                      gfxSize(FROM_TWIPS(aWidth),
     394               0 :                              FROM_TWIPS(aHeight)));
     395               0 :     mThebes->Stroke();
     396               0 : }
     397                 : 
     398                 : void
     399               0 : nsRenderingContext::FillEllipse(const nsRect& aRect)
     400                 : {
     401               0 :     FillEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
     402               0 : }
     403                 : 
     404                 : void
     405               0 : nsRenderingContext::FillEllipse(nscoord aX, nscoord aY,
     406                 :                                 nscoord aWidth, nscoord aHeight)
     407                 : {
     408               0 :     mThebes->NewPath();
     409                 :     mThebes->Ellipse(gfxPoint(FROM_TWIPS(aX) + FROM_TWIPS(aWidth)/2.0,
     410                 :                               FROM_TWIPS(aY) + FROM_TWIPS(aHeight)/2.0),
     411                 :                      gfxSize(FROM_TWIPS(aWidth),
     412               0 :                              FROM_TWIPS(aHeight)));
     413               0 :     mThebes->Fill();
     414               0 : }
     415                 : 
     416                 : void
     417               0 : nsRenderingContext::FillPolygon(const nsPoint twPoints[], PRInt32 aNumPoints)
     418                 : {
     419               0 :     if (aNumPoints == 0)
     420               0 :         return;
     421                 : 
     422               0 :     nsAutoArrayPtr<gfxPoint> pxPoints(new gfxPoint[aNumPoints]);
     423                 : 
     424               0 :     for (int i = 0; i < aNumPoints; i++) {
     425               0 :         pxPoints[i].x = FROM_TWIPS(twPoints[i].x);
     426               0 :         pxPoints[i].y = FROM_TWIPS(twPoints[i].y);
     427                 :     }
     428                 : 
     429               0 :     mThebes->NewPath();
     430               0 :     mThebes->Polygon(pxPoints, aNumPoints);
     431               0 :     mThebes->Fill();
     432                 : }
     433                 : 
     434                 : //
     435                 : // text
     436                 : //
     437                 : 
     438                 : void
     439               0 : nsRenderingContext::SetTextRunRTL(bool aIsRTL)
     440                 : {
     441               0 :     mFontMetrics->SetTextRunRTL(aIsRTL);
     442               0 : }
     443                 : 
     444                 : void
     445               0 : nsRenderingContext::SetFont(nsFontMetrics *aFontMetrics)
     446                 : {
     447               0 :     mFontMetrics = aFontMetrics;
     448               0 : }
     449                 : 
     450                 : PRInt32
     451               0 : nsRenderingContext::GetMaxChunkLength()
     452                 : {
     453               0 :     if (!mFontMetrics)
     454               0 :         return 1;
     455               0 :     return NS_MIN(mFontMetrics->GetMaxStringLength(), MAX_GFX_TEXT_BUF_SIZE);
     456                 : }
     457                 : 
     458                 : nscoord
     459               0 : nsRenderingContext::GetWidth(char aC)
     460                 : {
     461               0 :     if (aC == ' ' && mFontMetrics) {
     462               0 :         return mFontMetrics->SpaceWidth();
     463                 :     }
     464                 : 
     465               0 :     return GetWidth(&aC, 1);
     466                 : }
     467                 : 
     468                 : nscoord
     469               0 : nsRenderingContext::GetWidth(PRUnichar aC)
     470                 : {
     471               0 :     return GetWidth(&aC, 1);
     472                 : }
     473                 : 
     474                 : nscoord
     475               0 : nsRenderingContext::GetWidth(const nsString& aString)
     476                 : {
     477               0 :     return GetWidth(aString.get(), aString.Length());
     478                 : }
     479                 : 
     480                 : nscoord
     481               0 : nsRenderingContext::GetWidth(const char* aString)
     482                 : {
     483               0 :     return GetWidth(aString, strlen(aString));
     484                 : }
     485                 : 
     486                 : nscoord
     487               0 : nsRenderingContext::GetWidth(const char* aString, PRUint32 aLength)
     488                 : {
     489               0 :     PRUint32 maxChunkLength = GetMaxChunkLength();
     490               0 :     nscoord width = 0;
     491               0 :     while (aLength > 0) {
     492               0 :         PRInt32 len = FindSafeLength(aString, aLength, maxChunkLength);
     493               0 :         width += mFontMetrics->GetWidth(aString, len, this);
     494               0 :         aLength -= len;
     495               0 :         aString += len;
     496                 :     }
     497               0 :     return width;
     498                 : }
     499                 : 
     500                 : nscoord
     501               0 : nsRenderingContext::GetWidth(const PRUnichar *aString, PRUint32 aLength)
     502                 : {
     503               0 :     PRUint32 maxChunkLength = GetMaxChunkLength();
     504               0 :     nscoord width = 0;
     505               0 :     while (aLength > 0) {
     506               0 :         PRInt32 len = FindSafeLength(aString, aLength, maxChunkLength);
     507               0 :         width += mFontMetrics->GetWidth(aString, len, this);
     508               0 :         aLength -= len;
     509               0 :         aString += len;
     510                 :     }
     511               0 :     return width;
     512                 : }
     513                 : 
     514                 : nsBoundingMetrics
     515               0 : nsRenderingContext::GetBoundingMetrics(const PRUnichar* aString,
     516                 :                                        PRUint32 aLength)
     517                 : {
     518               0 :     PRUint32 maxChunkLength = GetMaxChunkLength();
     519               0 :     PRInt32 len = FindSafeLength(aString, aLength, maxChunkLength);
     520                 :     // Assign directly in the first iteration. This ensures that
     521                 :     // negative ascent/descent can be returned and the left bearing
     522                 :     // is properly initialized.
     523                 :     nsBoundingMetrics totalMetrics
     524               0 :         = mFontMetrics->GetBoundingMetrics(aString, len, this);
     525               0 :     aLength -= len;
     526               0 :     aString += len;
     527                 : 
     528               0 :     while (aLength > 0) {
     529               0 :         len = FindSafeLength(aString, aLength, maxChunkLength);
     530                 :         nsBoundingMetrics metrics
     531               0 :             = mFontMetrics->GetBoundingMetrics(aString, len, this);
     532               0 :         totalMetrics += metrics;
     533               0 :         aLength -= len;
     534               0 :         aString += len;
     535                 :     }
     536                 :     return totalMetrics;
     537                 : }
     538                 : 
     539                 : void
     540               0 : nsRenderingContext::DrawString(const char *aString, PRUint32 aLength,
     541                 :                                nscoord aX, nscoord aY)
     542                 : {
     543               0 :     PRUint32 maxChunkLength = GetMaxChunkLength();
     544               0 :     while (aLength > 0) {
     545               0 :         PRInt32 len = FindSafeLength(aString, aLength, maxChunkLength);
     546               0 :         mFontMetrics->DrawString(aString, len, aX, aY, this);
     547               0 :         aLength -= len;
     548                 : 
     549               0 :         if (aLength > 0) {
     550               0 :             nscoord width = mFontMetrics->GetWidth(aString, len, this);
     551               0 :             aX += width;
     552               0 :             aString += len;
     553                 :         }
     554                 :     }
     555               0 : }
     556                 : 
     557                 : void
     558               0 : nsRenderingContext::DrawString(const nsString& aString, nscoord aX, nscoord aY)
     559                 : {
     560               0 :     DrawString(aString.get(), aString.Length(), aX, aY);
     561               0 : }
     562                 : 
     563                 : void
     564               0 : nsRenderingContext::DrawString(const PRUnichar *aString, PRUint32 aLength,
     565                 :                                nscoord aX, nscoord aY)
     566                 : {
     567               0 :     PRUint32 maxChunkLength = GetMaxChunkLength();
     568               0 :     if (aLength <= maxChunkLength) {
     569               0 :         mFontMetrics->DrawString(aString, aLength, aX, aY, this, this);
     570               0 :         return;
     571                 :     }
     572                 : 
     573               0 :     bool isRTL = mFontMetrics->GetTextRunRTL();
     574                 : 
     575                 :     // If we're drawing right to left, we must start at the end.
     576               0 :     if (isRTL) {
     577               0 :         aX += GetWidth(aString, aLength);
     578                 :     }
     579                 : 
     580               0 :     while (aLength > 0) {
     581               0 :         PRInt32 len = FindSafeLength(aString, aLength, maxChunkLength);
     582               0 :         nscoord width = mFontMetrics->GetWidth(aString, len, this);
     583               0 :         if (isRTL) {
     584               0 :             aX -= width;
     585                 :         }
     586               0 :         mFontMetrics->DrawString(aString, len, aX, aY, this, this);
     587               0 :         if (!isRTL) {
     588               0 :             aX += width;
     589                 :         }
     590               0 :         aLength -= len;
     591               0 :         aString += len;
     592                 :     }
     593                 : }

Generated by: LCOV version 1.7