LCOV - code coverage report
Current view: directory - content/canvas/src - nsCanvasRenderingContext2DAzure.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1745 5 0.3 %
Date: 2012-06-02 Functions: 203 3 1.5 %

       1                 : /* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Bas Schouten <bschouten@mozilla.com>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "base/basictypes.h"
      39                 : 
      40                 : #include "nsIDOMXULElement.h"
      41                 : 
      42                 : #include "prmem.h"
      43                 : #include "prenv.h"
      44                 : 
      45                 : #include "nsIServiceManager.h"
      46                 : #include "nsMathUtils.h"
      47                 : 
      48                 : #include "nsContentUtils.h"
      49                 : 
      50                 : #include "nsIDOMDocument.h"
      51                 : #include "nsIDocument.h"
      52                 : #include "nsIDOMCanvasRenderingContext2D.h"
      53                 : #include "nsICanvasRenderingContextInternal.h"
      54                 : #include "nsHTMLCanvasElement.h"
      55                 : #include "nsSVGEffects.h"
      56                 : #include "nsPresContext.h"
      57                 : #include "nsIPresShell.h"
      58                 : #include "nsIVariant.h"
      59                 : 
      60                 : #include "nsIInterfaceRequestorUtils.h"
      61                 : #include "nsIFrame.h"
      62                 : #include "nsDOMError.h"
      63                 : #include "nsIScriptError.h"
      64                 : 
      65                 : #include "nsCSSParser.h"
      66                 : #include "mozilla/css/StyleRule.h"
      67                 : #include "mozilla/css/Declaration.h"
      68                 : #include "nsComputedDOMStyle.h"
      69                 : #include "nsStyleSet.h"
      70                 : 
      71                 : #include "nsPrintfCString.h"
      72                 : 
      73                 : #include "nsReadableUtils.h"
      74                 : 
      75                 : #include "nsColor.h"
      76                 : #include "nsGfxCIID.h"
      77                 : #include "nsIScriptSecurityManager.h"
      78                 : #include "nsIDocShell.h"
      79                 : #include "nsIDOMWindow.h"
      80                 : #include "nsPIDOMWindow.h"
      81                 : #include "nsIDocShell.h"
      82                 : #include "nsIDocShellTreeItem.h"
      83                 : #include "nsIDocShellTreeNode.h"
      84                 : #include "nsIXPConnect.h"
      85                 : #include "jsapi.h"
      86                 : #include "nsDisplayList.h"
      87                 : 
      88                 : #include "nsTArray.h"
      89                 : 
      90                 : #include "imgIEncoder.h"
      91                 : 
      92                 : #include "gfxContext.h"
      93                 : #include "gfxASurface.h"
      94                 : #include "gfxImageSurface.h"
      95                 : #include "gfxPlatform.h"
      96                 : #include "gfxFont.h"
      97                 : #include "gfxBlur.h"
      98                 : #include "gfxUtils.h"
      99                 : 
     100                 : #include "nsFrameManager.h"
     101                 : #include "nsFrameLoader.h"
     102                 : #include "nsBidi.h"
     103                 : #include "nsBidiPresUtils.h"
     104                 : #include "Layers.h"
     105                 : #include "CanvasUtils.h"
     106                 : #include "nsIMemoryReporter.h"
     107                 : #include "nsStyleUtil.h"
     108                 : #include "CanvasImageCache.h"
     109                 : 
     110                 : #include <algorithm>
     111                 : #include "mozilla/dom/ContentParent.h"
     112                 : #include "mozilla/ipc/PDocumentRendererParent.h"
     113                 : #include "mozilla/dom/PBrowserParent.h"
     114                 : #include "mozilla/ipc/DocumentRendererParent.h"
     115                 : 
     116                 : #include "mozilla/gfx/2D.h"
     117                 : #include "mozilla/gfx/PathHelpers.h"
     118                 : #include "mozilla/Preferences.h"
     119                 : 
     120                 : #ifdef XP_WIN
     121                 : #include "gfxWindowsPlatform.h"
     122                 : #endif
     123                 : 
     124                 : // windows.h (included by chromium code) defines this, in its infinite wisdom
     125                 : #undef DrawText
     126                 : 
     127                 : using namespace mozilla;
     128                 : using namespace mozilla::CanvasUtils;
     129                 : using namespace mozilla::css;
     130                 : using namespace mozilla::dom;
     131                 : using namespace mozilla::gfx;
     132                 : using namespace mozilla::ipc;
     133                 : using namespace mozilla::layers;
     134                 : 
     135                 : namespace mgfx = mozilla::gfx;
     136                 : 
     137                 : static float kDefaultFontSize = 10.0;
     138            1464 : static NS_NAMED_LITERAL_STRING(kDefaultFontName, "sans-serif");
     139            1464 : static NS_NAMED_LITERAL_STRING(kDefaultFontStyle, "10px sans-serif");
     140                 : 
     141                 : /* Memory reporter stuff */
     142                 : static nsIMemoryReporter *gCanvasAzureMemoryReporter = nsnull;
     143                 : static PRInt64 gCanvasAzureMemoryUsed = 0;
     144                 : 
     145               0 : static PRInt64 GetCanvasAzureMemoryUsed() {
     146               0 :   return gCanvasAzureMemoryUsed;
     147                 : }
     148                 : 
     149                 : // This is KIND_OTHER because it's not always clear where in memory the pixels
     150                 : // of a canvas are stored.  Furthermore, this memory will be tracked by the
     151                 : // underlying surface implementations.  See bug 655638 for details.
     152               0 : NS_MEMORY_REPORTER_IMPLEMENT(CanvasAzureMemory,
     153                 :   "canvas-2d-pixel-bytes",
     154                 :   KIND_OTHER,
     155                 :   UNITS_BYTES,
     156                 :   GetCanvasAzureMemoryUsed,
     157                 :   "Memory used by 2D canvases. Each canvas requires (width * height * 4) "
     158               0 :   "bytes.")
     159                 : 
     160                 : /**
     161                 :  ** nsCanvasGradientAzure
     162                 :  **/
     163                 : #define NS_CANVASGRADIENTAZURE_PRIVATE_IID \
     164                 :     {0x28425a6a, 0x90e0, 0x4d42, {0x9c, 0x75, 0xff, 0x60, 0x09, 0xb3, 0x10, 0xa8}}
     165                 : class nsCanvasGradientAzure : public nsIDOMCanvasGradient
     166                 : {
     167                 : public:
     168                 :   NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENTAZURE_PRIVATE_IID)
     169                 : 
     170                 :   enum Type
     171                 :   {
     172                 :     LINEAR = 0,
     173                 :     RADIAL
     174                 :   };
     175                 : 
     176               0 :   Type GetType()
     177                 :   {
     178               0 :     return mType;
     179                 :   }
     180                 : 
     181                 : 
     182               0 :   GradientStops *GetGradientStopsForTarget(DrawTarget *aRT)
     183                 :   {
     184               0 :     if (mStops && mStops->GetBackendType() == aRT->GetType()) {
     185               0 :       return mStops;
     186                 :     }
     187                 : 
     188               0 :     mStops = aRT->CreateGradientStops(mRawStops.Elements(), mRawStops.Length());
     189                 : 
     190               0 :     return mStops;
     191                 :   }
     192                 : 
     193                 :   NS_DECL_ISUPPORTS
     194                 : 
     195                 :   /* nsIDOMCanvasGradient */
     196               0 :   NS_IMETHOD AddColorStop (float offset,
     197                 :                             const nsAString& colorstr)
     198                 :   {
     199               0 :     if (!FloatValidate(offset) || offset < 0.0 || offset > 1.0) {
     200               0 :       return NS_ERROR_DOM_INDEX_SIZE_ERR;
     201                 :     }
     202                 : 
     203                 :     nscolor color;
     204               0 :     nsCSSParser parser;
     205               0 :     nsresult rv = parser.ParseColorString(nsString(colorstr),
     206               0 :                                           nsnull, 0, &color);
     207               0 :     if (NS_FAILED(rv)) {
     208               0 :       return NS_ERROR_DOM_SYNTAX_ERR;
     209                 :     }
     210                 : 
     211               0 :     mStops = nsnull;
     212                 : 
     213               0 :     GradientStop newStop;
     214                 : 
     215               0 :     newStop.offset = offset;
     216               0 :     newStop.color = Color::FromABGR(color);
     217                 : 
     218               0 :     mRawStops.AppendElement(newStop);
     219                 : 
     220               0 :     return NS_OK;
     221                 :   }
     222                 : 
     223                 : protected:
     224               0 :   nsCanvasGradientAzure(Type aType) : mType(aType)
     225               0 :   {}
     226                 : 
     227                 :   nsTArray<GradientStop> mRawStops;
     228                 :   RefPtr<GradientStops> mStops;
     229                 :   Type mType;
     230               0 :   virtual ~nsCanvasGradientAzure() {}
     231                 : };
     232                 : 
     233                 : class nsCanvasRadialGradientAzure : public nsCanvasGradientAzure
     234               0 : {
     235                 : public:
     236               0 :   nsCanvasRadialGradientAzure(const Point &aBeginOrigin, Float aBeginRadius,
     237                 :                               const Point &aEndOrigin, Float aEndRadius)
     238                 :     : nsCanvasGradientAzure(RADIAL)
     239                 :     , mCenter1(aBeginOrigin)
     240                 :     , mCenter2(aEndOrigin)
     241                 :     , mRadius1(aBeginRadius)
     242               0 :     , mRadius2(aEndRadius)
     243                 :   {
     244               0 :   }
     245                 : 
     246                 :   Point mCenter1;
     247                 :   Point mCenter2;
     248                 :   Float mRadius1;
     249                 :   Float mRadius2;
     250                 : };
     251                 : 
     252                 : class nsCanvasLinearGradientAzure : public nsCanvasGradientAzure
     253               0 : {
     254                 : public:
     255               0 :   nsCanvasLinearGradientAzure(const Point &aBegin, const Point &aEnd)
     256                 :     : nsCanvasGradientAzure(LINEAR)
     257                 :     , mBegin(aBegin)
     258               0 :     , mEnd(aEnd)
     259                 :   {
     260               0 :   }
     261                 : 
     262                 : protected:
     263                 :   friend class nsCanvasRenderingContext2DAzure;
     264                 : 
     265                 :   // Beginning of linear gradient.
     266                 :   Point mBegin;
     267                 :   // End of linear gradient.
     268                 :   Point mEnd;
     269                 : };
     270                 : 
     271                 : NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasGradientAzure, NS_CANVASGRADIENTAZURE_PRIVATE_IID)
     272                 : 
     273               0 : NS_IMPL_ADDREF(nsCanvasGradientAzure)
     274               0 : NS_IMPL_RELEASE(nsCanvasGradientAzure)
     275                 : 
     276                 : // XXX
     277                 : // DOMCI_DATA(CanvasGradient, nsCanvasGradientAzure)
     278                 : 
     279               0 : NS_INTERFACE_MAP_BEGIN(nsCanvasGradientAzure)
     280               0 :   NS_INTERFACE_MAP_ENTRY(nsCanvasGradientAzure)
     281               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMCanvasGradient)
     282               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CanvasGradient)
     283               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     284               0 : NS_INTERFACE_MAP_END
     285                 : 
     286                 : /**
     287                 :  ** nsCanvasPatternAzure
     288                 :  **/
     289                 : #define NS_CANVASPATTERNAZURE_PRIVATE_IID \
     290                 :     {0xc9bacc25, 0x28da, 0x421e, {0x9a, 0x4b, 0xbb, 0xd6, 0x93, 0x05, 0x12, 0xbc}}
     291                 : class nsCanvasPatternAzure MOZ_FINAL : public nsIDOMCanvasPattern
     292               0 : {
     293                 : public:
     294                 :   NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERNAZURE_PRIVATE_IID)
     295                 : 
     296                 :   enum RepeatMode
     297                 :   {
     298                 :     REPEAT,
     299                 :     REPEATX,
     300                 :     REPEATY,
     301                 :     NOREPEAT
     302                 :   };
     303                 : 
     304               0 :   nsCanvasPatternAzure(SourceSurface* aSurface,
     305                 :                        RepeatMode aRepeat,
     306                 :                        nsIPrincipal* principalForSecurityCheck,
     307                 :                        bool forceWriteOnly,
     308                 :                        bool CORSUsed)
     309                 :     : mSurface(aSurface)
     310                 :     , mRepeat(aRepeat)
     311                 :     , mPrincipal(principalForSecurityCheck)
     312                 :     , mForceWriteOnly(forceWriteOnly)
     313               0 :     , mCORSUsed(CORSUsed)
     314                 :   {
     315               0 :   }
     316                 : 
     317                 :   NS_DECL_ISUPPORTS
     318                 : 
     319                 :   RefPtr<SourceSurface> mSurface;
     320                 :   const RepeatMode mRepeat;
     321                 :   nsCOMPtr<nsIPrincipal> mPrincipal;
     322                 :   const bool mForceWriteOnly;
     323                 :   const bool mCORSUsed;
     324                 : };
     325                 : 
     326                 : NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasPatternAzure, NS_CANVASPATTERNAZURE_PRIVATE_IID)
     327                 : 
     328               0 : NS_IMPL_ADDREF(nsCanvasPatternAzure)
     329               0 : NS_IMPL_RELEASE(nsCanvasPatternAzure)
     330                 : 
     331                 : // XXX
     332                 : // DOMCI_DATA(CanvasPattern, nsCanvasPatternAzure)
     333                 : 
     334               0 : NS_INTERFACE_MAP_BEGIN(nsCanvasPatternAzure)
     335               0 :   NS_INTERFACE_MAP_ENTRY(nsCanvasPatternAzure)
     336               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMCanvasPattern)
     337               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CanvasPattern)
     338               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     339               0 : NS_INTERFACE_MAP_END
     340                 : 
     341                 : /**
     342                 :  ** nsTextMetricsAzure
     343                 :  **/
     344                 : #define NS_TEXTMETRICSAZURE_PRIVATE_IID \
     345                 :   {0x9793f9e7, 0x9dc1, 0x4e9c, {0x81, 0xc8, 0xfc, 0xa7, 0x14, 0xf4, 0x30, 0x79}}
     346                 : class nsTextMetricsAzure : public nsIDOMTextMetrics
     347                 : {
     348                 : public:
     349               0 :   nsTextMetricsAzure(float w) : width(w) { }
     350                 : 
     351               0 :   virtual ~nsTextMetricsAzure() { }
     352                 : 
     353                 :   NS_DECLARE_STATIC_IID_ACCESSOR(NS_TEXTMETRICSAZURE_PRIVATE_IID)
     354                 : 
     355               0 :   NS_IMETHOD GetWidth(float* w) {
     356               0 :     *w = width;
     357               0 :     return NS_OK;
     358                 :   }
     359                 : 
     360                 :   NS_DECL_ISUPPORTS
     361                 : 
     362                 : private:
     363                 :   float width;
     364                 : };
     365                 : 
     366                 : NS_DEFINE_STATIC_IID_ACCESSOR(nsTextMetricsAzure, NS_TEXTMETRICSAZURE_PRIVATE_IID)
     367                 : 
     368               0 : NS_IMPL_ADDREF(nsTextMetricsAzure)
     369               0 : NS_IMPL_RELEASE(nsTextMetricsAzure)
     370                 : 
     371                 : // XXX
     372                 : // DOMCI_DATA(TextMetrics, nsTextMetricsAzure)
     373                 : 
     374               0 : NS_INTERFACE_MAP_BEGIN(nsTextMetricsAzure)
     375               0 :   NS_INTERFACE_MAP_ENTRY(nsTextMetricsAzure)
     376               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMTextMetrics)
     377               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TextMetrics)
     378               0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     379               0 : NS_INTERFACE_MAP_END
     380                 : 
     381                 : struct nsCanvasBidiProcessorAzure;
     382                 : 
     383                 : // Cap sigma to avoid overly large temp surfaces.
     384                 : static const Float SIGMA_MAX = 100;
     385                 : 
     386                 : /**
     387                 :  ** nsCanvasRenderingContext2DAzure
     388                 :  **/
     389                 : class nsCanvasRenderingContext2DAzure :
     390                 :   public nsIDOMCanvasRenderingContext2D,
     391                 :   public nsICanvasRenderingContextInternal
     392                 : {
     393                 : public:
     394                 :   nsCanvasRenderingContext2DAzure();
     395                 :   virtual ~nsCanvasRenderingContext2DAzure();
     396                 : 
     397                 :   nsresult Redraw();
     398                 : 
     399                 :   // nsICanvasRenderingContextInternal
     400                 :   NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* aParentCanvas);
     401                 :   NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
     402               0 :   NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height)
     403               0 :   { return NS_ERROR_NOT_IMPLEMENTED; }
     404                 : 
     405                 :   NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter);
     406                 :   NS_IMETHOD GetInputStream(const char* aMimeType,
     407                 :                             const PRUnichar* aEncoderOptions,
     408                 :                             nsIInputStream **aStream);
     409                 :   NS_IMETHOD GetThebesSurface(gfxASurface **surface);
     410                 : 
     411               0 :   TemporaryRef<SourceSurface> GetSurfaceSnapshot()
     412               0 :   { return mTarget ? mTarget->Snapshot() : nsnull; }
     413                 : 
     414                 :   NS_IMETHOD SetIsOpaque(bool isOpaque);
     415                 :   NS_IMETHOD Reset();
     416                 :   already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
     417                 :                                                 CanvasLayer *aOldLayer,
     418                 :                                                 LayerManager *aManager);
     419                 :   void MarkContextClean();
     420                 :   NS_IMETHOD SetIsIPC(bool isIPC);
     421                 :   // this rect is in canvas device space
     422                 :   void Redraw(const mgfx::Rect &r);
     423               0 :   NS_IMETHOD Redraw(const gfxRect &r) { Redraw(ToRect(r)); return NS_OK; }
     424                 : 
     425                 :   // this rect is in mTarget's current user space
     426                 :   nsresult RedrawUser(const gfxRect &r);
     427                 : 
     428                 :   // nsISupports interface + CC
     429               0 :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     430                 : 
     431            1464 :   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCanvasRenderingContext2DAzure, nsIDOMCanvasRenderingContext2D)
     432                 : 
     433                 :   // nsIDOMCanvasRenderingContext2D interface
     434                 :   NS_DECL_NSIDOMCANVASRENDERINGCONTEXT2D
     435                 : 
     436                 :   enum Style {
     437                 :     STYLE_STROKE = 0,
     438                 :     STYLE_FILL,
     439                 :     STYLE_MAX
     440                 :   };
     441                 :   
     442                 :   nsresult LineTo(const Point& aPoint);
     443                 :   nsresult BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3);
     444                 : 
     445                 : protected:
     446                 :   nsresult InitializeWithTarget(DrawTarget *surface, PRInt32 width, PRInt32 height);
     447                 : 
     448                 :   /**
     449                 :     * The number of living nsCanvasRenderingContexts.  When this goes down to
     450                 :     * 0, we free the premultiply and unpremultiply tables, if they exist.
     451                 :     */
     452                 :   static PRUint32 sNumLivingContexts;
     453                 : 
     454                 :   /**
     455                 :     * Lookup table used to speed up GetImageData().
     456                 :     */
     457                 :   static PRUint8 (*sUnpremultiplyTable)[256];
     458                 : 
     459                 :   /**
     460                 :     * Lookup table used to speed up PutImageData().
     461                 :     */
     462                 :   static PRUint8 (*sPremultiplyTable)[256];
     463                 : 
     464                 :   // Some helpers.  Doesn't modify a color on failure.
     465                 :   nsresult SetStyleFromStringOrInterface(const nsAString& aStr, nsISupports *aInterface, Style aWhichStyle);
     466                 :   nsresult GetStyleAsStringOrInterface(nsAString& aStr, nsISupports **aInterface, PRInt32 *aType, Style aWhichStyle);
     467                 : 
     468                 :   void StyleColorToString(const nscolor& aColor, nsAString& aStr);
     469                 : 
     470                 :   /**
     471                 :     * Creates the unpremultiply lookup table, if it doesn't exist.
     472                 :     */
     473                 :   void EnsureUnpremultiplyTable();
     474                 : 
     475                 :   /**
     476                 :     * Creates the premultiply lookup table, if it doesn't exist.
     477                 :     */
     478                 :   void EnsurePremultiplyTable();
     479                 : 
     480                 :   /* This function ensures there is a writable pathbuilder available, this
     481                 :    * pathbuilder may be working in user space or in device space or
     482                 :    * device space.
     483                 :    */
     484                 :   void EnsureWritablePath();
     485                 : 
     486                 :   // Ensures a path in UserSpace is available.
     487                 :   void EnsureUserSpacePath();
     488                 : 
     489                 :   void TransformWillUpdate();
     490                 : 
     491                 :   // Report the fillRule has changed.
     492                 :   void FillRuleChanged();
     493                 : 
     494                 :   /**
     495                 :     * Returns the surface format this canvas should be allocated using. Takes
     496                 :     * into account mOpaque, platform requirements, etc.
     497                 :     */
     498                 :   SurfaceFormat GetSurfaceFormat() const;
     499                 : 
     500               0 :   nsHTMLCanvasElement *HTMLCanvasElement() {
     501               0 :     return static_cast<nsHTMLCanvasElement*>(mCanvasElement.get());
     502                 :   }
     503                 : 
     504                 :   // Member vars
     505                 :   PRInt32 mWidth, mHeight;
     506                 : 
     507                 :   // This is true when the canvas is valid, false otherwise, this occurs when
     508                 :   // for some reason initialization of the drawtarget fails. If the canvas
     509                 :   // is invalid certain behavior is expected.
     510                 :   bool mValid;
     511                 :   // This is true when the canvas is valid, but of zero size, this requires
     512                 :   // specific behavior on some operations.
     513                 :   bool mZero;
     514                 : 
     515                 :   bool mOpaque;
     516                 : 
     517                 :   // This is true when the next time our layer is retrieved we need to
     518                 :   // recreate it (i.e. our backing surface changed)
     519                 :   bool mResetLayer;
     520                 :   // This is needed for drawing in drawAsyncXULElement
     521                 :   bool mIPC;
     522                 : 
     523                 :   // the canvas element we're a context of
     524                 :   nsCOMPtr<nsIDOMHTMLCanvasElement> mCanvasElement;
     525                 : 
     526                 :   // If mCanvasElement is not provided, then a docshell is
     527                 :   nsCOMPtr<nsIDocShell> mDocShell;
     528                 : 
     529                 :   // our drawing surfaces, contexts, and layers
     530                 :   RefPtr<DrawTarget> mTarget;
     531                 : 
     532                 :   /**
     533                 :     * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
     534                 :     * Redraw is called, reset to false when Render is called.
     535                 :     */
     536                 :   bool mIsEntireFrameInvalid;
     537                 :   /**
     538                 :     * When this is set, the first call to Redraw(gfxRect) should set
     539                 :     * mIsEntireFrameInvalid since we expect it will be followed by
     540                 :     * many more Redraw calls.
     541                 :     */
     542                 :   bool mPredictManyRedrawCalls;
     543                 : 
     544                 :   // This is stored after GetThebesSurface has been called once to avoid
     545                 :   // excessive ThebesSurface initialization overhead.
     546                 :   nsRefPtr<gfxASurface> mThebesSurface;
     547                 : 
     548                 :   /**
     549                 :     * We also have a device space pathbuilder. The reason for this is as
     550                 :     * follows, when a path is being built, but the transform changes, we
     551                 :     * can no longer keep a single path in userspace, considering there's
     552                 :     * several 'user spaces' now. We therefore transform the current path
     553                 :     * into device space, and add all operations to this path in device
     554                 :     * space.
     555                 :     *
     556                 :     * When then finally executing a render, the Azure drawing API expects
     557                 :     * the path to be in userspace. We could then set an identity transform
     558                 :     * on the DrawTarget and do all drawing in device space. This is
     559                 :     * undesirable because it requires transforming patterns, gradients,
     560                 :     * clips, etc. into device space and it would not work for stroking.
     561                 :     * What we do instead is convert the path back to user space when it is
     562                 :     * drawn, and draw it with the current transform. This makes all drawing
     563                 :     * occur correctly.
     564                 :     *
     565                 :     * There's never both a device space path builder and a user space path
     566                 :     * builder present at the same time. There is also never a path and a
     567                 :     * path builder present at the same time. When writing proceeds on an
     568                 :     * existing path the Path is cleared and a new builder is created.
     569                 :     *
     570                 :     * mPath is always in user-space.
     571                 :     */
     572                 :   RefPtr<Path> mPath;
     573                 :   RefPtr<PathBuilder> mDSPathBuilder;
     574                 :   RefPtr<PathBuilder> mPathBuilder;
     575                 :   bool mPathTransformWillUpdate;
     576                 :   Matrix mPathToDS;
     577                 : 
     578                 :   /**
     579                 :     * Number of times we've invalidated before calling redraw
     580                 :     */
     581                 :   PRUint32 mInvalidateCount;
     582                 :   static const PRUint32 kCanvasMaxInvalidateCount = 100;
     583                 : 
     584                 :   /**
     585                 :     * Returns true if a shadow should be drawn along with a
     586                 :     * drawing operation.
     587                 :     */
     588               0 :   bool NeedToDrawShadow()
     589                 :   {
     590               0 :     const ContextState& state = CurrentState();
     591                 : 
     592                 :     // The spec says we should not draw shadows if the operator is OVER.
     593                 :     // If it's over and the alpha value is zero, nothing needs to be drawn.
     594                 :     return NS_GET_A(state.shadowColor) != 0 && 
     595               0 :       (state.shadowBlur != 0 || state.shadowOffset.x != 0 || state.shadowOffset.y != 0);
     596                 :   }
     597                 : 
     598               0 :   CompositionOp UsedOperation()
     599                 :   {
     600               0 :     if (NeedToDrawShadow()) {
     601                 :       // In this case the shadow rendering will use the operator.
     602               0 :       return OP_OVER;
     603                 :     }
     604                 : 
     605               0 :     return CurrentState().op;
     606                 :   }
     607                 : 
     608                 :   /**
     609                 :     * Gets the pres shell from either the canvas element or the doc shell
     610                 :     */
     611               0 :   nsIPresShell *GetPresShell() {
     612               0 :     nsCOMPtr<nsIContent> content = do_QueryObject(mCanvasElement);
     613               0 :     if (content) {
     614               0 :       return content->OwnerDoc()->GetShell();
     615                 :     }
     616               0 :     if (mDocShell) {
     617               0 :       nsCOMPtr<nsIPresShell> shell;
     618               0 :       mDocShell->GetPresShell(getter_AddRefs(shell));
     619               0 :       return shell.get();
     620                 :     }
     621               0 :     return nsnull;
     622                 :   }
     623                 : 
     624                 :   // text
     625                 :   enum TextAlign {
     626                 :     TEXT_ALIGN_START,
     627                 :     TEXT_ALIGN_END,
     628                 :     TEXT_ALIGN_LEFT,
     629                 :     TEXT_ALIGN_RIGHT,
     630                 :     TEXT_ALIGN_CENTER
     631                 :   };
     632                 : 
     633                 :   enum TextBaseline {
     634                 :     TEXT_BASELINE_TOP,
     635                 :     TEXT_BASELINE_HANGING,
     636                 :     TEXT_BASELINE_MIDDLE,
     637                 :     TEXT_BASELINE_ALPHABETIC,
     638                 :     TEXT_BASELINE_IDEOGRAPHIC,
     639                 :     TEXT_BASELINE_BOTTOM
     640                 :   };
     641                 : 
     642                 :   gfxFontGroup *GetCurrentFontStyle();
     643                 : 
     644                 :   enum TextDrawOperation {
     645                 :     TEXT_DRAW_OPERATION_FILL,
     646                 :     TEXT_DRAW_OPERATION_STROKE,
     647                 :     TEXT_DRAW_OPERATION_MEASURE
     648                 :   };
     649                 : 
     650                 :   /*
     651                 :     * Implementation of the fillText, strokeText, and measure functions with
     652                 :     * the operation abstracted to a flag.
     653                 :     */
     654                 :   nsresult DrawOrMeasureText(const nsAString& text,
     655                 :                               float x,
     656                 :                               float y,
     657                 :                               float maxWidth,
     658                 :                               TextDrawOperation op,
     659                 :                               float* aWidth);
     660                 : 
     661                 :   // state stack handling
     662               0 :   class ContextState {
     663                 :   public:
     664               0 :       ContextState() : textAlign(TEXT_ALIGN_START),
     665                 :                        textBaseline(TEXT_BASELINE_ALPHABETIC),
     666                 :                        lineWidth(1.0f),
     667                 :                        miterLimit(10.0f),
     668                 :                        globalAlpha(1.0f),
     669                 :                        shadowBlur(0.0),
     670                 :                        dashOffset(0.0f),
     671                 :                        op(OP_OVER),
     672                 :                        fillRule(FILL_WINDING),
     673                 :                        lineCap(CAP_BUTT),
     674                 :                        lineJoin(JOIN_MITER_OR_BEVEL),
     675               0 :                        imageSmoothingEnabled(true)
     676               0 :       { }
     677                 : 
     678               0 :       ContextState(const ContextState& other)
     679                 :           : fontGroup(other.fontGroup),
     680                 :             font(other.font),
     681                 :             textAlign(other.textAlign),
     682                 :             textBaseline(other.textBaseline),
     683                 :             shadowColor(other.shadowColor),
     684                 :             transform(other.transform),
     685                 :             shadowOffset(other.shadowOffset),
     686                 :             lineWidth(other.lineWidth),
     687                 :             miterLimit(other.miterLimit),
     688                 :             globalAlpha(other.globalAlpha),
     689                 :             shadowBlur(other.shadowBlur),
     690                 :             dash(other.dash),
     691                 :             dashOffset(other.dashOffset),
     692                 :             op(other.op),
     693                 :             fillRule(FILL_WINDING),
     694                 :             lineCap(other.lineCap),
     695                 :             lineJoin(other.lineJoin),
     696               0 :             imageSmoothingEnabled(other.imageSmoothingEnabled)
     697                 :       {
     698               0 :           for (int i = 0; i < STYLE_MAX; i++) {
     699               0 :               colorStyles[i] = other.colorStyles[i];
     700               0 :               gradientStyles[i] = other.gradientStyles[i];
     701               0 :               patternStyles[i] = other.patternStyles[i];
     702                 :           }
     703               0 :       }
     704                 : 
     705               0 :       void SetColorStyle(Style whichStyle, nscolor color) {
     706               0 :           colorStyles[whichStyle] = color;
     707               0 :           gradientStyles[whichStyle] = nsnull;
     708               0 :           patternStyles[whichStyle] = nsnull;
     709               0 :       }
     710                 : 
     711               0 :       void SetPatternStyle(Style whichStyle, nsCanvasPatternAzure* pat) {
     712               0 :           gradientStyles[whichStyle] = nsnull;
     713               0 :           patternStyles[whichStyle] = pat;
     714               0 :       }
     715                 : 
     716               0 :       void SetGradientStyle(Style whichStyle, nsCanvasGradientAzure* grad) {
     717               0 :           gradientStyles[whichStyle] = grad;
     718               0 :           patternStyles[whichStyle] = nsnull;
     719               0 :       }
     720                 : 
     721                 :       /**
     722                 :         * returns true iff the given style is a solid color.
     723                 :         */
     724               0 :       bool StyleIsColor(Style whichStyle) const
     725                 :       {
     726               0 :           return !(patternStyles[whichStyle] ||
     727               0 :                     gradientStyles[whichStyle]);
     728                 :       }
     729                 : 
     730                 : 
     731                 :       std::vector<RefPtr<Path> > clipsPushed;
     732                 : 
     733                 :       nsRefPtr<gfxFontGroup> fontGroup;
     734                 :       nsRefPtr<nsCanvasGradientAzure> gradientStyles[STYLE_MAX];
     735                 :       nsRefPtr<nsCanvasPatternAzure> patternStyles[STYLE_MAX];
     736                 : 
     737                 :       nsString font;
     738                 :       TextAlign textAlign;
     739                 :       TextBaseline textBaseline;
     740                 : 
     741                 :       nscolor colorStyles[STYLE_MAX];
     742                 :       nscolor shadowColor;
     743                 : 
     744                 :       Matrix transform;
     745                 :       Point shadowOffset;
     746                 :       Float lineWidth;
     747                 :       Float miterLimit;
     748                 :       Float globalAlpha;
     749                 :       Float shadowBlur;
     750                 :       FallibleTArray<Float> dash;
     751                 :       Float dashOffset;
     752                 : 
     753                 :       CompositionOp op;
     754                 :       FillRule fillRule;
     755                 :       CapStyle lineCap;
     756                 :       JoinStyle lineJoin;
     757                 : 
     758                 :       bool imageSmoothingEnabled;
     759                 :   };
     760                 : 
     761                 :   class GeneralPattern
     762                 :   {
     763                 :   public:
     764               0 :     GeneralPattern() : mPattern(nsnull) {}
     765               0 :     ~GeneralPattern()
     766                 :     {
     767               0 :       if (mPattern) {
     768               0 :         mPattern->~Pattern();
     769                 :       }
     770               0 :     }
     771                 : 
     772               0 :     Pattern& ForStyle(nsCanvasRenderingContext2DAzure *aCtx,
     773                 :                       Style aStyle,
     774                 :                       DrawTarget *aRT)
     775                 :     {
     776                 :       // This should only be called once or the mPattern destructor will
     777                 :       // not be executed.
     778               0 :       NS_ASSERTION(!mPattern, "ForStyle() should only be called once on GeneralPattern!");
     779                 : 
     780               0 :       const nsCanvasRenderingContext2DAzure::ContextState &state = aCtx->CurrentState();
     781                 : 
     782               0 :       if (state.StyleIsColor(aStyle)) {
     783               0 :         mPattern = new (mColorPattern.addr()) ColorPattern(Color::FromABGR(state.colorStyles[aStyle]));
     784               0 :       } else if (state.gradientStyles[aStyle] &&
     785               0 :                  state.gradientStyles[aStyle]->GetType() == nsCanvasGradientAzure::LINEAR) {
     786                 :         nsCanvasLinearGradientAzure *gradient =
     787               0 :           static_cast<nsCanvasLinearGradientAzure*>(state.gradientStyles[aStyle].get());
     788                 : 
     789               0 :         mPattern = new (mLinearGradientPattern.addr())
     790                 :           LinearGradientPattern(gradient->mBegin, gradient->mEnd,
     791               0 :                                 gradient->GetGradientStopsForTarget(aRT));
     792               0 :       } else if (state.gradientStyles[aStyle] &&
     793               0 :                  state.gradientStyles[aStyle]->GetType() == nsCanvasGradientAzure::RADIAL) {
     794                 :         nsCanvasRadialGradientAzure *gradient =
     795               0 :           static_cast<nsCanvasRadialGradientAzure*>(state.gradientStyles[aStyle].get());
     796                 : 
     797               0 :         mPattern = new (mRadialGradientPattern.addr())
     798                 :           RadialGradientPattern(gradient->mCenter1, gradient->mCenter2, gradient->mRadius1,
     799               0 :                                 gradient->mRadius2, gradient->GetGradientStopsForTarget(aRT));
     800               0 :       } else if (state.patternStyles[aStyle]) {
     801               0 :         if (aCtx->mCanvasElement) {
     802                 :           CanvasUtils::DoDrawImageSecurityCheck(aCtx->HTMLCanvasElement(),
     803               0 :                                                 state.patternStyles[aStyle]->mPrincipal,
     804               0 :                                                 state.patternStyles[aStyle]->mForceWriteOnly,
     805               0 :                                                 state.patternStyles[aStyle]->mCORSUsed);
     806                 :         }
     807                 : 
     808                 :         ExtendMode mode;
     809               0 :         if (state.patternStyles[aStyle]->mRepeat == nsCanvasPatternAzure::NOREPEAT) {
     810               0 :           mode = EXTEND_CLAMP;
     811                 :         } else {
     812               0 :           mode = EXTEND_REPEAT;
     813                 :         }
     814               0 :         mPattern = new (mSurfacePattern.addr())
     815               0 :           SurfacePattern(state.patternStyles[aStyle]->mSurface, mode);
     816                 :       }
     817                 : 
     818               0 :       return *mPattern;
     819                 :     }
     820                 : 
     821                 :     union {
     822                 :       AlignedStorage2<ColorPattern> mColorPattern;
     823                 :       AlignedStorage2<LinearGradientPattern> mLinearGradientPattern;
     824                 :       AlignedStorage2<RadialGradientPattern> mRadialGradientPattern;
     825                 :       AlignedStorage2<SurfacePattern> mSurfacePattern;
     826                 :     };
     827                 :     Pattern *mPattern;
     828                 :   };
     829                 : 
     830                 :   /* This is an RAII based class that can be used as a drawtarget for
     831                 :    * operations that need a shadow drawn. It will automatically provide a
     832                 :    * temporary target when needed, and if so blend it back with a shadow.
     833                 :    *
     834                 :    * aBounds specifies the bounds of the drawing operation that will be
     835                 :    * drawn to the target, it is given in device space! This function will
     836                 :    * change aBounds to incorporate shadow bounds. If this is NULL the drawing
     837                 :    * operation will be assumed to cover an infinite rect.
     838                 :    */
     839                 :   class AdjustedTarget
     840                 :   {
     841                 :   public:
     842               0 :     AdjustedTarget(nsCanvasRenderingContext2DAzure *ctx,
     843                 :                    mgfx::Rect *aBounds = nsnull)
     844               0 :       : mCtx(nsnull)
     845                 :     {
     846               0 :       if (!ctx->NeedToDrawShadow()) {
     847               0 :         mTarget = ctx->mTarget;
     848               0 :         return;
     849                 :       }
     850               0 :       mCtx = ctx;
     851                 : 
     852               0 :       const ContextState &state = mCtx->CurrentState();
     853                 : 
     854               0 :       mSigma = state.shadowBlur / 2.0f;
     855                 : 
     856               0 :       if (mSigma > SIGMA_MAX) {
     857               0 :         mSigma = SIGMA_MAX;
     858                 :       }
     859                 :         
     860               0 :       Matrix transform = mCtx->mTarget->GetTransform();
     861                 : 
     862               0 :       mTempRect = mgfx::Rect(0, 0, ctx->mWidth, ctx->mHeight);
     863                 : 
     864               0 :       Float blurRadius = mSigma * 3;
     865                 : 
     866                 :       // We need to enlarge and possibly offset our temporary surface
     867                 :       // so that things outside of the canvas may cast shadows.
     868               0 :       mTempRect.Inflate(Margin(blurRadius + NS_MAX<Float>(state.shadowOffset.x, 0),
     869               0 :                                blurRadius + NS_MAX<Float>(state.shadowOffset.y, 0),
     870               0 :                                blurRadius + NS_MAX<Float>(-state.shadowOffset.x, 0),
     871               0 :                                blurRadius + NS_MAX<Float>(-state.shadowOffset.y, 0)));
     872                 : 
     873               0 :       if (aBounds) {
     874                 :         // We actually include the bounds of the shadow blur, this makes it
     875                 :         // easier to execute the actual blur on hardware, and shouldn't affect
     876                 :         // the amount of pixels that need to be touched.
     877                 :         aBounds->Inflate(Margin(blurRadius, blurRadius,
     878               0 :                                 blurRadius, blurRadius));
     879               0 :         mTempRect = mTempRect.Intersect(*aBounds);
     880                 :       }
     881                 : 
     882               0 :       mTempRect.ScaleRoundOut(1.0f);
     883                 : 
     884               0 :       transform._31 -= mTempRect.x;
     885               0 :       transform._32 -= mTempRect.y;
     886                 :         
     887                 :       mTarget =
     888               0 :         mCtx->mTarget->CreateSimilarDrawTarget(IntSize(int32_t(mTempRect.width), int32_t(mTempRect.height)),
     889               0 :                                                FORMAT_B8G8R8A8);
     890                 : 
     891               0 :       if (!mTarget) {
     892                 :         // XXX - Deal with the situation where our temp size is too big to
     893                 :         // fit in a texture.
     894               0 :         mTarget = ctx->mTarget;
     895               0 :         mCtx = nsnull;
     896                 :       } else {
     897               0 :         mTarget->SetTransform(transform);
     898                 :       }
     899                 :     }
     900                 : 
     901               0 :     ~AdjustedTarget()
     902               0 :     {
     903               0 :       if (!mCtx) {
     904                 :         return;
     905                 :       }
     906                 : 
     907               0 :       RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
     908                 :       
     909               0 :       mCtx->mTarget->DrawSurfaceWithShadow(snapshot, mTempRect.TopLeft(),
     910               0 :                                            Color::FromABGR(mCtx->CurrentState().shadowColor),
     911               0 :                                            mCtx->CurrentState().shadowOffset, mSigma,
     912               0 :                                            mCtx->CurrentState().op);
     913               0 :     }
     914                 : 
     915               0 :     DrawTarget* operator->()
     916                 :     {
     917               0 :       return mTarget;
     918                 :     }
     919                 : 
     920                 :   private:
     921                 :     RefPtr<DrawTarget> mTarget;
     922                 :     nsCanvasRenderingContext2DAzure *mCtx;
     923                 :     Float mSigma;
     924                 :     mgfx::Rect mTempRect;
     925                 :   };
     926                 : 
     927                 :   nsAutoTArray<ContextState, 3> mStyleStack;
     928                 : 
     929               0 :   inline ContextState& CurrentState() {
     930               0 :     return mStyleStack[mStyleStack.Length() - 1];
     931                 :   }
     932                 :     
     933                 :   // other helpers
     934               0 :   void GetAppUnitsValues(PRUint32 *perDevPixel, PRUint32 *perCSSPixel) {
     935                 :     // If we don't have a canvas element, we just return something generic.
     936               0 :     PRUint32 devPixel = 60;
     937               0 :     PRUint32 cssPixel = 60;
     938                 : 
     939               0 :     nsIPresShell *ps = GetPresShell();
     940                 :     nsPresContext *pc;
     941                 : 
     942               0 :     if (!ps) goto FINISH;
     943               0 :     pc = ps->GetPresContext();
     944               0 :     if (!pc) goto FINISH;
     945               0 :     devPixel = pc->AppUnitsPerDevPixel();
     946               0 :     cssPixel = pc->AppUnitsPerCSSPixel();
     947                 : 
     948                 :   FINISH:
     949               0 :     if (perDevPixel)
     950               0 :       *perDevPixel = devPixel;
     951               0 :     if (perCSSPixel)
     952               0 :       *perCSSPixel = cssPixel;
     953               0 :   }
     954                 : 
     955                 :   friend struct nsCanvasBidiProcessorAzure;
     956                 : };
     957                 : 
     958               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCanvasRenderingContext2DAzure)
     959               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCanvasRenderingContext2DAzure)
     960                 : 
     961            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsCanvasRenderingContext2DAzure)
     962               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCanvasRenderingContext2DAzure)
     963               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCanvasElement)
     964               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     965               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCanvasRenderingContext2DAzure)
     966               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCanvasElement)
     967               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     968                 : 
     969                 : // XXX
     970                 : // DOMCI_DATA(CanvasRenderingContext2D, nsCanvasRenderingContext2DAzure)
     971                 : 
     972               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCanvasRenderingContext2DAzure)
     973               0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMCanvasRenderingContext2D)
     974               0 :   NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
     975               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMCanvasRenderingContext2D)
     976               0 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CanvasRenderingContext2D)
     977               0 : NS_INTERFACE_MAP_END
     978                 : 
     979                 : /**
     980                 :  ** CanvasRenderingContext2D impl
     981                 :  **/
     982                 : 
     983                 : 
     984                 : // Initialize our static variables.
     985                 : PRUint32 nsCanvasRenderingContext2DAzure::sNumLivingContexts = 0;
     986                 : PRUint8 (*nsCanvasRenderingContext2DAzure::sUnpremultiplyTable)[256] = nsnull;
     987                 : PRUint8 (*nsCanvasRenderingContext2DAzure::sPremultiplyTable)[256] = nsnull;
     988                 : 
     989                 : nsresult
     990               0 : NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult)
     991                 : {
     992                 : #ifdef XP_WIN
     993                 :   if ((gfxWindowsPlatform::GetPlatform()->GetRenderMode() !=
     994                 :       gfxWindowsPlatform::RENDER_DIRECT2D ||
     995                 :       !gfxWindowsPlatform::GetPlatform()->DWriteEnabled()) &&
     996                 :       !Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
     997                 :     return NS_ERROR_NOT_AVAILABLE;
     998                 :   }
     999                 : #elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(LINUX)
    1000                 :   return NS_ERROR_NOT_AVAILABLE;
    1001                 : #endif
    1002                 : 
    1003               0 :   nsRefPtr<nsIDOMCanvasRenderingContext2D> ctx = new nsCanvasRenderingContext2DAzure();
    1004               0 :   if (!ctx)
    1005               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1006                 : 
    1007               0 :   *aResult = ctx.forget().get();
    1008               0 :   return NS_OK;
    1009                 : }
    1010                 : 
    1011               0 : nsCanvasRenderingContext2DAzure::nsCanvasRenderingContext2DAzure()
    1012                 :   : mValid(false), mZero(false), mOpaque(false), mResetLayer(true)
    1013                 :   , mIPC(false)
    1014                 :   , mCanvasElement(nsnull)
    1015                 :   , mIsEntireFrameInvalid(false)
    1016                 :   , mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
    1017               0 :   , mInvalidateCount(0)
    1018                 : {
    1019               0 :   sNumLivingContexts++;
    1020               0 : }
    1021                 : 
    1022               0 : nsCanvasRenderingContext2DAzure::~nsCanvasRenderingContext2DAzure()
    1023                 : {
    1024               0 :   Reset();
    1025               0 :   sNumLivingContexts--;
    1026               0 :   if (!sNumLivingContexts) {
    1027               0 :     delete[] sUnpremultiplyTable;
    1028               0 :     delete[] sPremultiplyTable;
    1029               0 :     sUnpremultiplyTable = nsnull;
    1030               0 :     sPremultiplyTable = nsnull;
    1031                 :   }
    1032               0 : }
    1033                 : 
    1034                 : nsresult
    1035               0 : nsCanvasRenderingContext2DAzure::Reset()
    1036                 : {
    1037               0 :   if (mCanvasElement) {
    1038               0 :     HTMLCanvasElement()->InvalidateCanvas();
    1039                 :   }
    1040                 : 
    1041                 :   // only do this for non-docshell created contexts,
    1042                 :   // since those are the ones that we created a surface for
    1043               0 :   if (mValid && !mDocShell) {
    1044               0 :     gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
    1045                 :   }
    1046                 : 
    1047               0 :   mTarget = nsnull;
    1048                 : 
    1049                 :   // Since the target changes the backing texture will change, and this will
    1050                 :   // no longer be valid.
    1051               0 :   mThebesSurface = nsnull;
    1052               0 :   mValid = false;
    1053               0 :   mIsEntireFrameInvalid = false;
    1054               0 :   mPredictManyRedrawCalls = false;
    1055                 : 
    1056               0 :   return NS_OK;
    1057                 : }
    1058                 : 
    1059                 : nsresult
    1060               0 : nsCanvasRenderingContext2DAzure::SetStyleFromStringOrInterface(const nsAString& aStr,
    1061                 :                                                                nsISupports *aInterface,
    1062                 :                                                                Style aWhichStyle)
    1063                 : {
    1064                 :   nsresult rv;
    1065                 :   nscolor color;
    1066                 : 
    1067               0 :   if (!aStr.IsVoid()) {
    1068                 :     nsIDocument* document = mCanvasElement ?
    1069               0 :                             HTMLCanvasElement()->OwnerDoc() : nsnull;
    1070                 : 
    1071                 :     // Pass the CSS Loader object to the parser, to allow parser error
    1072                 :     // reports to include the outer window ID.
    1073               0 :     nsCSSParser parser(document ? document->CSSLoader() : nsnull);
    1074               0 :     rv = parser.ParseColorString(aStr, nsnull, 0, &color);
    1075               0 :     if (NS_FAILED(rv)) {
    1076                 :       // Error reporting happens inside the CSS parser
    1077               0 :       return NS_OK;
    1078                 :     }
    1079                 : 
    1080               0 :     CurrentState().SetColorStyle(aWhichStyle, color);
    1081               0 :     return NS_OK;
    1082                 :   }
    1083                 : 
    1084               0 :   if (aInterface) {
    1085               0 :     nsCOMPtr<nsCanvasGradientAzure> grad(do_QueryInterface(aInterface));
    1086               0 :     if (grad) {
    1087               0 :       CurrentState().SetGradientStyle(aWhichStyle, grad);
    1088               0 :       return NS_OK;
    1089                 :     }
    1090                 : 
    1091               0 :     nsCOMPtr<nsCanvasPatternAzure> pattern(do_QueryInterface(aInterface));
    1092               0 :     if (pattern) {
    1093               0 :       CurrentState().SetPatternStyle(aWhichStyle, pattern);
    1094               0 :       return NS_OK;
    1095                 :     }
    1096                 :   }
    1097                 : 
    1098                 :   nsContentUtils::ReportToConsole(
    1099                 :     nsIScriptError::warningFlag,
    1100                 :     "Canvas",
    1101               0 :     mCanvasElement ? HTMLCanvasElement()->OwnerDoc() : nsnull,
    1102                 :     nsContentUtils::eDOM_PROPERTIES,
    1103               0 :     "UnexpectedCanvasVariantStyle");
    1104                 : 
    1105               0 :   return NS_OK;
    1106                 : }
    1107                 : 
    1108                 : nsresult
    1109               0 : nsCanvasRenderingContext2DAzure::GetStyleAsStringOrInterface(nsAString& aStr,
    1110                 :                                                              nsISupports **aInterface,
    1111                 :                                                              PRInt32 *aType,
    1112                 :                                                              Style aWhichStyle)
    1113                 : {
    1114               0 :   const ContextState &state = CurrentState();
    1115                 : 
    1116               0 :   if (state.patternStyles[aWhichStyle]) {
    1117               0 :     aStr.SetIsVoid(true);
    1118               0 :     NS_ADDREF(*aInterface = state.patternStyles[aWhichStyle]);
    1119               0 :     *aType = CMG_STYLE_PATTERN;
    1120               0 :   } else if (state.gradientStyles[aWhichStyle]) {
    1121               0 :     aStr.SetIsVoid(true);
    1122               0 :     NS_ADDREF(*aInterface = state.gradientStyles[aWhichStyle]);
    1123               0 :     *aType = CMG_STYLE_GRADIENT;
    1124                 :   } else {
    1125               0 :     StyleColorToString(state.colorStyles[aWhichStyle], aStr);
    1126               0 :     *aInterface = nsnull;
    1127               0 :     *aType = CMG_STYLE_STRING;
    1128                 :   }
    1129                 : 
    1130               0 :   return NS_OK;
    1131                 : }
    1132                 : 
    1133                 : void
    1134               0 : nsCanvasRenderingContext2DAzure::StyleColorToString(const nscolor& aColor, nsAString& aStr)
    1135                 : {
    1136                 :   // We can't reuse the normal CSS color stringification code,
    1137                 :   // because the spec calls for a different algorithm for canvas.
    1138               0 :   if (NS_GET_A(aColor) == 255) {
    1139                 :     CopyUTF8toUTF16(nsPrintfCString(100, "#%02x%02x%02x",
    1140                 :                                     NS_GET_R(aColor),
    1141                 :                                     NS_GET_G(aColor),
    1142               0 :                                     NS_GET_B(aColor)),
    1143               0 :                     aStr);
    1144                 :   } else {
    1145                 :     CopyUTF8toUTF16(nsPrintfCString(100, "rgba(%d, %d, %d, ",
    1146                 :                                     NS_GET_R(aColor),
    1147                 :                                     NS_GET_G(aColor),
    1148               0 :                                     NS_GET_B(aColor)),
    1149               0 :                     aStr);
    1150               0 :     aStr.AppendFloat(nsStyleUtil::ColorComponentToFloat(NS_GET_A(aColor)));
    1151               0 :     aStr.Append(')');
    1152                 :   }
    1153               0 : }
    1154                 : 
    1155                 : nsresult
    1156               0 : nsCanvasRenderingContext2DAzure::Redraw()
    1157                 : {
    1158               0 :   if (mIsEntireFrameInvalid) {
    1159               0 :     return NS_OK;
    1160                 :   }
    1161                 : 
    1162               0 :   mIsEntireFrameInvalid = true;
    1163                 : 
    1164               0 :   if (!mCanvasElement) {
    1165               0 :     NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
    1166               0 :     return NS_OK;
    1167                 :   }
    1168                 : 
    1169               0 :   if (!mThebesSurface)
    1170                 :     mThebesSurface =
    1171               0 :       gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
    1172               0 :   mThebesSurface->MarkDirty();
    1173                 : 
    1174               0 :   nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement());
    1175                 : 
    1176               0 :   HTMLCanvasElement()->InvalidateCanvasContent(nsnull);
    1177                 : 
    1178               0 :   return NS_OK;
    1179                 : }
    1180                 : 
    1181                 : void
    1182               0 : nsCanvasRenderingContext2DAzure::Redraw(const mgfx::Rect &r)
    1183                 : {
    1184               0 :   ++mInvalidateCount;
    1185                 : 
    1186               0 :   if (mIsEntireFrameInvalid) {
    1187               0 :     return;
    1188                 :   }
    1189                 : 
    1190               0 :   if (mPredictManyRedrawCalls ||
    1191                 :     mInvalidateCount > kCanvasMaxInvalidateCount) {
    1192               0 :     Redraw();
    1193               0 :     return;
    1194                 :   }
    1195                 : 
    1196               0 :   if (!mCanvasElement) {
    1197               0 :     NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
    1198               0 :     return;
    1199                 :   }
    1200                 : 
    1201               0 :   if (!mThebesSurface)
    1202                 :     mThebesSurface =
    1203               0 :       gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
    1204               0 :   mThebesSurface->MarkDirty();
    1205                 : 
    1206               0 :   nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement());
    1207                 : 
    1208               0 :   gfxRect tmpR = ThebesRect(r);
    1209               0 :   HTMLCanvasElement()->InvalidateCanvasContent(&tmpR);
    1210                 : 
    1211               0 :   return;
    1212                 : }
    1213                 : 
    1214                 : nsresult
    1215               0 : nsCanvasRenderingContext2DAzure::RedrawUser(const gfxRect& r)
    1216                 : {
    1217               0 :   if (mIsEntireFrameInvalid) {
    1218               0 :     ++mInvalidateCount;
    1219               0 :     return NS_OK;
    1220                 :   }
    1221                 : 
    1222                 :   mgfx::Rect newr =
    1223               0 :     mTarget->GetTransform().TransformBounds(ToRect(r));
    1224               0 :   Redraw(newr);
    1225                 : 
    1226               0 :   return NS_OK;
    1227                 : }
    1228                 : 
    1229                 : NS_IMETHODIMP
    1230               0 : nsCanvasRenderingContext2DAzure::SetDimensions(PRInt32 width, PRInt32 height)
    1231                 : {
    1232               0 :   RefPtr<DrawTarget> target;
    1233                 : 
    1234                 :   // Zero sized surfaces cause issues, so just go with 1x1.
    1235               0 :   if (height == 0 || width == 0) {
    1236               0 :     mZero = true;
    1237               0 :     height = 1;
    1238               0 :     width = 1;
    1239                 :   } else {
    1240               0 :     mZero = false;
    1241                 :   }
    1242                 : 
    1243                 :   // Check that the dimensions are sane
    1244               0 :   IntSize size(width, height);
    1245               0 :   if (size.width <= 0xFFFF && size.height <= 0xFFFF &&
    1246                 :       size.width >= 0 && size.height >= 0) {
    1247               0 :     SurfaceFormat format = GetSurfaceFormat();
    1248               0 :     nsCOMPtr<nsIContent> content = do_QueryObject(mCanvasElement);
    1249               0 :     nsIDocument* ownerDoc = nsnull;
    1250               0 :     if (content) {
    1251               0 :       ownerDoc = content->OwnerDoc();
    1252                 :     }
    1253                 : 
    1254               0 :     nsRefPtr<LayerManager> layerManager = nsnull;
    1255                 : 
    1256               0 :     if (ownerDoc) {
    1257                 :       layerManager =
    1258               0 :         nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
    1259                 :     }
    1260                 : 
    1261               0 :     if (layerManager) {
    1262               0 :       target = layerManager->CreateDrawTarget(size, format);
    1263                 :     } else {
    1264               0 :       target = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(size, format);
    1265                 :     }
    1266                 :   }
    1267                 : 
    1268               0 :   if (target) {
    1269               0 :     if (gCanvasAzureMemoryReporter == nsnull) {
    1270               0 :         gCanvasAzureMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasAzureMemory);
    1271               0 :       NS_RegisterMemoryReporter(gCanvasAzureMemoryReporter);
    1272                 :     }
    1273                 : 
    1274               0 :     gCanvasAzureMemoryUsed += width * height * 4;
    1275               0 :     JSContext* context = nsContentUtils::GetCurrentJSContext();
    1276               0 :     if (context) {
    1277               0 :       JS_updateMallocCounter(context, width * height * 4);
    1278                 :     }
    1279                 :   }
    1280                 : 
    1281               0 :   return InitializeWithTarget(target, width, height);
    1282                 : }
    1283                 : 
    1284                 : nsresult
    1285               0 : nsCanvasRenderingContext2DAzure::InitializeWithTarget(DrawTarget *target, PRInt32 width, PRInt32 height)
    1286                 : {
    1287               0 :   Reset();
    1288                 : 
    1289               0 :   NS_ASSERTION(mCanvasElement, "Must have a canvas element!");
    1290               0 :   mDocShell = nsnull;
    1291                 : 
    1292               0 :   mWidth = width;
    1293               0 :   mHeight = height;
    1294                 : 
    1295                 :   // This first time this is called on this object is via
    1296                 :   // nsHTMLCanvasElement::GetContext. If target was non-null then mTarget is
    1297                 :   // non-null, otherwise we'll return an error here and GetContext won't
    1298                 :   // return this context object and we'll never enter this code again.
    1299                 :   // All other times this method is called, if target is null then
    1300                 :   // mTarget won't be changed, i.e. it will remain non-null, or else it
    1301                 :   // will be set to non-null.
    1302                 :   // In all cases, any usable canvas context will have non-null mTarget.
    1303                 : 
    1304               0 :   if (target) {
    1305               0 :     mValid = true;
    1306               0 :     mTarget = target;
    1307                 :   } else {
    1308               0 :     mValid = false;
    1309                 :     // Create a dummy target in the hopes that it will help us deal with users
    1310                 :     // calling into us after having changed the size where the size resulted
    1311                 :     // in an inability to create a correct DrawTarget.
    1312               0 :     mTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
    1313                 :   }
    1314                 : 
    1315               0 :   mResetLayer = true;
    1316                 : 
    1317                 :   // set up the initial canvas defaults
    1318               0 :   mStyleStack.Clear();
    1319               0 :   mPathBuilder = nsnull;
    1320               0 :   mPath = nsnull;
    1321               0 :   mDSPathBuilder = nsnull;
    1322                 : 
    1323               0 :   ContextState *state = mStyleStack.AppendElement();
    1324               0 :   state->globalAlpha = 1.0;
    1325                 : 
    1326               0 :   state->colorStyles[STYLE_FILL] = NS_RGB(0,0,0);
    1327               0 :   state->colorStyles[STYLE_STROKE] = NS_RGB(0,0,0);
    1328               0 :   state->shadowColor = NS_RGBA(0,0,0,0);
    1329                 : 
    1330               0 :   if (mTarget) {
    1331               0 :     mTarget->ClearRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
    1332                 :     // always force a redraw, because if the surface dimensions were reset
    1333                 :     // then the surface became cleared, and we need to redraw everything.
    1334               0 :     Redraw();
    1335                 :   }
    1336                 : 
    1337               0 :   return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
    1338                 : }
    1339                 : 
    1340                 : NS_IMETHODIMP
    1341               0 : nsCanvasRenderingContext2DAzure::SetIsOpaque(bool isOpaque)
    1342                 : {
    1343               0 :   if (isOpaque == mOpaque)
    1344               0 :     return NS_OK;
    1345                 : 
    1346               0 :   mOpaque = isOpaque;
    1347                 : 
    1348               0 :   if (mValid) {
    1349                 :     /* If we've already been created, let SetDimensions take care of
    1350                 :       * recreating our surface
    1351                 :       */
    1352               0 :     return SetDimensions(mWidth, mHeight);
    1353                 :   }
    1354                 : 
    1355               0 :   return NS_OK;
    1356                 : }
    1357                 : 
    1358                 : NS_IMETHODIMP
    1359               0 : nsCanvasRenderingContext2DAzure::SetIsIPC(bool isIPC)
    1360                 : {
    1361               0 :   if (isIPC == mIPC)
    1362               0 :       return NS_OK;
    1363                 : 
    1364               0 :   mIPC = isIPC;
    1365                 : 
    1366               0 :   if (mValid) {
    1367                 :     /* If we've already been created, let SetDimensions take care of
    1368                 :       * recreating our surface
    1369                 :       */
    1370               0 :     return SetDimensions(mWidth, mHeight);
    1371                 :   }
    1372                 : 
    1373               0 :   return NS_OK;
    1374                 : }
    1375                 : 
    1376                 : NS_IMETHODIMP
    1377               0 : nsCanvasRenderingContext2DAzure::Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter)
    1378                 : {
    1379               0 :   nsresult rv = NS_OK;
    1380                 : 
    1381               0 :   if (!mValid || !mTarget) {
    1382               0 :     return NS_ERROR_FAILURE;
    1383                 :   }
    1384                 : 
    1385               0 :   nsRefPtr<gfxASurface> surface;
    1386                 :   
    1387               0 :   if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) {
    1388               0 :     return NS_ERROR_FAILURE;
    1389                 :   }
    1390                 : 
    1391               0 :   nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
    1392                 : 
    1393               0 :   pat->SetFilter(aFilter);
    1394               0 :   pat->SetExtend(gfxPattern::EXTEND_PAD);
    1395                 : 
    1396               0 :   gfxContext::GraphicsOperator op = ctx->CurrentOperator();
    1397               0 :   if (mOpaque)
    1398               0 :       ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
    1399                 : 
    1400                 :   // XXX I don't want to use PixelSnapped here, but layout doesn't guarantee
    1401                 :   // pixel alignment for this stuff!
    1402               0 :   ctx->NewPath();
    1403               0 :   ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
    1404               0 :   ctx->Fill();
    1405                 : 
    1406               0 :   if (mOpaque)
    1407               0 :       ctx->SetOperator(op);
    1408                 : 
    1409               0 :   return rv;
    1410                 : }
    1411                 : 
    1412                 : NS_IMETHODIMP
    1413               0 : nsCanvasRenderingContext2DAzure::GetInputStream(const char *aMimeType,
    1414                 :                                                 const PRUnichar *aEncoderOptions,
    1415                 :                                                 nsIInputStream **aStream)
    1416                 : {
    1417               0 :   if (!mValid || !mTarget) {
    1418               0 :     return NS_ERROR_FAILURE;
    1419                 :   }
    1420                 : 
    1421               0 :   nsRefPtr<gfxASurface> surface;
    1422                 : 
    1423               0 :   if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) {
    1424               0 :     return NS_ERROR_FAILURE;
    1425                 :   }
    1426                 : 
    1427                 :   nsresult rv;
    1428               0 :   const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
    1429               0 :   nsAutoArrayPtr<char> conid(new (std::nothrow) char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
    1430                 : 
    1431               0 :   if (!conid) {
    1432               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1433                 :   }
    1434                 : 
    1435               0 :   strcpy(conid, encoderPrefix);
    1436               0 :   strcat(conid, aMimeType);
    1437                 : 
    1438               0 :   nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
    1439               0 :   if (!encoder) {
    1440               0 :     return NS_ERROR_FAILURE;
    1441                 :   }
    1442                 : 
    1443               0 :   nsAutoArrayPtr<PRUint8> imageBuffer(new (std::nothrow) PRUint8[mWidth * mHeight * 4]);
    1444               0 :   if (!imageBuffer) {
    1445               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1446                 :   }
    1447                 : 
    1448                 :   nsRefPtr<gfxImageSurface> imgsurf =
    1449                 :     new gfxImageSurface(imageBuffer.get(),
    1450                 :                         gfxIntSize(mWidth, mHeight),
    1451                 :                         mWidth * 4,
    1452               0 :                         gfxASurface::ImageFormatARGB32);
    1453                 : 
    1454               0 :   if (!imgsurf || imgsurf->CairoStatus()) {
    1455               0 :     return NS_ERROR_FAILURE;
    1456                 :   }
    1457                 : 
    1458               0 :   nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
    1459                 : 
    1460               0 :   if (!ctx || ctx->HasError()) {
    1461               0 :     return NS_ERROR_FAILURE;
    1462                 :   }
    1463                 : 
    1464               0 :   ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
    1465               0 :   ctx->SetSource(surface, gfxPoint(0, 0));
    1466               0 :   ctx->Paint();
    1467                 : 
    1468               0 :   rv = encoder->InitFromData(imageBuffer.get(),
    1469                 :                               mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4,
    1470                 :                               imgIEncoder::INPUT_FORMAT_HOSTARGB,
    1471               0 :                               nsDependentString(aEncoderOptions));
    1472               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1473                 : 
    1474               0 :   return CallQueryInterface(encoder, aStream);
    1475                 : }
    1476                 : 
    1477                 : SurfaceFormat
    1478               0 : nsCanvasRenderingContext2DAzure::GetSurfaceFormat() const
    1479                 : {
    1480               0 :   return mOpaque ? FORMAT_B8G8R8X8 : FORMAT_B8G8R8A8;
    1481                 : }
    1482                 : 
    1483                 : //
    1484                 : // nsCanvasRenderingContext2DAzure impl
    1485                 : //
    1486                 : 
    1487                 : NS_IMETHODIMP
    1488               0 : nsCanvasRenderingContext2DAzure::SetCanvasElement(nsHTMLCanvasElement* aCanvasElement)
    1489                 : {
    1490               0 :   mCanvasElement = aCanvasElement;
    1491                 : 
    1492               0 :   return NS_OK;
    1493                 : }
    1494                 : 
    1495                 : NS_IMETHODIMP
    1496               0 : nsCanvasRenderingContext2DAzure::GetCanvas(nsIDOMHTMLCanvasElement **canvas)
    1497                 : {
    1498               0 :   NS_IF_ADDREF(*canvas = mCanvasElement);
    1499                 : 
    1500               0 :   return NS_OK;
    1501                 : }
    1502                 : 
    1503                 : //
    1504                 : // state
    1505                 : //
    1506                 : 
    1507                 : NS_IMETHODIMP
    1508               0 : nsCanvasRenderingContext2DAzure::Save()
    1509                 : {
    1510               0 :   mStyleStack[mStyleStack.Length() - 1].transform = mTarget->GetTransform();
    1511               0 :   mStyleStack.SetCapacity(mStyleStack.Length() + 1);
    1512               0 :   mStyleStack.AppendElement(CurrentState());
    1513               0 :   return NS_OK;
    1514                 : }
    1515                 : 
    1516                 : NS_IMETHODIMP
    1517               0 : nsCanvasRenderingContext2DAzure::Restore()
    1518                 : {
    1519               0 :   if (mStyleStack.Length() - 1 == 0)
    1520               0 :     return NS_OK;
    1521                 : 
    1522               0 :   for (PRUint32 i = 0; i < CurrentState().clipsPushed.size(); i++) {
    1523               0 :     mTarget->PopClip();
    1524                 :   }
    1525                 : 
    1526               0 :   mStyleStack.RemoveElementAt(mStyleStack.Length() - 1);
    1527                 : 
    1528               0 :   TransformWillUpdate();
    1529                 : 
    1530               0 :   mTarget->SetTransform(CurrentState().transform);
    1531                 : 
    1532               0 :   return NS_OK;
    1533                 : }
    1534                 : 
    1535                 : //
    1536                 : // transformations
    1537                 : //
    1538                 : 
    1539                 : NS_IMETHODIMP
    1540               0 : nsCanvasRenderingContext2DAzure::Scale(float x, float y)
    1541                 : {
    1542               0 :   if (!FloatValidate(x,y))
    1543               0 :     return NS_OK;
    1544                 : 
    1545               0 :   TransformWillUpdate();
    1546                 : 
    1547               0 :   Matrix newMatrix = mTarget->GetTransform();
    1548               0 :   mTarget->SetTransform(newMatrix.Scale(x, y));
    1549               0 :   return NS_OK;
    1550                 : }
    1551                 : 
    1552                 : NS_IMETHODIMP
    1553               0 : nsCanvasRenderingContext2DAzure::Rotate(float angle)
    1554                 : {
    1555               0 :   if (!FloatValidate(angle))
    1556               0 :     return NS_OK;
    1557                 : 
    1558               0 :   TransformWillUpdate();
    1559                 : 
    1560               0 :   Matrix rotation = Matrix::Rotation(angle);
    1561               0 :   mTarget->SetTransform(rotation * mTarget->GetTransform());
    1562               0 :   return NS_OK;
    1563                 : }
    1564                 : 
    1565                 : NS_IMETHODIMP
    1566               0 : nsCanvasRenderingContext2DAzure::Translate(float x, float y)
    1567                 : {
    1568               0 :   if (!FloatValidate(x,y)) {
    1569               0 :     return NS_OK;
    1570                 :   }
    1571                 : 
    1572               0 :   TransformWillUpdate();
    1573                 : 
    1574               0 :   Matrix newMatrix = mTarget->GetTransform();
    1575               0 :   mTarget->SetTransform(newMatrix.Translate(x, y));
    1576               0 :   return NS_OK;
    1577                 : }
    1578                 : 
    1579                 : NS_IMETHODIMP
    1580               0 : nsCanvasRenderingContext2DAzure::Transform(float m11, float m12, float m21, float m22, float dx, float dy)
    1581                 : {
    1582               0 :   if (!FloatValidate(m11,m12,m21,m22,dx,dy)) {
    1583               0 :     return NS_OK;
    1584                 :   }
    1585                 : 
    1586               0 :   TransformWillUpdate();
    1587                 : 
    1588               0 :   Matrix matrix(m11, m12, m21, m22, dx, dy);
    1589               0 :   mTarget->SetTransform(matrix * mTarget->GetTransform());
    1590               0 :   return NS_OK;
    1591                 : }
    1592                 : 
    1593                 : NS_IMETHODIMP
    1594               0 : nsCanvasRenderingContext2DAzure::SetTransform(float m11, float m12, float m21, float m22, float dx, float dy)
    1595                 : {
    1596               0 :   if (!FloatValidate(m11,m12,m21,m22,dx,dy)) {
    1597               0 :     return NS_OK;
    1598                 :   }
    1599                 : 
    1600               0 :   TransformWillUpdate();
    1601                 : 
    1602               0 :   Matrix matrix(m11, m12, m21, m22, dx, dy);
    1603               0 :   mTarget->SetTransform(matrix);
    1604                 : 
    1605               0 :   return NS_OK;
    1606                 : }
    1607                 : 
    1608                 : NS_IMETHODIMP
    1609               0 : nsCanvasRenderingContext2DAzure::SetMozCurrentTransform(JSContext* cx,
    1610                 :                                                         const jsval& matrix)
    1611                 : {
    1612                 :   nsresult rv;
    1613               0 :   Matrix newCTM;
    1614                 : 
    1615               0 :   if (!JSValToMatrix(cx, matrix, &newCTM, &rv)) {
    1616               0 :     return rv;
    1617                 :   }
    1618                 : 
    1619               0 :   mTarget->SetTransform(newCTM);
    1620                 : 
    1621               0 :   return NS_OK;
    1622                 : }
    1623                 : 
    1624                 : NS_IMETHODIMP
    1625               0 : nsCanvasRenderingContext2DAzure::GetMozCurrentTransform(JSContext* cx,
    1626                 :                                                         jsval* matrix)
    1627                 : {
    1628               0 :   return MatrixToJSVal(mTarget->GetTransform(), cx, matrix);
    1629                 : }
    1630                 : 
    1631                 : NS_IMETHODIMP
    1632               0 : nsCanvasRenderingContext2DAzure::SetMozCurrentTransformInverse(JSContext* cx,
    1633                 :                                                                const jsval& matrix)
    1634                 : {
    1635                 :   nsresult rv;
    1636               0 :   Matrix newCTMInverse;
    1637                 : 
    1638               0 :   if (!JSValToMatrix(cx, matrix, &newCTMInverse, &rv)) {
    1639               0 :     return rv;
    1640                 :   }
    1641                 : 
    1642                 :   // XXX ERRMSG we need to report an error to developers here! (bug 329026)
    1643               0 :   if (newCTMInverse.Invert()) {
    1644               0 :     mTarget->SetTransform(newCTMInverse);
    1645                 :   }
    1646                 : 
    1647               0 :   return NS_OK;
    1648                 : }
    1649                 : 
    1650                 : NS_IMETHODIMP
    1651               0 : nsCanvasRenderingContext2DAzure::GetMozCurrentTransformInverse(JSContext* cx,
    1652                 :                                                                jsval* matrix)
    1653                 : {
    1654               0 :   Matrix ctm = mTarget->GetTransform();
    1655                 : 
    1656               0 :   if (!ctm.Invert()) {
    1657               0 :     double NaN = JSVAL_TO_DOUBLE(JS_GetNaNValue(cx));
    1658               0 :     ctm = Matrix(NaN, NaN, NaN, NaN, NaN, NaN);
    1659                 :   }
    1660                 : 
    1661               0 :   return MatrixToJSVal(ctm, cx, matrix);
    1662                 : }
    1663                 : 
    1664                 : //
    1665                 : // colors
    1666                 : //
    1667                 : 
    1668                 : NS_IMETHODIMP
    1669               0 : nsCanvasRenderingContext2DAzure::SetGlobalAlpha(float aGlobalAlpha)
    1670                 : {
    1671               0 :   if (!FloatValidate(aGlobalAlpha) || aGlobalAlpha < 0.0 || aGlobalAlpha > 1.0) {
    1672               0 :     return NS_OK;
    1673                 :   }
    1674                 : 
    1675               0 :   CurrentState().globalAlpha = aGlobalAlpha;
    1676                 :     
    1677               0 :   return NS_OK;
    1678                 : }
    1679                 : 
    1680                 : NS_IMETHODIMP
    1681               0 : nsCanvasRenderingContext2DAzure::GetGlobalAlpha(float *aGlobalAlpha)
    1682                 : {
    1683               0 :   *aGlobalAlpha = CurrentState().globalAlpha;
    1684               0 :   return NS_OK;
    1685                 : }
    1686                 : 
    1687                 : NS_IMETHODIMP
    1688               0 : nsCanvasRenderingContext2DAzure::SetStrokeStyle(nsIVariant *aValue)
    1689                 : {
    1690               0 :   if (!aValue)
    1691               0 :       return NS_ERROR_FAILURE;
    1692                 : 
    1693               0 :   nsString str;
    1694                 : 
    1695                 :   nsresult rv;
    1696                 :   PRUint16 vtype;
    1697               0 :   rv = aValue->GetDataType(&vtype);
    1698               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1699                 : 
    1700               0 :   if (vtype == nsIDataType::VTYPE_INTERFACE ||
    1701                 :       vtype == nsIDataType::VTYPE_INTERFACE_IS)
    1702                 :   {
    1703                 :     nsIID *iid;
    1704               0 :     nsCOMPtr<nsISupports> sup;
    1705               0 :     rv = aValue->GetAsInterface(&iid, getter_AddRefs(sup));
    1706               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1707               0 :     if (iid) {
    1708               0 :       NS_Free(iid);
    1709                 :     }
    1710                 : 
    1711               0 :     str.SetIsVoid(true);
    1712               0 :     return SetStrokeStyle_multi(str, sup);
    1713                 :   }
    1714                 : 
    1715               0 :   rv = aValue->GetAsAString(str);
    1716               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1717                 : 
    1718               0 :   return SetStrokeStyle_multi(str, nsnull);
    1719                 : }
    1720                 : 
    1721                 : NS_IMETHODIMP
    1722               0 : nsCanvasRenderingContext2DAzure::GetStrokeStyle(nsIVariant **aResult)
    1723                 : {
    1724               0 :   nsCOMPtr<nsIWritableVariant> wv = do_CreateInstance(NS_VARIANT_CONTRACTID);
    1725                 : 
    1726               0 :   nsCOMPtr<nsISupports> sup;
    1727               0 :   nsString str;
    1728                 :   PRInt32 t;
    1729               0 :   nsresult rv = GetStrokeStyle_multi(str, getter_AddRefs(sup), &t);
    1730               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1731                 : 
    1732               0 :   if (t == CMG_STYLE_STRING) {
    1733               0 :     rv = wv->SetAsAString(str);
    1734               0 :   } else if (t == CMG_STYLE_PATTERN) {
    1735               0 :     rv = wv->SetAsInterface(NS_GET_IID(nsIDOMCanvasPattern),
    1736               0 :                             sup);
    1737               0 :   } else if (t == CMG_STYLE_GRADIENT) {
    1738               0 :     rv = wv->SetAsInterface(NS_GET_IID(nsIDOMCanvasGradient),
    1739               0 :                             sup);
    1740                 :   } else {
    1741               0 :     NS_ERROR("Unknown type from GetStroke/FillStyle_multi!");
    1742               0 :     return NS_ERROR_FAILURE;
    1743                 :   }
    1744               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1745                 : 
    1746               0 :   NS_IF_ADDREF(*aResult = wv.get());
    1747               0 :   return NS_OK;
    1748                 : }
    1749                 : 
    1750                 : NS_IMETHODIMP
    1751               0 : nsCanvasRenderingContext2DAzure::SetFillStyle(nsIVariant *aValue)
    1752                 : {
    1753               0 :   if (!aValue) {
    1754               0 :     return NS_ERROR_FAILURE;
    1755                 :   }
    1756                 : 
    1757               0 :   nsString str;
    1758                 :   nsresult rv;
    1759                 :   PRUint16 vtype;
    1760               0 :   rv = aValue->GetDataType(&vtype);
    1761               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1762                 : 
    1763               0 :   if (vtype == nsIDataType::VTYPE_INTERFACE ||
    1764                 :       vtype == nsIDataType::VTYPE_INTERFACE_IS)
    1765                 :   {
    1766                 :     nsIID *iid;
    1767               0 :     nsCOMPtr<nsISupports> sup;
    1768               0 :     rv = aValue->GetAsInterface(&iid, getter_AddRefs(sup));
    1769               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1770                 : 
    1771               0 :     str.SetIsVoid(true);
    1772               0 :     return SetFillStyle_multi(str, sup);
    1773                 :   }
    1774                 : 
    1775               0 :   rv = aValue->GetAsAString(str);
    1776               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1777                 : 
    1778               0 :   return SetFillStyle_multi(str, nsnull);
    1779                 : }
    1780                 : 
    1781                 : NS_IMETHODIMP
    1782               0 : nsCanvasRenderingContext2DAzure::GetFillStyle(nsIVariant **aResult)
    1783                 : {
    1784               0 :   nsCOMPtr<nsIWritableVariant> wv = do_CreateInstance(NS_VARIANT_CONTRACTID);
    1785                 : 
    1786               0 :   nsCOMPtr<nsISupports> sup;
    1787               0 :   nsString str;
    1788                 :   PRInt32 t;
    1789               0 :   nsresult rv = GetFillStyle_multi(str, getter_AddRefs(sup), &t);
    1790               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1791                 : 
    1792               0 :   if (t == CMG_STYLE_STRING) {
    1793               0 :     rv = wv->SetAsAString(str);
    1794               0 :   } else if (t == CMG_STYLE_PATTERN) {
    1795               0 :     rv = wv->SetAsInterface(NS_GET_IID(nsIDOMCanvasPattern),
    1796               0 :                             sup);
    1797               0 :   } else if (t == CMG_STYLE_GRADIENT) {
    1798               0 :     rv = wv->SetAsInterface(NS_GET_IID(nsIDOMCanvasGradient),
    1799               0 :                             sup);
    1800                 :   } else {
    1801               0 :     NS_ERROR("Unknown type from GetStroke/FillStyle_multi!");
    1802               0 :     return NS_ERROR_FAILURE;
    1803                 :   }
    1804               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1805                 : 
    1806               0 :   NS_IF_ADDREF(*aResult = wv.get());
    1807               0 :   return NS_OK;
    1808                 : }
    1809                 : 
    1810                 : NS_IMETHODIMP
    1811               0 : nsCanvasRenderingContext2DAzure::SetMozFillRule(const nsAString& aString)
    1812                 : {
    1813                 :   FillRule rule;
    1814                 : 
    1815               0 :   if (aString.EqualsLiteral("evenodd"))
    1816               0 :     rule = FILL_EVEN_ODD;
    1817               0 :   else if (aString.EqualsLiteral("nonzero"))
    1818               0 :     rule = FILL_WINDING;
    1819                 :   else
    1820               0 :     return NS_OK;
    1821                 : 
    1822               0 :   CurrentState().fillRule = rule;
    1823               0 :   return NS_OK;
    1824                 : }
    1825                 : 
    1826                 : NS_IMETHODIMP
    1827               0 : nsCanvasRenderingContext2DAzure::GetMozFillRule(nsAString& aString)
    1828                 : {
    1829               0 :     switch (CurrentState().fillRule) {
    1830                 :     case FILL_WINDING:
    1831               0 :         aString.AssignLiteral("nonzero"); break;
    1832                 :     case FILL_EVEN_ODD:
    1833               0 :         aString.AssignLiteral("evenodd"); break;
    1834                 :     }
    1835                 : 
    1836               0 :     return NS_OK;
    1837                 : }
    1838                 : 
    1839                 : NS_IMETHODIMP
    1840               0 : nsCanvasRenderingContext2DAzure::SetStrokeStyle_multi(const nsAString& aStr, nsISupports *aInterface)
    1841                 : {
    1842               0 :     return SetStyleFromStringOrInterface(aStr, aInterface, STYLE_STROKE);
    1843                 : }
    1844                 : 
    1845                 : NS_IMETHODIMP
    1846               0 : nsCanvasRenderingContext2DAzure::GetStrokeStyle_multi(nsAString& aStr, nsISupports **aInterface, PRInt32 *aType)
    1847                 : {
    1848               0 :     return GetStyleAsStringOrInterface(aStr, aInterface, aType, STYLE_STROKE);
    1849                 : }
    1850                 : 
    1851                 : NS_IMETHODIMP
    1852               0 : nsCanvasRenderingContext2DAzure::SetFillStyle_multi(const nsAString& aStr, nsISupports *aInterface)
    1853                 : {
    1854               0 :     return SetStyleFromStringOrInterface(aStr, aInterface, STYLE_FILL);
    1855                 : }
    1856                 : 
    1857                 : NS_IMETHODIMP
    1858               0 : nsCanvasRenderingContext2DAzure::GetFillStyle_multi(nsAString& aStr, nsISupports **aInterface, PRInt32 *aType)
    1859                 : {
    1860               0 :     return GetStyleAsStringOrInterface(aStr, aInterface, aType, STYLE_FILL);
    1861                 : }
    1862                 : 
    1863                 : //
    1864                 : // gradients and patterns
    1865                 : //
    1866                 : NS_IMETHODIMP
    1867               0 : nsCanvasRenderingContext2DAzure::CreateLinearGradient(float x0, float y0, float x1, float y1,
    1868                 :                                                       nsIDOMCanvasGradient **_retval)
    1869                 : {
    1870               0 :   if (!FloatValidate(x0,y0,x1,y1)) {
    1871               0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
    1872                 :   }
    1873                 : 
    1874                 :   nsRefPtr<nsIDOMCanvasGradient> grad =
    1875               0 :     new nsCanvasLinearGradientAzure(Point(x0, y0), Point(x1, y1));
    1876                 : 
    1877               0 :   *_retval = grad.forget().get();
    1878               0 :   return NS_OK;
    1879                 : }
    1880                 : 
    1881                 : NS_IMETHODIMP
    1882               0 : nsCanvasRenderingContext2DAzure::CreateRadialGradient(float x0, float y0, float r0,
    1883                 :                                                       float x1, float y1, float r1,
    1884                 :                                                       nsIDOMCanvasGradient **_retval)
    1885                 : {
    1886               0 :   if (!FloatValidate(x0,y0,r0,x1,y1,r1)) {
    1887               0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
    1888                 :   }
    1889                 : 
    1890               0 :   if (r0 < 0.0 || r1 < 0.0) {
    1891               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
    1892                 :   }
    1893                 : 
    1894                 :   nsRefPtr<nsIDOMCanvasGradient> grad =
    1895               0 :     new nsCanvasRadialGradientAzure(Point(x0, y0), r0, Point(x1, y1), r1);
    1896                 : 
    1897               0 :   *_retval = grad.forget().get();
    1898               0 :   return NS_OK;
    1899                 : }
    1900                 : 
    1901                 : NS_IMETHODIMP
    1902               0 : nsCanvasRenderingContext2DAzure::CreatePattern(nsIDOMHTMLElement *image,
    1903                 :                                                const nsAString& repeat,
    1904                 :                                                nsIDOMCanvasPattern **_retval)
    1905                 : {
    1906               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(image);
    1907               0 :   if (!content) {
    1908               0 :     return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
    1909                 :   }
    1910                 : 
    1911                 :   nsCanvasPatternAzure::RepeatMode repeatMode =
    1912               0 :     nsCanvasPatternAzure::NOREPEAT;
    1913                 : 
    1914               0 :   if (repeat.IsEmpty() || repeat.EqualsLiteral("repeat")) {
    1915               0 :     repeatMode = nsCanvasPatternAzure::REPEAT;
    1916               0 :   } else if (repeat.EqualsLiteral("repeat-x")) {
    1917               0 :     repeatMode = nsCanvasPatternAzure::REPEATX;
    1918               0 :   } else if (repeat.EqualsLiteral("repeat-y")) {
    1919               0 :     repeatMode = nsCanvasPatternAzure::REPEATY;
    1920               0 :   } else if (repeat.EqualsLiteral("no-repeat")) {
    1921               0 :     repeatMode = nsCanvasPatternAzure::NOREPEAT;
    1922                 :   } else {
    1923               0 :     return NS_ERROR_DOM_SYNTAX_ERR;
    1924                 :   }
    1925                 : 
    1926               0 :   nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content);
    1927               0 :   if (canvas) {
    1928               0 :     nsIntSize size = canvas->GetSize();
    1929               0 :     if (size.width == 0 || size.height == 0) {
    1930               0 :       return NS_ERROR_DOM_INVALID_STATE_ERR;
    1931                 :     }
    1932                 : 
    1933                 :     // Special case for Canvas, which could be an Azure canvas!
    1934               0 :     nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
    1935               0 :     if (srcCanvas) {
    1936                 :       // This might not be an Azure canvas!
    1937               0 :       RefPtr<SourceSurface> srcSurf = srcCanvas->GetSurfaceSnapshot();
    1938                 : 
    1939                 :       nsRefPtr<nsCanvasPatternAzure> pat =
    1940               0 :         new nsCanvasPatternAzure(srcSurf, repeatMode, content->NodePrincipal(), canvas->IsWriteOnly(), false);
    1941                 : 
    1942               0 :       *_retval = pat.forget().get();
    1943               0 :       return NS_OK;
    1944                 :     }
    1945                 :   }
    1946                 : 
    1947                 :   // The canvas spec says that createPattern should use the first frame
    1948                 :   // of animated images
    1949                 :   nsLayoutUtils::SurfaceFromElementResult res =
    1950               0 :     nsLayoutUtils::SurfaceFromElement(content->AsElement(),
    1951               0 :       nsLayoutUtils::SFE_WANT_FIRST_FRAME | nsLayoutUtils::SFE_WANT_NEW_SURFACE);
    1952                 : 
    1953               0 :   if (!res.mSurface) {
    1954               0 :     return NS_ERROR_NOT_AVAILABLE;
    1955                 :   }
    1956                 : 
    1957                 :   // Ignore nsnull cairo surfaces! See bug 666312.
    1958               0 :   if (!res.mSurface->CairoSurface()) {
    1959               0 :     return NS_OK;
    1960                 :   }
    1961                 : 
    1962                 :   RefPtr<SourceSurface> srcSurf =
    1963               0 :     gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface);
    1964                 : 
    1965                 :   nsRefPtr<nsCanvasPatternAzure> pat =
    1966                 :     new nsCanvasPatternAzure(srcSurf, repeatMode, res.mPrincipal,
    1967               0 :                              res.mIsWriteOnly, res.mCORSUsed);
    1968                 : 
    1969               0 :   *_retval = pat.forget().get();
    1970               0 :   return NS_OK;
    1971                 : }
    1972                 : 
    1973                 : //
    1974                 : // shadows
    1975                 : //
    1976                 : NS_IMETHODIMP
    1977               0 : nsCanvasRenderingContext2DAzure::SetShadowOffsetX(float x)
    1978                 : {
    1979               0 :   if (!FloatValidate(x)) {
    1980               0 :     return NS_OK;
    1981                 :   }
    1982                 : 
    1983               0 :   CurrentState().shadowOffset.x = x;
    1984               0 :   return NS_OK;
    1985                 : }
    1986                 : 
    1987                 : NS_IMETHODIMP
    1988               0 : nsCanvasRenderingContext2DAzure::GetShadowOffsetX(float *x)
    1989                 : {
    1990               0 :   *x = static_cast<float>(CurrentState().shadowOffset.x);
    1991               0 :   return NS_OK;
    1992                 : }
    1993                 : 
    1994                 : NS_IMETHODIMP
    1995               0 : nsCanvasRenderingContext2DAzure::SetShadowOffsetY(float y)
    1996                 : {
    1997               0 :   if (!FloatValidate(y)) {
    1998               0 :     return NS_OK;
    1999                 :   }
    2000                 : 
    2001               0 :   CurrentState().shadowOffset.y = y;
    2002               0 :   return NS_OK;
    2003                 : }
    2004                 : 
    2005                 : NS_IMETHODIMP
    2006               0 : nsCanvasRenderingContext2DAzure::GetShadowOffsetY(float *y)
    2007                 : {
    2008               0 :   *y = static_cast<float>(CurrentState().shadowOffset.y);
    2009               0 :   return NS_OK;
    2010                 : }
    2011                 : 
    2012                 : NS_IMETHODIMP
    2013               0 : nsCanvasRenderingContext2DAzure::SetShadowBlur(float blur)
    2014                 : {
    2015               0 :   if (!FloatValidate(blur) || blur < 0.0) {
    2016               0 :     return NS_OK;
    2017                 :   }
    2018                 : 
    2019               0 :   CurrentState().shadowBlur = blur;
    2020               0 :   return NS_OK;
    2021                 : }
    2022                 : 
    2023                 : NS_IMETHODIMP
    2024               0 : nsCanvasRenderingContext2DAzure::GetShadowBlur(float *blur)
    2025                 : {
    2026               0 :   *blur = CurrentState().shadowBlur;
    2027               0 :   return NS_OK;
    2028                 : }
    2029                 : 
    2030                 : NS_IMETHODIMP
    2031               0 : nsCanvasRenderingContext2DAzure::SetShadowColor(const nsAString& colorstr)
    2032                 : {
    2033                 :   nsIDocument* document = mCanvasElement ?
    2034               0 :                           HTMLCanvasElement()->OwnerDoc() : nsnull;
    2035                 : 
    2036                 :   // Pass the CSS Loader object to the parser, to allow parser error reports
    2037                 :   // to include the outer window ID.
    2038               0 :   nsCSSParser parser(document ? document->CSSLoader() : nsnull);
    2039                 :   nscolor color;
    2040               0 :   nsresult rv = parser.ParseColorString(colorstr, nsnull, 0, &color);
    2041               0 :   if (NS_FAILED(rv)) {
    2042                 :     // Error reporting happens inside the CSS parser
    2043               0 :     return NS_OK;
    2044                 :   }
    2045               0 :   CurrentState().shadowColor = color;
    2046                 : 
    2047               0 :   return NS_OK;
    2048                 : }
    2049                 : 
    2050                 : NS_IMETHODIMP
    2051               0 : nsCanvasRenderingContext2DAzure::GetShadowColor(nsAString& color)
    2052                 : {
    2053               0 :   StyleColorToString(CurrentState().shadowColor, color);
    2054                 : 
    2055               0 :   return NS_OK;
    2056                 : }
    2057                 : 
    2058                 : //
    2059                 : // rects
    2060                 : //
    2061                 : 
    2062                 : NS_IMETHODIMP
    2063               0 : nsCanvasRenderingContext2DAzure::ClearRect(float x, float y, float w, float h)
    2064                 : {
    2065               0 :   if (!FloatValidate(x,y,w,h)) {
    2066               0 :     return NS_OK;
    2067                 :   }
    2068                 :  
    2069               0 :   mTarget->ClearRect(mgfx::Rect(x, y, w, h));
    2070                 : 
    2071               0 :   return RedrawUser(gfxRect(x, y, w, h));
    2072                 : }
    2073                 : 
    2074                 : NS_IMETHODIMP
    2075               0 : nsCanvasRenderingContext2DAzure::FillRect(float x, float y, float w, float h)
    2076                 : {
    2077               0 :   if (!FloatValidate(x,y,w,h)) {
    2078               0 :     return NS_OK;
    2079                 :   }
    2080                 : 
    2081               0 :   const ContextState &state = CurrentState();
    2082                 : 
    2083               0 :   if (state.patternStyles[STYLE_FILL]) {
    2084                 :     nsCanvasPatternAzure::RepeatMode repeat = 
    2085               0 :       state.patternStyles[STYLE_FILL]->mRepeat;
    2086                 :     // In the FillRect case repeat modes are easy to deal with.
    2087               0 :     bool limitx = repeat == nsCanvasPatternAzure::NOREPEAT || repeat == nsCanvasPatternAzure::REPEATY;
    2088               0 :     bool limity = repeat == nsCanvasPatternAzure::NOREPEAT || repeat == nsCanvasPatternAzure::REPEATX;
    2089                 : 
    2090                 :     IntSize patternSize =
    2091               0 :       state.patternStyles[STYLE_FILL]->mSurface->GetSize();
    2092                 : 
    2093                 :     // We always need to execute painting for non-over operators, even if
    2094                 :     // we end up with w/h = 0.
    2095               0 :     if (limitx) {
    2096               0 :       if (x < 0) {
    2097               0 :         w += x;
    2098               0 :         if (w < 0) {
    2099               0 :           w = 0;
    2100                 :         }
    2101                 : 
    2102               0 :         x = 0;
    2103                 :       }
    2104               0 :       if (x + w > patternSize.width) {
    2105               0 :         w = patternSize.width - x;
    2106               0 :         if (w < 0) {
    2107               0 :           w = 0;
    2108                 :         }
    2109                 :       }
    2110                 :     }
    2111               0 :     if (limity) {
    2112               0 :       if (y < 0) {
    2113               0 :         h += y;
    2114               0 :         if (h < 0) {
    2115               0 :           h = 0;
    2116                 :         }
    2117                 : 
    2118               0 :         y = 0;
    2119                 :       }
    2120               0 :       if (y + h > patternSize.height) {
    2121               0 :         h = patternSize.height - y;
    2122               0 :         if (h < 0) {
    2123               0 :           h = 0;
    2124                 :         }
    2125                 :       }
    2126                 :     }
    2127                 :   }
    2128                 : 
    2129               0 :   mgfx::Rect bounds;
    2130                 :   
    2131               0 :   if (NeedToDrawShadow()) {
    2132               0 :     bounds = mgfx::Rect(x, y, w, h);
    2133               0 :     bounds = mTarget->GetTransform().TransformBounds(bounds);
    2134                 :   }
    2135                 : 
    2136               0 :   AdjustedTarget(this, bounds.IsEmpty() ? nsnull : &bounds)->
    2137                 :     FillRect(mgfx::Rect(x, y, w, h),
    2138               0 :              GeneralPattern().ForStyle(this, STYLE_FILL, mTarget),
    2139               0 :              DrawOptions(state.globalAlpha, UsedOperation()));
    2140                 : 
    2141               0 :   return RedrawUser(gfxRect(x, y, w, h));
    2142                 : }
    2143                 : 
    2144                 : NS_IMETHODIMP
    2145               0 : nsCanvasRenderingContext2DAzure::StrokeRect(float x, float y, float w, float h)
    2146                 : {
    2147               0 :   if (!FloatValidate(x,y,w,h)) {
    2148               0 :     return NS_OK;
    2149                 :   }
    2150                 : 
    2151               0 :   const ContextState &state = CurrentState();
    2152                 : 
    2153               0 :   mgfx::Rect bounds;
    2154                 :   
    2155               0 :   if (NeedToDrawShadow()) {
    2156                 :     bounds = mgfx::Rect(x - state.lineWidth / 2.0f, y - state.lineWidth / 2.0f,
    2157               0 :                         w + state.lineWidth, h + state.lineWidth);
    2158               0 :     bounds = mTarget->GetTransform().TransformBounds(bounds);
    2159                 :   }
    2160                 : 
    2161               0 :   if (!w && !h) {
    2162               0 :     return NS_OK;
    2163               0 :   } else if (!h) {
    2164               0 :     CapStyle cap = CAP_BUTT;
    2165               0 :     if (state.lineJoin == JOIN_ROUND) {
    2166               0 :       cap = CAP_ROUND;
    2167                 :     }
    2168               0 :     AdjustedTarget(this, bounds.IsEmpty() ? nsnull : &bounds)->
    2169                 :       StrokeLine(Point(x, y), Point(x + w, y),
    2170               0 :                   GeneralPattern().ForStyle(this, STYLE_STROKE, mTarget),
    2171                 :                   StrokeOptions(state.lineWidth, state.lineJoin,
    2172                 :                                 cap, state.miterLimit,
    2173                 :                                 state.dash.Length(),
    2174                 :                                 state.dash.Elements(),
    2175                 :                                 state.dashOffset),
    2176               0 :                   DrawOptions(state.globalAlpha, UsedOperation()));
    2177               0 :     return NS_OK;
    2178               0 :   } else if (!w) {
    2179               0 :     CapStyle cap = CAP_BUTT;
    2180               0 :     if (state.lineJoin == JOIN_ROUND) {
    2181               0 :       cap = CAP_ROUND;
    2182                 :     }
    2183               0 :     AdjustedTarget(this, bounds.IsEmpty() ? nsnull : &bounds)->
    2184                 :       StrokeLine(Point(x, y), Point(x, y + h),
    2185               0 :                   GeneralPattern().ForStyle(this, STYLE_STROKE, mTarget),
    2186                 :                   StrokeOptions(state.lineWidth, state.lineJoin,
    2187                 :                                 cap, state.miterLimit,
    2188                 :                                 state.dash.Length(),
    2189                 :                                 state.dash.Elements(),
    2190                 :                                 state.dashOffset),
    2191               0 :                   DrawOptions(state.globalAlpha, UsedOperation()));
    2192               0 :     return NS_OK;
    2193                 :   }
    2194                 : 
    2195               0 :   AdjustedTarget(this, bounds.IsEmpty() ? nsnull : &bounds)->
    2196                 :     StrokeRect(mgfx::Rect(x, y, w, h),
    2197               0 :                 GeneralPattern().ForStyle(this, STYLE_STROKE, mTarget),
    2198                 :                 StrokeOptions(state.lineWidth, state.lineJoin,
    2199                 :                               state.lineCap, state.miterLimit,
    2200                 :                               state.dash.Length(),
    2201                 :                               state.dash.Elements(),
    2202                 :                               state.dashOffset),
    2203               0 :                 DrawOptions(state.globalAlpha, UsedOperation()));
    2204                 : 
    2205               0 :   return Redraw();
    2206                 : }
    2207                 : 
    2208                 : //
    2209                 : // path bits
    2210                 : //
    2211                 : 
    2212                 : NS_IMETHODIMP
    2213               0 : nsCanvasRenderingContext2DAzure::BeginPath()
    2214                 : {
    2215               0 :   mPath = nsnull;
    2216               0 :   mPathBuilder = nsnull;
    2217               0 :   mDSPathBuilder = nsnull;
    2218               0 :   mPathTransformWillUpdate = false;
    2219               0 :   return NS_OK;
    2220                 : }
    2221                 : 
    2222                 : NS_IMETHODIMP
    2223               0 : nsCanvasRenderingContext2DAzure::ClosePath()
    2224                 : {
    2225               0 :   EnsureWritablePath();
    2226                 : 
    2227               0 :   if (mPathBuilder) {
    2228               0 :     mPathBuilder->Close();
    2229                 :   } else {
    2230               0 :     mDSPathBuilder->Close();
    2231                 :   }
    2232                 : 
    2233               0 :   return NS_OK;
    2234                 : }
    2235                 : 
    2236                 : NS_IMETHODIMP
    2237               0 : nsCanvasRenderingContext2DAzure::Fill()
    2238                 : {
    2239               0 :   EnsureUserSpacePath();
    2240                 : 
    2241               0 :   if (!mPath) {
    2242               0 :     return NS_OK;
    2243                 :   }
    2244                 : 
    2245               0 :   mgfx::Rect bounds;
    2246                 : 
    2247               0 :   if (NeedToDrawShadow()) {
    2248               0 :     bounds = mPath->GetBounds(mTarget->GetTransform());
    2249                 :   }
    2250                 : 
    2251               0 :   AdjustedTarget(this, bounds.IsEmpty() ? nsnull : &bounds)->
    2252               0 :     Fill(mPath, GeneralPattern().ForStyle(this, STYLE_FILL, mTarget),
    2253               0 :          DrawOptions(CurrentState().globalAlpha, UsedOperation()));
    2254                 : 
    2255               0 :   return Redraw();
    2256                 : }
    2257                 : 
    2258                 : NS_IMETHODIMP
    2259               0 : nsCanvasRenderingContext2DAzure::Stroke()
    2260                 : {
    2261               0 :   EnsureUserSpacePath();
    2262                 : 
    2263               0 :   if (!mPath) {
    2264               0 :     return NS_OK;
    2265                 :   }
    2266                 : 
    2267               0 :   const ContextState &state = CurrentState();
    2268                 : 
    2269                 :   StrokeOptions strokeOptions(state.lineWidth, state.lineJoin,
    2270                 :                               state.lineCap, state.miterLimit,
    2271                 :                               state.dash.Length(), state.dash.Elements(),
    2272               0 :                               state.dashOffset);
    2273                 : 
    2274               0 :   mgfx::Rect bounds;
    2275               0 :   if (NeedToDrawShadow()) {
    2276                 :     bounds =
    2277               0 :       mPath->GetStrokedBounds(strokeOptions, mTarget->GetTransform());
    2278                 :   }
    2279                 : 
    2280               0 :   AdjustedTarget(this, bounds.IsEmpty() ? nsnull : &bounds)->
    2281               0 :     Stroke(mPath, GeneralPattern().ForStyle(this, STYLE_STROKE, mTarget),
    2282               0 :            strokeOptions, DrawOptions(state.globalAlpha, UsedOperation()));
    2283                 : 
    2284               0 :   return Redraw();
    2285                 : }
    2286                 : 
    2287                 : NS_IMETHODIMP
    2288               0 : nsCanvasRenderingContext2DAzure::Clip()
    2289                 : {
    2290               0 :   EnsureUserSpacePath();
    2291                 : 
    2292               0 :   if (!mPath) {
    2293               0 :     return NS_OK;
    2294                 :   }
    2295                 : 
    2296               0 :   mTarget->PushClip(mPath);
    2297               0 :   CurrentState().clipsPushed.push_back(mPath);
    2298                 : 
    2299               0 :   return NS_OK;
    2300                 : }
    2301                 : 
    2302                 : NS_IMETHODIMP
    2303               0 : nsCanvasRenderingContext2DAzure::MoveTo(float x, float y)
    2304                 : {
    2305               0 :   if (!FloatValidate(x,y))
    2306               0 :       return NS_OK;
    2307                 : 
    2308               0 :   EnsureWritablePath();
    2309                 : 
    2310               0 :   if (mPathBuilder) {
    2311               0 :     mPathBuilder->MoveTo(Point(x, y));
    2312                 :   } else {
    2313               0 :     mDSPathBuilder->MoveTo(mTarget->GetTransform() * Point(x, y));
    2314                 :   }
    2315                 : 
    2316               0 :   return NS_OK;
    2317                 : }
    2318                 : 
    2319                 : NS_IMETHODIMP
    2320               0 : nsCanvasRenderingContext2DAzure::LineTo(float x, float y)
    2321                 : {
    2322               0 :   if (!FloatValidate(x,y))
    2323               0 :       return NS_OK;
    2324                 : 
    2325               0 :   EnsureWritablePath();
    2326                 :     
    2327               0 :   return LineTo(Point(x, y));;
    2328                 : }
    2329                 :   
    2330                 : nsresult 
    2331               0 : nsCanvasRenderingContext2DAzure::LineTo(const Point& aPoint)
    2332                 : {
    2333               0 :   if (mPathBuilder) {
    2334               0 :     mPathBuilder->LineTo(aPoint);
    2335                 :   } else {
    2336               0 :     mDSPathBuilder->LineTo(mTarget->GetTransform() * aPoint);
    2337                 :   }
    2338                 : 
    2339               0 :   return NS_OK;
    2340                 : }
    2341                 : 
    2342                 : NS_IMETHODIMP
    2343               0 : nsCanvasRenderingContext2DAzure::QuadraticCurveTo(float cpx, float cpy, float x, float y)
    2344                 : {
    2345               0 :   if (!FloatValidate(cpx, cpy, x, y)) {
    2346               0 :     return NS_OK;
    2347                 :   }
    2348                 : 
    2349               0 :   EnsureWritablePath();
    2350                 : 
    2351               0 :   if (mPathBuilder) {
    2352               0 :     mPathBuilder->QuadraticBezierTo(Point(cpx, cpy), Point(x, y));
    2353                 :   } else {
    2354               0 :     Matrix transform = mTarget->GetTransform();
    2355               0 :     mDSPathBuilder->QuadraticBezierTo(transform * Point(cpx, cpy), transform * Point(x, y));
    2356                 :   }
    2357                 : 
    2358               0 :   return NS_OK;
    2359                 : }
    2360                 : 
    2361                 : NS_IMETHODIMP
    2362               0 : nsCanvasRenderingContext2DAzure::BezierCurveTo(float cp1x, float cp1y,
    2363                 :                                               float cp2x, float cp2y,
    2364                 :                                               float x, float y)
    2365                 : {
    2366               0 :   if (!FloatValidate(cp1x, cp1y, cp2x, cp2y, x, y)) {
    2367               0 :     return NS_OK;
    2368                 :   }
    2369                 : 
    2370               0 :   EnsureWritablePath();
    2371                 : 
    2372               0 :   return BezierTo(Point(cp1x, cp1y), Point(cp2x, cp2y), Point(x, y));
    2373                 : }
    2374                 : 
    2375                 : nsresult
    2376               0 : nsCanvasRenderingContext2DAzure::BezierTo(const Point& aCP1,
    2377                 :                                           const Point& aCP2,
    2378                 :                                           const Point& aCP3)
    2379                 : {
    2380               0 :   if (mPathBuilder) {
    2381               0 :     mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
    2382                 :   } else {
    2383               0 :     Matrix transform = mTarget->GetTransform();
    2384               0 :     mDSPathBuilder->BezierTo(transform * aCP1,
    2385                 :                               transform * aCP2,
    2386               0 :                               transform * aCP3);
    2387                 :   }
    2388                 : 
    2389               0 :   return NS_OK;
    2390                 : }
    2391                 : 
    2392                 : NS_IMETHODIMP
    2393               0 : nsCanvasRenderingContext2DAzure::ArcTo(float x1, float y1, float x2, float y2, float radius)
    2394                 : {
    2395               0 :   if (!FloatValidate(x1, y1, x2, y2, radius)) {
    2396               0 :     return NS_OK;
    2397                 :   }
    2398                 : 
    2399               0 :   if (radius < 0) {
    2400               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
    2401                 :   }
    2402                 : 
    2403               0 :   EnsureWritablePath();
    2404                 : 
    2405                 :   // Current point in user space!
    2406               0 :   Point p0;
    2407               0 :   if (mPathBuilder) {
    2408               0 :     p0 = mPathBuilder->CurrentPoint();
    2409                 :   } else {
    2410               0 :     Matrix invTransform = mTarget->GetTransform();
    2411               0 :     if (!invTransform.Invert()) {
    2412               0 :       return NS_OK;
    2413                 :     }
    2414                 : 
    2415               0 :     p0 = invTransform * mDSPathBuilder->CurrentPoint();
    2416                 :   }
    2417                 : 
    2418               0 :   Point p1(x1, y1);
    2419               0 :   Point p2(x2, y2);
    2420                 : 
    2421                 :   // Execute these calculations in double precision to avoid cumulative
    2422                 :   // rounding errors.
    2423                 :   double dir, a2, b2, c2, cosx, sinx, d, anx, any,
    2424                 :           bnx, bny, x3, y3, x4, y4, cx, cy, angle0, angle1;
    2425                 :   bool anticlockwise;
    2426                 : 
    2427               0 :   if (p0 == p1 || p1 == p2 || radius == 0) {
    2428               0 :     LineTo(p1.x, p1.y);
    2429               0 :     return NS_OK;
    2430                 :   }
    2431                 : 
    2432                 :   // Check for colinearity
    2433               0 :   dir = (p2.x - p1.x) * (p0.y - p1.y) + (p2.y - p1.y) * (p1.x - p0.x);
    2434               0 :   if (dir == 0) {
    2435               0 :     LineTo(p1.x, p1.y);
    2436               0 :     return NS_OK;
    2437                 :   }
    2438                 : 
    2439                 : 
    2440                 :   // XXX - Math for this code was already available from the non-azure code
    2441                 :   // and would be well tested. Perhaps converting to bezier directly might
    2442                 :   // be more efficient longer run.
    2443               0 :   a2 = (p0.x-x1)*(p0.x-x1) + (p0.y-y1)*(p0.y-y1);
    2444               0 :   b2 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
    2445               0 :   c2 = (p0.x-x2)*(p0.x-x2) + (p0.y-y2)*(p0.y-y2);
    2446               0 :   cosx = (a2+b2-c2)/(2*sqrt(a2*b2));
    2447                 : 
    2448               0 :   sinx = sqrt(1 - cosx*cosx);
    2449               0 :   d = radius / ((1 - cosx) / sinx);
    2450                 : 
    2451               0 :   anx = (x1-p0.x) / sqrt(a2);
    2452               0 :   any = (y1-p0.y) / sqrt(a2);
    2453               0 :   bnx = (x1-x2) / sqrt(b2);
    2454               0 :   bny = (y1-y2) / sqrt(b2);
    2455               0 :   x3 = x1 - anx*d;
    2456               0 :   y3 = y1 - any*d;
    2457               0 :   x4 = x1 - bnx*d;
    2458               0 :   y4 = y1 - bny*d;
    2459               0 :   anticlockwise = (dir < 0);
    2460               0 :   cx = x3 + any*radius*(anticlockwise ? 1 : -1);
    2461               0 :   cy = y3 - anx*radius*(anticlockwise ? 1 : -1);
    2462               0 :   angle0 = atan2((y3-cy), (x3-cx));
    2463               0 :   angle1 = atan2((y4-cy), (x4-cx));
    2464                 : 
    2465                 : 
    2466               0 :   LineTo(x3, y3);
    2467                 : 
    2468               0 :   Arc(cx, cy, radius, angle0, angle1, anticlockwise);
    2469               0 :   return NS_OK;
    2470                 : }
    2471                 : 
    2472                 : NS_IMETHODIMP
    2473               0 : nsCanvasRenderingContext2DAzure::Arc(float x, float y,
    2474                 :                                      float r,
    2475                 :                                      float startAngle, float endAngle,
    2476                 :                                      bool ccw)
    2477                 : {
    2478               0 :   if (!FloatValidate(x, y, r, startAngle, endAngle)) {
    2479               0 :     return NS_OK;
    2480                 :   }
    2481                 : 
    2482               0 :   if (r < 0.0)
    2483               0 :       return NS_ERROR_DOM_INDEX_SIZE_ERR;
    2484                 : 
    2485               0 :   EnsureWritablePath();
    2486                 : 
    2487               0 :   ArcToBezier(this, Point(x, y), r, startAngle, endAngle, ccw);
    2488               0 :   return NS_OK;
    2489                 : }
    2490                 : 
    2491                 : NS_IMETHODIMP
    2492               0 : nsCanvasRenderingContext2DAzure::Rect(float x, float y, float w, float h)
    2493                 : {
    2494               0 :   if (!FloatValidate(x, y, w, h)) {
    2495               0 :     return NS_OK;
    2496                 :   }
    2497                 : 
    2498               0 :   EnsureWritablePath();
    2499                 : 
    2500               0 :   if (mPathBuilder) {
    2501               0 :     mPathBuilder->MoveTo(Point(x, y));
    2502               0 :     mPathBuilder->LineTo(Point(x + w, y));
    2503               0 :     mPathBuilder->LineTo(Point(x + w, y + h));
    2504               0 :     mPathBuilder->LineTo(Point(x, y + h));
    2505               0 :     mPathBuilder->Close();
    2506                 :   } else {
    2507               0 :     mDSPathBuilder->MoveTo(mTarget->GetTransform() * Point(x, y));
    2508               0 :     mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(x + w, y));
    2509               0 :     mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(x + w, y + h));
    2510               0 :     mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(x, y + h));
    2511               0 :     mDSPathBuilder->Close();
    2512                 :   }
    2513                 : 
    2514               0 :   return NS_OK;
    2515                 : }
    2516                 : 
    2517                 : void
    2518               0 : nsCanvasRenderingContext2DAzure::EnsureWritablePath()
    2519                 : {
    2520               0 :   if (mDSPathBuilder) {
    2521               0 :     return;
    2522                 :   }
    2523                 : 
    2524               0 :   FillRule fillRule = CurrentState().fillRule;
    2525                 : 
    2526               0 :   if (mPathBuilder) {
    2527               0 :     if (mPathTransformWillUpdate) {
    2528               0 :       mPath = mPathBuilder->Finish();
    2529                 :       mDSPathBuilder =
    2530               0 :         mPath->TransformedCopyToBuilder(mPathToDS, fillRule);
    2531               0 :       mPath = nsnull;
    2532               0 :       mPathBuilder = nsnull;
    2533                 :     }
    2534               0 :     return;
    2535                 :   }
    2536                 : 
    2537               0 :   if (!mPath) {
    2538               0 :     mPathBuilder = mTarget->CreatePathBuilder(fillRule);
    2539               0 :   } else if (!mPathTransformWillUpdate) {
    2540               0 :     mPathBuilder = mPath->CopyToBuilder(fillRule);
    2541                 :   } else {
    2542                 :     mDSPathBuilder =
    2543               0 :       mPath->TransformedCopyToBuilder(mPathToDS, fillRule);
    2544               0 :     mPathTransformWillUpdate = false;
    2545                 :   }
    2546                 : }
    2547                 : 
    2548                 : void
    2549               0 : nsCanvasRenderingContext2DAzure::EnsureUserSpacePath()
    2550                 : {
    2551               0 :   FillRule fillRule = CurrentState().fillRule;
    2552                 : 
    2553               0 :   if (!mPath && !mPathBuilder && !mDSPathBuilder) {
    2554               0 :     mPathBuilder = mTarget->CreatePathBuilder(fillRule);
    2555                 :   }
    2556                 : 
    2557               0 :   if (mPathBuilder) {
    2558               0 :     mPath = mPathBuilder->Finish();
    2559               0 :     mPathBuilder = nsnull;
    2560                 :   }
    2561                 : 
    2562               0 :   if (mPath && mPathTransformWillUpdate) {
    2563                 :     mDSPathBuilder =
    2564               0 :       mPath->TransformedCopyToBuilder(mPathToDS, fillRule);
    2565               0 :     mPath = nsnull;
    2566               0 :     mPathTransformWillUpdate = false;
    2567                 :   }
    2568                 : 
    2569               0 :   if (mDSPathBuilder) {
    2570               0 :     RefPtr<Path> dsPath;
    2571               0 :     dsPath = mDSPathBuilder->Finish();
    2572               0 :     mDSPathBuilder = nsnull;
    2573                 : 
    2574               0 :     Matrix inverse = mTarget->GetTransform();
    2575               0 :     if (!inverse.Invert()) {
    2576                 :       return;
    2577                 :     }
    2578                 : 
    2579                 :     mPathBuilder =
    2580               0 :       dsPath->TransformedCopyToBuilder(inverse, fillRule);
    2581               0 :     mPath = mPathBuilder->Finish();
    2582               0 :     mPathBuilder = nsnull;
    2583                 :   }
    2584                 : 
    2585               0 :   if (mPath && mPath->GetFillRule() != fillRule) {
    2586               0 :     mPathBuilder = mPath->CopyToBuilder(fillRule);
    2587               0 :     mPath = mPathBuilder->Finish();
    2588                 :   }
    2589                 : }
    2590                 : 
    2591                 : void
    2592               0 : nsCanvasRenderingContext2DAzure::TransformWillUpdate()
    2593                 : {
    2594                 :   // Store the matrix that would transform the current path to device
    2595                 :   // space.
    2596               0 :   if (mPath || mPathBuilder) {
    2597               0 :     if (!mPathTransformWillUpdate) {
    2598                 :       // If the transform has already been updated, but a device space builder
    2599                 :       // has not been created yet mPathToDS contains the right transform to
    2600                 :       // transform the current mPath into device space.
    2601                 :       // We should leave it alone.
    2602               0 :       mPathToDS = mTarget->GetTransform();
    2603                 :     }
    2604               0 :     mPathTransformWillUpdate = true;
    2605                 :   }
    2606               0 : }
    2607                 : 
    2608                 : //
    2609                 : // text
    2610                 : //
    2611                 : 
    2612                 : /**
    2613                 :  * Helper function for SetFont that creates a style rule for the given font.
    2614                 :  * @param aFont The CSS font string
    2615                 :  * @param aNode The canvas element
    2616                 :  * @param aResult Pointer in which to place the new style rule.
    2617                 :  * @remark Assumes all pointer arguments are non-null.
    2618                 :  */
    2619                 : static nsresult
    2620               0 : CreateFontStyleRule(const nsAString& aFont,
    2621                 :                     nsINode* aNode,
    2622                 :                     StyleRule** aResult)
    2623                 : {
    2624               0 :   nsRefPtr<StyleRule> rule;
    2625                 :   bool changed;
    2626                 : 
    2627               0 :   nsIPrincipal* principal = aNode->NodePrincipal();
    2628               0 :   nsIDocument* document = aNode->OwnerDoc();
    2629                 : 
    2630               0 :   nsIURI* docURL = document->GetDocumentURI();
    2631               0 :   nsIURI* baseURL = document->GetDocBaseURI();
    2632                 : 
    2633                 :   // Pass the CSS Loader object to the parser, to allow parser error reports
    2634                 :   // to include the outer window ID.
    2635               0 :   nsCSSParser parser(document->CSSLoader());
    2636                 : 
    2637               0 :   nsresult rv = parser.ParseStyleAttribute(EmptyString(), docURL, baseURL,
    2638               0 :                                             principal, getter_AddRefs(rule));
    2639               0 :   if (NS_FAILED(rv)) {
    2640               0 :     return rv;
    2641                 :   }
    2642                 : 
    2643                 :   rv = parser.ParseProperty(eCSSProperty_font, aFont, docURL, baseURL,
    2644                 :                             principal, rule->GetDeclaration(), &changed,
    2645               0 :                             false);
    2646               0 :   if (NS_FAILED(rv))
    2647               0 :     return rv;
    2648                 : 
    2649                 :   rv = parser.ParseProperty(eCSSProperty_line_height,
    2650               0 :                             NS_LITERAL_STRING("normal"), docURL, baseURL,
    2651                 :                             principal, rule->GetDeclaration(), &changed,
    2652               0 :                             false);
    2653               0 :   if (NS_FAILED(rv)) {
    2654               0 :     return rv;
    2655                 :   }
    2656                 : 
    2657               0 :   rule->RuleMatched();
    2658                 : 
    2659               0 :   rule.forget(aResult);
    2660               0 :   return NS_OK;
    2661                 : }
    2662                 : 
    2663                 : NS_IMETHODIMP
    2664               0 : nsCanvasRenderingContext2DAzure::SetFont(const nsAString& font)
    2665                 : {
    2666                 :   nsresult rv;
    2667                 : 
    2668                 :   /*
    2669                 :     * If font is defined with relative units (e.g. ems) and the parent
    2670                 :     * style context changes in between calls, setting the font to the
    2671                 :     * same value as previous could result in a different computed value,
    2672                 :     * so we cannot have the optimization where we check if the new font
    2673                 :     * string is equal to the old one.
    2674                 :     */
    2675                 : 
    2676               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
    2677               0 :   if (!content && !mDocShell) {
    2678               0 :       NS_WARNING("Canvas element must be an nsIContent and non-null or a docshell must be provided");
    2679               0 :       return NS_ERROR_FAILURE;
    2680                 :   }
    2681                 : 
    2682               0 :   nsIPresShell* presShell = GetPresShell();
    2683               0 :   if (!presShell) {
    2684               0 :     return NS_ERROR_FAILURE;
    2685                 :   }
    2686               0 :   nsIDocument* document = presShell->GetDocument();
    2687                 : 
    2688               0 :   nsCOMArray<nsIStyleRule> rules;
    2689                 : 
    2690               0 :   nsRefPtr<css::StyleRule> rule;
    2691               0 :   rv = CreateFontStyleRule(font, document, getter_AddRefs(rule));
    2692                 : 
    2693               0 :   if (NS_FAILED(rv)) {
    2694               0 :     return rv;
    2695                 :   }
    2696                 : 
    2697               0 :   css::Declaration *declaration = rule->GetDeclaration();
    2698                 :   // The easiest way to see whether we got a syntax error or whether
    2699                 :   // we got 'inherit' or 'initial' is to look at font-size-adjust,
    2700                 :   // which the shorthand resets to either 'none' or
    2701                 :   // '-moz-system-font'.
    2702                 :   // We know the declaration is not !important, so we can use
    2703                 :   // GetNormalBlock().
    2704                 :   const nsCSSValue *fsaVal =
    2705               0 :     declaration->GetNormalBlock()->ValueFor(eCSSProperty_font_size_adjust);
    2706               0 :   if (!fsaVal || (fsaVal->GetUnit() != eCSSUnit_None &&
    2707               0 :                   fsaVal->GetUnit() != eCSSUnit_System_Font)) {
    2708                 :       // We got an all-property value or a syntax error.  The spec says
    2709                 :       // this value must be ignored.
    2710               0 :     return NS_OK;
    2711                 :   }
    2712                 : 
    2713               0 :   rules.AppendObject(rule);
    2714                 : 
    2715               0 :   nsStyleSet* styleSet = presShell->StyleSet();
    2716                 : 
    2717                 :   // have to get a parent style context for inherit-like relative
    2718                 :   // values (2em, bolder, etc.)
    2719               0 :   nsRefPtr<nsStyleContext> parentContext;
    2720                 : 
    2721               0 :   if (content && content->IsInDoc()) {
    2722                 :       // inherit from the canvas element
    2723                 :       parentContext = nsComputedDOMStyle::GetStyleContextForElement(
    2724               0 :               content->AsElement(),
    2725                 :               nsnull,
    2726               0 :               presShell);
    2727                 :   } else {
    2728                 :     // otherwise inherit from default (10px sans-serif)
    2729               0 :     nsRefPtr<css::StyleRule> parentRule;
    2730               0 :     rv = CreateFontStyleRule(NS_LITERAL_STRING("10px sans-serif"),
    2731                 :                               document,
    2732               0 :                               getter_AddRefs(parentRule));
    2733                 : 
    2734               0 :     if (NS_FAILED(rv)) {
    2735               0 :       return rv;
    2736                 :     }
    2737                 : 
    2738               0 :     nsCOMArray<nsIStyleRule> parentRules;
    2739               0 :     parentRules.AppendObject(parentRule);
    2740               0 :     parentContext = styleSet->ResolveStyleForRules(nsnull, parentRules);
    2741                 :   }
    2742                 : 
    2743               0 :   if (!parentContext) {
    2744               0 :       return NS_ERROR_FAILURE;
    2745                 :   }
    2746                 : 
    2747                 :   nsRefPtr<nsStyleContext> sc =
    2748               0 :       styleSet->ResolveStyleForRules(parentContext, rules);
    2749               0 :   if (!sc) {
    2750               0 :     return NS_ERROR_FAILURE;
    2751                 :   }
    2752                 : 
    2753               0 :   const nsStyleFont* fontStyle = sc->GetStyleFont();
    2754                 : 
    2755               0 :   NS_ASSERTION(fontStyle, "Could not obtain font style");
    2756                 : 
    2757               0 :   nsIAtom* language = sc->GetStyleFont()->mLanguage;
    2758               0 :   if (!language) {
    2759               0 :     language = presShell->GetPresContext()->GetLanguageFromCharset();
    2760                 :   }
    2761                 : 
    2762                 :   // use CSS pixels instead of dev pixels to avoid being affected by page zoom
    2763               0 :   const PRUint32 aupcp = nsPresContext::AppUnitsPerCSSPixel();
    2764                 :   // un-zoom the font size to avoid being affected by text-only zoom
    2765                 :   //
    2766                 :   // Purposely ignore the font size that respects the user's minimum
    2767                 :   // font preference (fontStyle->mFont.size) in favor of the computed
    2768                 :   // size (fontStyle->mSize).  See
    2769                 :   // https://bugzilla.mozilla.org/show_bug.cgi?id=698652.
    2770               0 :   const nscoord fontSize = nsStyleFont::UnZoomText(parentContext->PresContext(), fontStyle->mSize);
    2771                 : 
    2772               0 :   bool printerFont = (presShell->GetPresContext()->Type() == nsPresContext::eContext_PrintPreview ||
    2773               0 :                         presShell->GetPresContext()->Type() == nsPresContext::eContext_Print);
    2774                 : 
    2775                 :   gfxFontStyle style(fontStyle->mFont.style,
    2776                 :                       fontStyle->mFont.weight,
    2777                 :                       fontStyle->mFont.stretch,
    2778               0 :                       NSAppUnitsToFloatPixels(fontSize, float(aupcp)),
    2779                 :                       language,
    2780                 :                       fontStyle->mFont.sizeAdjust,
    2781                 :                       fontStyle->mFont.systemFont,
    2782                 :                       printerFont,
    2783                 :                       fontStyle->mFont.featureSettings,
    2784               0 :                       fontStyle->mFont.languageOverride);
    2785                 : 
    2786               0 :   CurrentState().fontGroup =
    2787               0 :       gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name,
    2788                 :                                                   &style,
    2789               0 :                                                   presShell->GetPresContext()->GetUserFontSet());
    2790               0 :   NS_ASSERTION(CurrentState().fontGroup, "Could not get font group");
    2791                 : 
    2792                 :   // The font getter is required to be reserialized based on what we
    2793                 :   // parsed (including having line-height removed).  (Older drafts of
    2794                 :   // the spec required font sizes be converted to pixels, but that no
    2795                 :   // longer seems to be required.)
    2796               0 :   declaration->GetValue(eCSSProperty_font, CurrentState().font);
    2797                 : 
    2798               0 :   return NS_OK;
    2799                 : }
    2800                 : 
    2801                 : NS_IMETHODIMP
    2802               0 : nsCanvasRenderingContext2DAzure::GetFont(nsAString& font)
    2803                 : {
    2804                 :   /* will initilize the value if not set, else does nothing */
    2805               0 :   GetCurrentFontStyle();
    2806                 : 
    2807               0 :   font = CurrentState().font;
    2808               0 :   return NS_OK;
    2809                 : }
    2810                 : 
    2811                 : NS_IMETHODIMP
    2812               0 : nsCanvasRenderingContext2DAzure::SetTextAlign(const nsAString& ta)
    2813                 : {
    2814               0 :   if (ta.EqualsLiteral("start"))
    2815               0 :     CurrentState().textAlign = TEXT_ALIGN_START;
    2816               0 :   else if (ta.EqualsLiteral("end"))
    2817               0 :     CurrentState().textAlign = TEXT_ALIGN_END;
    2818               0 :   else if (ta.EqualsLiteral("left"))
    2819               0 :     CurrentState().textAlign = TEXT_ALIGN_LEFT;
    2820               0 :   else if (ta.EqualsLiteral("right"))
    2821               0 :     CurrentState().textAlign = TEXT_ALIGN_RIGHT;
    2822               0 :   else if (ta.EqualsLiteral("center"))
    2823               0 :     CurrentState().textAlign = TEXT_ALIGN_CENTER;
    2824                 : 
    2825               0 :   return NS_OK;
    2826                 : }
    2827                 : 
    2828                 : NS_IMETHODIMP
    2829               0 : nsCanvasRenderingContext2DAzure::GetTextAlign(nsAString& ta)
    2830                 : {
    2831               0 :   switch (CurrentState().textAlign)
    2832                 :   {
    2833                 :   case TEXT_ALIGN_START:
    2834               0 :     ta.AssignLiteral("start");
    2835               0 :     break;
    2836                 :   case TEXT_ALIGN_END:
    2837               0 :     ta.AssignLiteral("end");
    2838               0 :     break;
    2839                 :   case TEXT_ALIGN_LEFT:
    2840               0 :     ta.AssignLiteral("left");
    2841               0 :     break;
    2842                 :   case TEXT_ALIGN_RIGHT:
    2843               0 :     ta.AssignLiteral("right");
    2844               0 :     break;
    2845                 :   case TEXT_ALIGN_CENTER:
    2846               0 :     ta.AssignLiteral("center");
    2847               0 :     break;
    2848                 :   }
    2849                 : 
    2850               0 :   return NS_OK;
    2851                 : }
    2852                 : 
    2853                 : NS_IMETHODIMP
    2854               0 : nsCanvasRenderingContext2DAzure::SetTextBaseline(const nsAString& tb)
    2855                 : {
    2856               0 :   if (tb.EqualsLiteral("top"))
    2857               0 :     CurrentState().textBaseline = TEXT_BASELINE_TOP;
    2858               0 :   else if (tb.EqualsLiteral("hanging"))
    2859               0 :     CurrentState().textBaseline = TEXT_BASELINE_HANGING;
    2860               0 :   else if (tb.EqualsLiteral("middle"))
    2861               0 :     CurrentState().textBaseline = TEXT_BASELINE_MIDDLE;
    2862               0 :   else if (tb.EqualsLiteral("alphabetic"))
    2863               0 :     CurrentState().textBaseline = TEXT_BASELINE_ALPHABETIC;
    2864               0 :   else if (tb.EqualsLiteral("ideographic"))
    2865               0 :     CurrentState().textBaseline = TEXT_BASELINE_IDEOGRAPHIC;
    2866               0 :   else if (tb.EqualsLiteral("bottom"))
    2867               0 :     CurrentState().textBaseline = TEXT_BASELINE_BOTTOM;
    2868                 : 
    2869               0 :   return NS_OK;
    2870                 : }
    2871                 : 
    2872                 : NS_IMETHODIMP
    2873               0 : nsCanvasRenderingContext2DAzure::GetTextBaseline(nsAString& tb)
    2874                 : {
    2875               0 :   switch (CurrentState().textBaseline)
    2876                 :   {
    2877                 :   case TEXT_BASELINE_TOP:
    2878               0 :     tb.AssignLiteral("top");
    2879               0 :     break;
    2880                 :   case TEXT_BASELINE_HANGING:
    2881               0 :     tb.AssignLiteral("hanging");
    2882               0 :     break;
    2883                 :   case TEXT_BASELINE_MIDDLE:
    2884               0 :     tb.AssignLiteral("middle");
    2885               0 :     break;
    2886                 :   case TEXT_BASELINE_ALPHABETIC:
    2887               0 :     tb.AssignLiteral("alphabetic");
    2888               0 :     break;
    2889                 :   case TEXT_BASELINE_IDEOGRAPHIC:
    2890               0 :     tb.AssignLiteral("ideographic");
    2891               0 :     break;
    2892                 :   case TEXT_BASELINE_BOTTOM:
    2893               0 :     tb.AssignLiteral("bottom");
    2894               0 :     break;
    2895                 :   }
    2896                 : 
    2897               0 :   return NS_OK;
    2898                 : }
    2899                 : 
    2900                 : /*
    2901                 :  * Helper function that replaces the whitespace characters in a string
    2902                 :  * with U+0020 SPACE. The whitespace characters are defined as U+0020 SPACE,
    2903                 :  * U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), U+000B LINE
    2904                 :  * TABULATION, U+000C FORM FEED (FF), and U+000D CARRIAGE RETURN (CR).
    2905                 :  * @param str The string whose whitespace characters to replace.
    2906                 :  */
    2907                 : static inline void
    2908               0 : TextReplaceWhitespaceCharacters(nsAutoString& str)
    2909                 : {
    2910               0 :   str.ReplaceChar("\x09\x0A\x0B\x0C\x0D", PRUnichar(' '));
    2911               0 : }
    2912                 : 
    2913                 : NS_IMETHODIMP
    2914               0 : nsCanvasRenderingContext2DAzure::FillText(const nsAString& text, float x, float y, float maxWidth)
    2915                 : {
    2916               0 :   return DrawOrMeasureText(text, x, y, maxWidth, TEXT_DRAW_OPERATION_FILL, nsnull);
    2917                 : }
    2918                 : 
    2919                 : NS_IMETHODIMP
    2920               0 : nsCanvasRenderingContext2DAzure::StrokeText(const nsAString& text, float x, float y, float maxWidth)
    2921                 : {
    2922               0 :   return DrawOrMeasureText(text, x, y, maxWidth, TEXT_DRAW_OPERATION_STROKE, nsnull);
    2923                 : }
    2924                 : 
    2925                 : NS_IMETHODIMP
    2926               0 : nsCanvasRenderingContext2DAzure::MeasureText(const nsAString& rawText,
    2927                 :                                       nsIDOMTextMetrics** _retval)
    2928                 : {
    2929                 :   float width;
    2930                 : 
    2931               0 :   nsresult rv = DrawOrMeasureText(rawText, 0, 0, 0, TEXT_DRAW_OPERATION_MEASURE, &width);
    2932                 : 
    2933               0 :   if (NS_FAILED(rv)) {
    2934               0 :     return rv;
    2935                 :   }
    2936                 : 
    2937               0 :   nsRefPtr<nsIDOMTextMetrics> textMetrics = new nsTextMetricsAzure(width);
    2938               0 :   if (!textMetrics.get()) {
    2939               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2940                 :   }
    2941                 : 
    2942               0 :   *_retval = textMetrics.forget().get();
    2943                 : 
    2944               0 :   return NS_OK;
    2945                 : }
    2946                 : 
    2947                 : /**
    2948                 :  * Used for nsBidiPresUtils::ProcessText
    2949                 :  */
    2950                 : struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiProcessor
    2951               0 : {
    2952                 :   typedef nsCanvasRenderingContext2DAzure::ContextState ContextState;
    2953                 : 
    2954               0 :   virtual void SetText(const PRUnichar* text, PRInt32 length, nsBidiDirection direction)
    2955                 :   {
    2956               0 :     mFontgrp->UpdateFontList(); // ensure user font generation is current
    2957                 :     mTextRun = mFontgrp->MakeTextRun(text,
    2958                 :                                      length,
    2959                 :                                      mThebes,
    2960                 :                                      mAppUnitsPerDevPixel,
    2961               0 :                                      direction==NSBIDI_RTL ? gfxTextRunFactory::TEXT_IS_RTL : 0);
    2962               0 :   }
    2963                 : 
    2964               0 :   virtual nscoord GetWidth()
    2965                 :   {
    2966                 :     gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0,
    2967                 :                                                                mTextRun->GetLength(),
    2968                 :                                                                mDoMeasureBoundingBox ?
    2969                 :                                                                  gfxFont::TIGHT_INK_EXTENTS :
    2970                 :                                                                  gfxFont::LOOSE_INK_EXTENTS,
    2971                 :                                                                mThebes,
    2972               0 :                                                                nsnull);
    2973                 : 
    2974                 :     // this only measures the height; the total width is gotten from the
    2975                 :     // the return value of ProcessText.
    2976               0 :     if (mDoMeasureBoundingBox) {
    2977               0 :       textRunMetrics.mBoundingBox.Scale(1.0 / mAppUnitsPerDevPixel);
    2978               0 :       mBoundingBox = mBoundingBox.Union(textRunMetrics.mBoundingBox);
    2979                 :     }
    2980                 : 
    2981               0 :     return NSToCoordRound(textRunMetrics.mAdvanceWidth);
    2982                 :   }
    2983                 : 
    2984               0 :   virtual void DrawText(nscoord xOffset, nscoord width)
    2985                 :   {
    2986               0 :     gfxPoint point = mPt;
    2987               0 :     point.x += xOffset;
    2988                 : 
    2989                 :     // offset is given in terms of left side of string
    2990               0 :     if (mTextRun->IsRightToLeft()) {
    2991                 :       // Bug 581092 - don't use rounded pixel width to advance to
    2992                 :       // right-hand end of run, because this will cause different
    2993                 :       // glyph positioning for LTR vs RTL drawing of the same
    2994                 :       // glyph string on OS X and DWrite where textrun widths may
    2995                 :       // involve fractional pixels.
    2996                 :       gfxTextRun::Metrics textRunMetrics =
    2997                 :         mTextRun->MeasureText(0,
    2998                 :                               mTextRun->GetLength(),
    2999                 :                               mDoMeasureBoundingBox ?
    3000                 :                                   gfxFont::TIGHT_INK_EXTENTS :
    3001                 :                                   gfxFont::LOOSE_INK_EXTENTS,
    3002                 :                               mThebes,
    3003               0 :                               nsnull);
    3004               0 :       point.x += textRunMetrics.mAdvanceWidth;
    3005                 :       // old code was:
    3006                 :       //   point.x += width * mAppUnitsPerDevPixel;
    3007                 :       // TODO: restore this if/when we move to fractional coords
    3008                 :       // throughout the text layout process
    3009                 :     }
    3010                 : 
    3011                 :     PRUint32 numRuns;
    3012               0 :     const gfxTextRun::GlyphRun *runs = mTextRun->GetGlyphRuns(&numRuns);
    3013               0 :     const PRUint32 appUnitsPerDevUnit = mAppUnitsPerDevPixel;
    3014               0 :     const double devUnitsPerAppUnit = 1.0/double(appUnitsPerDevUnit);
    3015                 :     Point baselineOrigin =
    3016               0 :       Point(point.x * devUnitsPerAppUnit, point.y * devUnitsPerAppUnit);
    3017                 : 
    3018               0 :     float advanceSum = 0;
    3019                 : 
    3020               0 :     for (PRUint32 c = 0; c < numRuns; c++) {
    3021               0 :       gfxFont *font = runs[c].mFont;
    3022               0 :       PRUint32 endRun = 0;
    3023               0 :       if (c + 1 < numRuns) {
    3024               0 :         endRun = runs[c + 1].mCharacterOffset;
    3025                 :       } else {
    3026               0 :         endRun = mTextRun->GetLength();
    3027                 :       }
    3028                 : 
    3029               0 :       const gfxTextRun::CompressedGlyph *glyphs = mTextRun->GetCharacterGlyphs();
    3030                 : 
    3031                 :       RefPtr<ScaledFont> scaledFont =
    3032               0 :         gfxPlatform::GetPlatform()->GetScaledFontForFont(font);
    3033                 : 
    3034               0 :       if (!scaledFont) {
    3035                 :         // This can occur when something switched DirectWrite off.
    3036                 :         return;
    3037                 :       }
    3038                 : 
    3039                 :       GlyphBuffer buffer;
    3040                 : 
    3041               0 :       std::vector<Glyph> glyphBuf;
    3042                 : 
    3043               0 :       for (PRUint32 i = runs[c].mCharacterOffset; i < endRun; i++) {
    3044               0 :         Glyph newGlyph;
    3045               0 :         if (glyphs[i].IsSimpleGlyph()) {
    3046               0 :           newGlyph.mIndex = glyphs[i].GetSimpleGlyph();
    3047               0 :           if (mTextRun->IsRightToLeft()) {
    3048                 :             newGlyph.mPosition.x = baselineOrigin.x - advanceSum -
    3049               0 :               glyphs[i].GetSimpleAdvance() * devUnitsPerAppUnit;
    3050                 :           } else {
    3051               0 :             newGlyph.mPosition.x = baselineOrigin.x + advanceSum;
    3052                 :           }
    3053               0 :           newGlyph.mPosition.y = baselineOrigin.y;
    3054               0 :           advanceSum += glyphs[i].GetSimpleAdvance() * devUnitsPerAppUnit;
    3055               0 :           glyphBuf.push_back(newGlyph);
    3056               0 :           continue;
    3057                 :         }
    3058                 : 
    3059               0 :         if (!glyphs[i].GetGlyphCount()) {
    3060               0 :           continue;
    3061                 :         }
    3062                 : 
    3063                 :         gfxTextRun::DetailedGlyph *detailedGlyphs =
    3064               0 :           mTextRun->GetDetailedGlyphs(i);
    3065                 : 
    3066               0 :         for (PRUint32 c = 0; c < glyphs[i].GetGlyphCount(); c++) {
    3067               0 :           newGlyph.mIndex = detailedGlyphs[c].mGlyphID;
    3068               0 :           if (mTextRun->IsRightToLeft()) {
    3069               0 :             newGlyph.mPosition.x = baselineOrigin.x + detailedGlyphs[c].mXOffset * devUnitsPerAppUnit -
    3070               0 :               advanceSum - detailedGlyphs[c].mAdvance * devUnitsPerAppUnit;
    3071                 :           } else {
    3072               0 :             newGlyph.mPosition.x = baselineOrigin.x + detailedGlyphs[c].mXOffset * devUnitsPerAppUnit + advanceSum;
    3073                 :           }
    3074               0 :           newGlyph.mPosition.y = baselineOrigin.y + detailedGlyphs[c].mYOffset * devUnitsPerAppUnit;
    3075               0 :           glyphBuf.push_back(newGlyph);
    3076               0 :           advanceSum += detailedGlyphs[c].mAdvance * devUnitsPerAppUnit;
    3077                 :         }
    3078                 :       }
    3079                 : 
    3080               0 :       if (!glyphBuf.size()) {
    3081                 :         // This may happen for glyph runs for a 0 size font.
    3082               0 :         continue;
    3083                 :       }
    3084                 : 
    3085               0 :       buffer.mGlyphs = &glyphBuf.front();
    3086               0 :       buffer.mNumGlyphs = glyphBuf.size();
    3087                 : 
    3088               0 :       if (mOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_FILL) {
    3089               0 :         nsCanvasRenderingContext2DAzure::AdjustedTarget(mCtx)->
    3090                 :           FillGlyphs(scaledFont, buffer,
    3091               0 :                       nsCanvasRenderingContext2DAzure::GeneralPattern().
    3092               0 :                         ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_FILL, mCtx->mTarget),
    3093               0 :                       DrawOptions(mState->globalAlpha, mCtx->UsedOperation()));
    3094               0 :       } else if (mOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_STROKE) {
    3095               0 :         RefPtr<Path> path = scaledFont->GetPathForGlyphs(buffer, mCtx->mTarget);
    3096                 : 
    3097               0 :         const ContextState& state = *mState;
    3098               0 :         nsCanvasRenderingContext2DAzure::AdjustedTarget(mCtx)->
    3099               0 :           Stroke(path, nsCanvasRenderingContext2DAzure::GeneralPattern().
    3100               0 :                     ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_STROKE, mCtx->mTarget),
    3101                 :                   StrokeOptions(state.lineWidth, state.lineJoin,
    3102                 :                                 state.lineCap, state.miterLimit,
    3103                 :                                 state.dash.Length(),
    3104                 :                                 state.dash.Elements(),
    3105                 :                                 state.dashOffset),
    3106               0 :                   DrawOptions(state.globalAlpha, mCtx->UsedOperation()));
    3107                 : 
    3108                 :       }
    3109                 :     }
    3110                 :   }
    3111                 : 
    3112                 :   // current text run
    3113                 :   nsAutoPtr<gfxTextRun> mTextRun;
    3114                 : 
    3115                 :   // pointer to a screen reference context used to measure text and such
    3116                 :   nsRefPtr<gfxContext> mThebes;
    3117                 : 
    3118                 :   // Pointer to the draw target we should fill our text to
    3119                 :   nsCanvasRenderingContext2DAzure *mCtx;
    3120                 : 
    3121                 :   // position of the left side of the string, alphabetic baseline
    3122                 :   gfxPoint mPt;
    3123                 : 
    3124                 :   // current font
    3125                 :   gfxFontGroup* mFontgrp;
    3126                 : 
    3127                 :   // dev pixel conversion factor
    3128                 :   PRUint32 mAppUnitsPerDevPixel;
    3129                 : 
    3130                 :   // operation (fill or stroke)
    3131                 :   nsCanvasRenderingContext2DAzure::TextDrawOperation mOp;
    3132                 : 
    3133                 :   // context state
    3134                 :   ContextState *mState;
    3135                 : 
    3136                 :   // union of bounding boxes of all runs, needed for shadows
    3137                 :   gfxRect mBoundingBox;
    3138                 : 
    3139                 :   // true iff the bounding box should be measured
    3140                 :   bool mDoMeasureBoundingBox;
    3141                 : };
    3142                 : 
    3143                 : nsresult
    3144               0 : nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText,
    3145                 :                                                    float aX,
    3146                 :                                                    float aY,
    3147                 :                                                    float aMaxWidth,
    3148                 :                                                    TextDrawOperation aOp,
    3149                 :                                                    float* aWidth)
    3150                 : {
    3151                 :   nsresult rv;
    3152                 : 
    3153               0 :   if (!FloatValidate(aX, aY, aMaxWidth))
    3154               0 :       return NS_ERROR_DOM_SYNTAX_ERR;
    3155                 : 
    3156                 :   // spec isn't clear on what should happen if aMaxWidth <= 0, so
    3157                 :   // treat it as an invalid argument
    3158                 :   // technically, 0 should be an invalid value as well, but 0 is the default
    3159                 :   // arg, and there is no way to tell if the default was used
    3160               0 :   if (aMaxWidth < 0)
    3161               0 :     return NS_ERROR_INVALID_ARG;
    3162                 : 
    3163               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
    3164               0 :   if (!content && !mDocShell) {
    3165               0 :       NS_WARNING("Canvas element must be an nsIContent and non-null or a docshell must be provided");
    3166               0 :     return NS_ERROR_FAILURE;
    3167                 :   }
    3168                 : 
    3169               0 :   nsIPresShell* presShell = GetPresShell();
    3170               0 :   if (!presShell)
    3171               0 :       return NS_ERROR_FAILURE;
    3172                 : 
    3173               0 :   nsIDocument* document = presShell->GetDocument();
    3174                 : 
    3175                 :   // replace all the whitespace characters with U+0020 SPACE
    3176               0 :   nsAutoString textToDraw(aRawText);
    3177               0 :   TextReplaceWhitespaceCharacters(textToDraw);
    3178                 : 
    3179                 :   // for now, default to ltr if not in doc
    3180               0 :   bool isRTL = false;
    3181                 : 
    3182               0 :   if (content && content->IsInDoc()) {
    3183                 :     // try to find the closest context
    3184                 :     nsRefPtr<nsStyleContext> canvasStyle =
    3185               0 :       nsComputedDOMStyle::GetStyleContextForElement(content->AsElement(),
    3186                 :                                                     nsnull,
    3187               0 :                                                     presShell);
    3188               0 :     if (!canvasStyle) {
    3189               0 :       return NS_ERROR_FAILURE;
    3190                 :     }
    3191                 : 
    3192               0 :     isRTL = canvasStyle->GetStyleVisibility()->mDirection ==
    3193               0 :       NS_STYLE_DIRECTION_RTL;
    3194                 :   } else {
    3195               0 :     isRTL = GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) == IBMBIDI_TEXTDIRECTION_RTL;
    3196                 :   }
    3197                 : 
    3198               0 :   const ContextState &state = CurrentState();
    3199                 : 
    3200                 :   // This is only needed to know if we can know the drawing bounding box easily.
    3201               0 :   bool doDrawShadow = aOp == TEXT_DRAW_OPERATION_FILL && NeedToDrawShadow();
    3202                 : 
    3203               0 :   nsCanvasBidiProcessorAzure processor;
    3204                 : 
    3205               0 :   GetAppUnitsValues(&processor.mAppUnitsPerDevPixel, nsnull);
    3206               0 :   processor.mPt = gfxPoint(aX, aY);
    3207                 :   processor.mThebes =
    3208               0 :     new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
    3209               0 :   Matrix matrix = mTarget->GetTransform();
    3210               0 :   processor.mThebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21, matrix._22, matrix._31, matrix._32));
    3211               0 :   processor.mCtx = this;
    3212               0 :   processor.mOp = aOp;
    3213               0 :   processor.mBoundingBox = gfxRect(0, 0, 0, 0);
    3214               0 :   processor.mDoMeasureBoundingBox = doDrawShadow || !mIsEntireFrameInvalid;
    3215               0 :   processor.mState = &CurrentState();
    3216                 :     
    3217                 : 
    3218               0 :   processor.mFontgrp = GetCurrentFontStyle();
    3219               0 :   NS_ASSERTION(processor.mFontgrp, "font group is null");
    3220                 : 
    3221                 :   nscoord totalWidthCoord;
    3222                 : 
    3223                 :   // calls bidi algo twice since it needs the full text width and the
    3224                 :   // bounding boxes before rendering anything
    3225               0 :   nsBidi bidiEngine;
    3226                 :   rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
    3227               0 :                                 textToDraw.Length(),
    3228                 :                                 isRTL ? NSBIDI_RTL : NSBIDI_LTR,
    3229                 :                                 presShell->GetPresContext(),
    3230                 :                                 processor,
    3231                 :                                 nsBidiPresUtils::MODE_MEASURE,
    3232                 :                                 nsnull,
    3233                 :                                 0,
    3234                 :                                 &totalWidthCoord,
    3235               0 :                                 &bidiEngine);
    3236               0 :   if (NS_FAILED(rv)) {
    3237               0 :     return rv;
    3238                 :   }
    3239                 : 
    3240               0 :   float totalWidth = float(totalWidthCoord) / processor.mAppUnitsPerDevPixel;
    3241               0 :   if (aWidth) {
    3242               0 :     *aWidth = totalWidth;
    3243                 :   }
    3244                 : 
    3245                 :   // if only measuring, don't need to do any more work
    3246               0 :   if (aOp==TEXT_DRAW_OPERATION_MEASURE) {
    3247               0 :     return NS_OK;
    3248                 :   }
    3249                 : 
    3250                 :   // offset pt.x based on text align
    3251                 :   gfxFloat anchorX;
    3252                 : 
    3253               0 :   if (state.textAlign == TEXT_ALIGN_CENTER) {
    3254               0 :     anchorX = .5;
    3255               0 :   } else if (state.textAlign == TEXT_ALIGN_LEFT ||
    3256               0 :             (!isRTL && state.textAlign == TEXT_ALIGN_START) ||
    3257                 :             (isRTL && state.textAlign == TEXT_ALIGN_END)) {
    3258               0 :     anchorX = 0;
    3259                 :   } else {
    3260               0 :     anchorX = 1;
    3261                 :   }
    3262                 : 
    3263               0 :   processor.mPt.x -= anchorX * totalWidth;
    3264                 : 
    3265                 :   // offset pt.y based on text baseline
    3266               0 :   NS_ASSERTION(processor.mFontgrp->FontListLength()>0, "font group contains no fonts");
    3267               0 :   const gfxFont::Metrics& fontMetrics = processor.mFontgrp->GetFontAt(0)->GetMetrics();
    3268                 : 
    3269                 :   gfxFloat anchorY;
    3270                 : 
    3271               0 :   switch (state.textBaseline)
    3272                 :   {
    3273                 :   case TEXT_BASELINE_HANGING:
    3274                 :       // fall through; best we can do with the information available
    3275                 :   case TEXT_BASELINE_TOP:
    3276               0 :     anchorY = fontMetrics.emAscent;
    3277               0 :     break;
    3278                 :     break;
    3279                 :   case TEXT_BASELINE_MIDDLE:
    3280               0 :     anchorY = (fontMetrics.emAscent - fontMetrics.emDescent) * .5f;
    3281               0 :     break;
    3282                 :   case TEXT_BASELINE_IDEOGRAPHIC:
    3283                 :     // fall through; best we can do with the information available
    3284                 :   case TEXT_BASELINE_ALPHABETIC:
    3285               0 :     anchorY = 0;
    3286               0 :     break;
    3287                 :   case TEXT_BASELINE_BOTTOM:
    3288               0 :     anchorY = -fontMetrics.emDescent;
    3289               0 :     break;
    3290                 :   }
    3291                 : 
    3292               0 :   processor.mPt.y += anchorY;
    3293                 : 
    3294                 :   // correct bounding box to get it to be the correct size/position
    3295               0 :   processor.mBoundingBox.width = totalWidth;
    3296               0 :   processor.mBoundingBox.MoveBy(processor.mPt);
    3297                 : 
    3298               0 :   processor.mPt.x *= processor.mAppUnitsPerDevPixel;
    3299               0 :   processor.mPt.y *= processor.mAppUnitsPerDevPixel;
    3300                 : 
    3301               0 :   Matrix oldTransform = mTarget->GetTransform();
    3302                 :   // if text is over aMaxWidth, then scale the text horizontally such that its
    3303                 :   // width is precisely aMaxWidth
    3304               0 :   if (aMaxWidth > 0 && totalWidth > aMaxWidth) {
    3305               0 :     Matrix newTransform = oldTransform;
    3306                 : 
    3307                 :     // Translate so that the anchor point is at 0,0, then scale and then
    3308                 :     // translate back.
    3309               0 :     newTransform.Translate(aX, 0);
    3310               0 :     newTransform.Scale(aMaxWidth / totalWidth, 1);
    3311               0 :     newTransform.Translate(-aX, 0);
    3312                 :     /* we do this to avoid an ICE in the android compiler */
    3313               0 :     Matrix androidCompilerBug = newTransform;
    3314               0 :     mTarget->SetTransform(androidCompilerBug);
    3315                 :   }
    3316                 : 
    3317                 :   // save the previous bounding box
    3318               0 :   gfxRect boundingBox = processor.mBoundingBox;
    3319                 : 
    3320                 :   // don't ever need to measure the bounding box twice
    3321               0 :   processor.mDoMeasureBoundingBox = false;
    3322                 : 
    3323                 :   rv = nsBidiPresUtils::ProcessText(textToDraw.get(),
    3324               0 :                                     textToDraw.Length(),
    3325                 :                                     isRTL ? NSBIDI_RTL : NSBIDI_LTR,
    3326                 :                                     presShell->GetPresContext(),
    3327                 :                                     processor,
    3328                 :                                     nsBidiPresUtils::MODE_DRAW,
    3329                 :                                     nsnull,
    3330                 :                                     0,
    3331                 :                                     nsnull,
    3332               0 :                                     &bidiEngine);
    3333                 : 
    3334                 : 
    3335               0 :   mTarget->SetTransform(oldTransform);
    3336                 : 
    3337               0 :   if (aOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_FILL && !doDrawShadow)
    3338               0 :     return RedrawUser(boundingBox);
    3339                 : 
    3340               0 :   return Redraw();
    3341                 : }
    3342                 : 
    3343                 : NS_IMETHODIMP
    3344               0 : nsCanvasRenderingContext2DAzure::SetMozTextStyle(const nsAString& textStyle)
    3345                 : {
    3346                 :     // font and mozTextStyle are the same value
    3347               0 :     return SetFont(textStyle);
    3348                 : }
    3349                 : 
    3350                 : NS_IMETHODIMP
    3351               0 : nsCanvasRenderingContext2DAzure::GetMozTextStyle(nsAString& textStyle)
    3352                 : {
    3353                 :     // font and mozTextStyle are the same value
    3354               0 :     return GetFont(textStyle);
    3355                 : }
    3356                 : 
    3357               0 : gfxFontGroup *nsCanvasRenderingContext2DAzure::GetCurrentFontStyle()
    3358                 : {
    3359                 :   // use lazy initilization for the font group since it's rather expensive
    3360               0 :   if (!CurrentState().fontGroup) {
    3361               0 :     nsresult rv = SetFont(kDefaultFontStyle);
    3362               0 :     if (NS_FAILED(rv)) {
    3363               0 :       gfxFontStyle style;
    3364               0 :       style.size = kDefaultFontSize;
    3365               0 :       CurrentState().fontGroup =
    3366               0 :         gfxPlatform::GetPlatform()->CreateFontGroup(kDefaultFontName,
    3367                 :                                                     &style,
    3368               0 :                                                     nsnull);
    3369               0 :       if (CurrentState().fontGroup) {
    3370               0 :         CurrentState().font = kDefaultFontStyle;
    3371               0 :         rv = NS_OK;
    3372                 :       } else {
    3373               0 :         rv = NS_ERROR_OUT_OF_MEMORY;
    3374                 :       }
    3375                 :     }
    3376                 :             
    3377               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "Default canvas font is invalid");
    3378                 :   }
    3379                 : 
    3380               0 :   return CurrentState().fontGroup;
    3381                 : }
    3382                 : 
    3383                 : //
    3384                 : // line caps/joins
    3385                 : //
    3386                 : NS_IMETHODIMP
    3387               0 : nsCanvasRenderingContext2DAzure::SetLineWidth(float width)
    3388                 : {
    3389               0 :   if (!FloatValidate(width) || width <= 0.0) {
    3390               0 :     return NS_OK;
    3391                 :   }
    3392                 : 
    3393               0 :   CurrentState().lineWidth = width;
    3394               0 :   return NS_OK;
    3395                 : }
    3396                 : 
    3397                 : NS_IMETHODIMP
    3398               0 : nsCanvasRenderingContext2DAzure::GetLineWidth(float *width)
    3399                 : {
    3400               0 :   *width = CurrentState().lineWidth;
    3401               0 :   return NS_OK;
    3402                 : }
    3403                 : 
    3404                 : NS_IMETHODIMP
    3405               0 : nsCanvasRenderingContext2DAzure::SetLineCap(const nsAString& capstyle)
    3406                 : {
    3407                 :   CapStyle cap;
    3408                 : 
    3409               0 :   if (capstyle.EqualsLiteral("butt")) {
    3410               0 :     cap = CAP_BUTT;
    3411               0 :   } else if (capstyle.EqualsLiteral("round")) {
    3412               0 :     cap = CAP_ROUND;
    3413               0 :   } else if (capstyle.EqualsLiteral("square")) {
    3414               0 :     cap = CAP_SQUARE;
    3415                 :   } else {
    3416                 :     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
    3417               0 :     return NS_OK;
    3418                 :   }
    3419                 : 
    3420               0 :   CurrentState().lineCap = cap;
    3421                 : 
    3422               0 :   return NS_OK;
    3423                 : }
    3424                 : 
    3425                 : NS_IMETHODIMP
    3426               0 : nsCanvasRenderingContext2DAzure::GetLineCap(nsAString& capstyle)
    3427                 : {
    3428               0 :   switch (CurrentState().lineCap) {
    3429                 :   case CAP_BUTT:
    3430               0 :     capstyle.AssignLiteral("butt");
    3431               0 :     break;
    3432                 :   case CAP_ROUND:
    3433               0 :     capstyle.AssignLiteral("round");
    3434               0 :     break;
    3435                 :   case CAP_SQUARE:
    3436               0 :     capstyle.AssignLiteral("square");
    3437               0 :     break;
    3438                 :   }
    3439                 : 
    3440               0 :   return NS_OK;
    3441                 : }
    3442                 : 
    3443                 : NS_IMETHODIMP
    3444               0 : nsCanvasRenderingContext2DAzure::SetLineJoin(const nsAString& joinstyle)
    3445                 : {
    3446                 :   JoinStyle j;
    3447                 : 
    3448               0 :   if (joinstyle.EqualsLiteral("round")) {
    3449               0 :     j = JOIN_ROUND;
    3450               0 :   } else if (joinstyle.EqualsLiteral("bevel")) {
    3451               0 :     j = JOIN_BEVEL;
    3452               0 :   } else if (joinstyle.EqualsLiteral("miter")) {
    3453               0 :     j = JOIN_MITER_OR_BEVEL;
    3454                 :   } else {
    3455                 :     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
    3456               0 :     return NS_OK;
    3457                 :   }
    3458                 : 
    3459               0 :   CurrentState().lineJoin = j;
    3460                 :    
    3461               0 :   return NS_OK;
    3462                 : }
    3463                 : 
    3464                 : NS_IMETHODIMP
    3465               0 : nsCanvasRenderingContext2DAzure::GetLineJoin(nsAString& joinstyle)
    3466                 : {
    3467               0 :   switch (CurrentState().lineJoin) {
    3468                 :   case JOIN_ROUND:
    3469               0 :     joinstyle.AssignLiteral("round");
    3470               0 :     break;
    3471                 :   case JOIN_BEVEL:
    3472               0 :     joinstyle.AssignLiteral("bevel");
    3473               0 :     break;
    3474                 :   case JOIN_MITER_OR_BEVEL:
    3475               0 :     joinstyle.AssignLiteral("miter");
    3476               0 :     break;
    3477                 :   default:
    3478               0 :     return NS_ERROR_FAILURE;
    3479                 :   }
    3480                 : 
    3481               0 :   return NS_OK;
    3482                 : }
    3483                 : 
    3484                 : NS_IMETHODIMP
    3485               0 : nsCanvasRenderingContext2DAzure::SetMiterLimit(float miter)
    3486                 : {
    3487               0 :   if (!FloatValidate(miter) || miter <= 0.0)
    3488               0 :     return NS_OK;
    3489                 : 
    3490               0 :   CurrentState().miterLimit = miter;
    3491                 : 
    3492               0 :   return NS_OK;
    3493                 : }
    3494                 : 
    3495                 : NS_IMETHODIMP
    3496               0 : nsCanvasRenderingContext2DAzure::GetMiterLimit(float *miter)
    3497                 : {
    3498               0 :   *miter = CurrentState().miterLimit;
    3499               0 :   return NS_OK;
    3500                 : }
    3501                 : 
    3502                 : NS_IMETHODIMP
    3503               0 : nsCanvasRenderingContext2DAzure::SetMozDash(JSContext *cx, const jsval& patternArray)
    3504                 : {
    3505               0 :   FallibleTArray<Float> dash;
    3506               0 :   nsresult rv = JSValToDashArray(cx, patternArray, dash);
    3507               0 :   if (NS_SUCCEEDED(rv)) {
    3508               0 :     ContextState& state = CurrentState();
    3509               0 :     state.dash = dash;
    3510               0 :     if (state.dash.IsEmpty()) {
    3511               0 :       state.dashOffset = 0;
    3512                 :     }
    3513                 :   }
    3514               0 :   return rv;
    3515                 : }
    3516                 : 
    3517                 : NS_IMETHODIMP
    3518               0 : nsCanvasRenderingContext2DAzure::GetMozDash(JSContext* cx, jsval* dashArray)
    3519                 : {
    3520               0 :   return DashArrayToJSVal(CurrentState().dash, cx, dashArray);
    3521                 : }
    3522                 :  
    3523                 : NS_IMETHODIMP
    3524               0 : nsCanvasRenderingContext2DAzure::SetMozDashOffset(float offset)
    3525                 : {
    3526               0 :   if (!FloatValidate(offset)) {
    3527               0 :     return NS_ERROR_ILLEGAL_VALUE;
    3528                 :   }
    3529               0 :   ContextState& state = CurrentState();
    3530               0 :   if (!state.dash.IsEmpty()) {
    3531               0 :     state.dashOffset = offset;
    3532                 :   }
    3533               0 :   return NS_OK;
    3534                 : }
    3535                 :  
    3536                 : NS_IMETHODIMP
    3537               0 : nsCanvasRenderingContext2DAzure::GetMozDashOffset(float* offset)
    3538                 : {
    3539               0 :   *offset = CurrentState().dashOffset;
    3540               0 :   return NS_OK;
    3541                 : }
    3542                 : 
    3543                 : NS_IMETHODIMP
    3544               0 : nsCanvasRenderingContext2DAzure::IsPointInPath(float x, float y, bool *retVal)
    3545                 : {
    3546               0 :   if (!FloatValidate(x,y)) {
    3547               0 :     *retVal = false;
    3548               0 :     return NS_OK;
    3549                 :   }
    3550                 : 
    3551               0 :   EnsureUserSpacePath();
    3552                 : 
    3553               0 :   *retVal = false;
    3554                 : 
    3555               0 :   if (mPath) {
    3556               0 :     *retVal = mPath->ContainsPoint(Point(x, y), mTarget->GetTransform());
    3557                 :   }
    3558                 : 
    3559               0 :   return NS_OK;
    3560                 : }
    3561                 : 
    3562                 : //
    3563                 : // image
    3564                 : //
    3565                 : 
    3566                 : // drawImage(in HTMLImageElement image, in float dx, in float dy);
    3567                 : //   -- render image from 0,0 at dx,dy top-left coords
    3568                 : // drawImage(in HTMLImageElement image, in float dx, in float dy, in float sw, in float sh);
    3569                 : //   -- render image from 0,0 at dx,dy top-left coords clipping it to sw,sh
    3570                 : // drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
    3571                 : //   -- render the region defined by (sx,sy,sw,wh) in image-local space into the region (dx,dy,dw,dh) on the canvas
    3572                 : 
    3573                 : NS_IMETHODIMP
    3574               0 : nsCanvasRenderingContext2DAzure::DrawImage(nsIDOMElement *imgElt, float a1,
    3575                 :                                            float a2, float a3, float a4, float a5,
    3576                 :                                            float a6, float a7, float a8,
    3577                 :                                            PRUint8 optional_argc)
    3578                 : {
    3579               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(imgElt);
    3580               0 :   if (!content) {
    3581               0 :     return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
    3582                 :   }
    3583                 : 
    3584               0 :   if (optional_argc == 0) {
    3585               0 :     if (!FloatValidate(a1, a2)) {
    3586               0 :       return NS_OK;
    3587                 :     }
    3588               0 :   } else if (optional_argc == 2) {
    3589               0 :     if (!FloatValidate(a1, a2, a3, a4)) {
    3590               0 :       return NS_OK;
    3591                 :     }
    3592               0 :   } else if (optional_argc == 6) {
    3593               0 :     if (!FloatValidate(a1, a2, a3, a4, a5, a6) || !FloatValidate(a7, a8)) {
    3594               0 :       return NS_OK;
    3595                 :     }
    3596                 :   }
    3597                 : 
    3598                 :   double sx,sy,sw,sh;
    3599                 :   double dx,dy,dw,dh;
    3600                 : 
    3601               0 :   RefPtr<SourceSurface> srcSurf;
    3602               0 :   gfxIntSize imgSize;
    3603                 : 
    3604               0 :   nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content);
    3605               0 :   if (canvas) {
    3606               0 :     nsIntSize size = canvas->GetSize();
    3607               0 :     if (size.width == 0 || size.height == 0) {
    3608               0 :       return NS_ERROR_DOM_INVALID_STATE_ERR;
    3609                 :     }
    3610                 : 
    3611                 :     // Special case for Canvas, which could be an Azure canvas!
    3612               0 :     nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
    3613               0 :     if (srcCanvas == this) {
    3614                 :       // Self-copy.
    3615               0 :       srcSurf = mTarget->Snapshot();
    3616               0 :       imgSize = gfxIntSize(mWidth, mHeight);
    3617               0 :     } else if (srcCanvas) {
    3618                 :       // This might not be an Azure canvas!
    3619               0 :       srcSurf = srcCanvas->GetSurfaceSnapshot();
    3620                 : 
    3621               0 :       if (srcSurf && mCanvasElement) {
    3622                 :         // Do security check here.
    3623                 :         CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(),
    3624               0 :                                               content->NodePrincipal(), canvas->IsWriteOnly(),
    3625               0 :                                               false);
    3626               0 :         imgSize = gfxIntSize(srcSurf->GetSize().width, srcSurf->GetSize().height);
    3627                 :       }
    3628                 :     }
    3629                 :   } else {
    3630                 :     gfxASurface* imgsurf =
    3631               0 :       CanvasImageCache::Lookup(imgElt, HTMLCanvasElement(), &imgSize);
    3632               0 :     if (imgsurf) {
    3633               0 :       srcSurf = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, imgsurf);
    3634                 :     }
    3635                 :   }
    3636                 : 
    3637               0 :   if (!srcSurf) {
    3638                 :     // The canvas spec says that drawImage should draw the first frame
    3639                 :     // of animated images
    3640               0 :     PRUint32 sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME;
    3641                 :     nsLayoutUtils::SurfaceFromElementResult res =
    3642               0 :       nsLayoutUtils::SurfaceFromElement(content->AsElement(), sfeFlags);
    3643                 : 
    3644               0 :     if (!res.mSurface) {
    3645                 :       // Spec says to silently do nothing if the element is still loading.
    3646               0 :       return res.mIsStillLoading ? NS_OK : NS_ERROR_NOT_AVAILABLE;
    3647                 :     }
    3648                 : 
    3649                 :     // Ignore cairo surfaces that are bad! See bug 666312.
    3650               0 :     if (res.mSurface->CairoStatus()) {
    3651               0 :       return NS_OK;
    3652                 :     }
    3653                 : 
    3654               0 :     imgSize = res.mSize;
    3655                 : 
    3656               0 :     if (mCanvasElement) {
    3657                 :       CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(),
    3658                 :                                             res.mPrincipal, res.mIsWriteOnly,
    3659               0 :                                             res.mCORSUsed);
    3660                 :     }
    3661                 : 
    3662               0 :     if (res.mImageRequest) {
    3663                 :       CanvasImageCache::NotifyDrawImage(imgElt, HTMLCanvasElement(),
    3664               0 :                                         res.mImageRequest, res.mSurface, imgSize);
    3665                 :     }
    3666                 : 
    3667               0 :     srcSurf = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface);
    3668                 :   }
    3669                 : 
    3670               0 :   if (optional_argc == 0) {
    3671               0 :     dx = a1;
    3672               0 :     dy = a2;
    3673               0 :     sx = sy = 0.0;
    3674               0 :     dw = sw = (double) imgSize.width;
    3675               0 :     dh = sh = (double) imgSize.height;
    3676               0 :   } else if (optional_argc == 2) {
    3677               0 :     dx = a1;
    3678               0 :     dy = a2;
    3679               0 :     dw = a3;
    3680               0 :     dh = a4;
    3681               0 :     sx = sy = 0.0;
    3682               0 :     sw = (double) imgSize.width;
    3683               0 :     sh = (double) imgSize.height;
    3684               0 :   } else if (optional_argc == 6) {
    3685               0 :     sx = a1;
    3686               0 :     sy = a2;
    3687               0 :     sw = a3;
    3688               0 :     sh = a4;
    3689               0 :     dx = a5;
    3690               0 :     dy = a6;
    3691               0 :     dw = a7;
    3692               0 :     dh = a8;
    3693                 :   } else {
    3694                 :     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
    3695               0 :     return NS_ERROR_INVALID_ARG;
    3696                 :   }
    3697                 : 
    3698               0 :   if (dw == 0.0 || dh == 0.0) {
    3699                 :     // not really failure, but nothing to do --
    3700                 :     // and noone likes a divide-by-zero
    3701               0 :     return NS_OK;
    3702                 :   }
    3703                 : 
    3704               0 :   if (sx < 0.0 || sy < 0.0 ||
    3705                 :       sw < 0.0 || sw > (double) imgSize.width ||
    3706                 :       sh < 0.0 || sh > (double) imgSize.height ||
    3707                 :       dw < 0.0 || dh < 0.0) {
    3708                 :     // XXX - Unresolved spec issues here, for now return error.
    3709               0 :     return NS_ERROR_DOM_INDEX_SIZE_ERR;
    3710                 :   }
    3711                 : 
    3712                 :   Filter filter;
    3713                 : 
    3714               0 :   if (CurrentState().imageSmoothingEnabled)
    3715               0 :     filter = mgfx::FILTER_LINEAR;
    3716                 :   else
    3717               0 :     filter = mgfx::FILTER_POINT;
    3718                 : 
    3719               0 :   mgfx::Rect bounds;
    3720                 :   
    3721               0 :   if (NeedToDrawShadow()) {
    3722               0 :     bounds = mgfx::Rect(dx, dy, dw, dh);
    3723               0 :     bounds = mTarget->GetTransform().TransformBounds(bounds);
    3724                 :   }
    3725                 : 
    3726               0 :   AdjustedTarget(this, bounds.IsEmpty() ? nsnull : &bounds)->
    3727                 :     DrawSurface(srcSurf,
    3728                 :                 mgfx::Rect(dx, dy, dw, dh),
    3729                 :                 mgfx::Rect(sx, sy, sw, sh),
    3730                 :                 DrawSurfaceOptions(filter),
    3731               0 :                 DrawOptions(CurrentState().globalAlpha, UsedOperation()));
    3732                 : 
    3733               0 :   return RedrawUser(gfxRect(dx, dy, dw, dh));
    3734                 : }
    3735                 : 
    3736                 : NS_IMETHODIMP
    3737               0 : nsCanvasRenderingContext2DAzure::SetGlobalCompositeOperation(const nsAString& op)
    3738                 : {
    3739                 :   CompositionOp comp_op;
    3740                 : 
    3741                 : #define CANVAS_OP_TO_GFX_OP(cvsop, op2d) \
    3742                 :   if (op.EqualsLiteral(cvsop))   \
    3743                 :     comp_op = OP_##op2d;
    3744                 : 
    3745               0 :   CANVAS_OP_TO_GFX_OP("copy", SOURCE)
    3746               0 :   else CANVAS_OP_TO_GFX_OP("source-atop", ATOP)
    3747               0 :   else CANVAS_OP_TO_GFX_OP("source-in", IN)
    3748               0 :   else CANVAS_OP_TO_GFX_OP("source-out", OUT)
    3749               0 :   else CANVAS_OP_TO_GFX_OP("source-over", OVER)
    3750               0 :   else CANVAS_OP_TO_GFX_OP("destination-in", DEST_IN)
    3751               0 :   else CANVAS_OP_TO_GFX_OP("destination-out", DEST_OUT)
    3752               0 :   else CANVAS_OP_TO_GFX_OP("destination-over", DEST_OVER)
    3753               0 :   else CANVAS_OP_TO_GFX_OP("destination-atop", DEST_ATOP)
    3754               0 :   else CANVAS_OP_TO_GFX_OP("lighter", ADD)
    3755               0 :   else CANVAS_OP_TO_GFX_OP("xor", XOR)
    3756                 :   // XXX ERRMSG we need to report an error to developers here! (bug 329026)
    3757               0 :   else return NS_OK;
    3758                 : 
    3759                 : #undef CANVAS_OP_TO_GFX_OP
    3760               0 :   CurrentState().op = comp_op;
    3761               0 :   return NS_OK;
    3762                 : }
    3763                 : 
    3764                 : NS_IMETHODIMP
    3765               0 : nsCanvasRenderingContext2DAzure::GetGlobalCompositeOperation(nsAString& op)
    3766                 : {
    3767               0 :   CompositionOp comp_op = CurrentState().op;
    3768                 : 
    3769                 : #define CANVAS_OP_TO_GFX_OP(cvsop, op2d) \
    3770                 :   if (comp_op == OP_##op2d) \
    3771                 :     op.AssignLiteral(cvsop);
    3772                 : 
    3773               0 :   CANVAS_OP_TO_GFX_OP("copy", SOURCE)
    3774               0 :   else CANVAS_OP_TO_GFX_OP("destination-atop", DEST_ATOP)
    3775               0 :   else CANVAS_OP_TO_GFX_OP("destination-in", DEST_IN)
    3776               0 :   else CANVAS_OP_TO_GFX_OP("destination-out", DEST_OUT)
    3777               0 :   else CANVAS_OP_TO_GFX_OP("destination-over", DEST_OVER)
    3778               0 :   else CANVAS_OP_TO_GFX_OP("lighter", ADD)
    3779               0 :   else CANVAS_OP_TO_GFX_OP("source-atop", ATOP)
    3780               0 :   else CANVAS_OP_TO_GFX_OP("source-in", IN)
    3781               0 :   else CANVAS_OP_TO_GFX_OP("source-out", OUT)
    3782               0 :   else CANVAS_OP_TO_GFX_OP("source-over", OVER)
    3783               0 :   else CANVAS_OP_TO_GFX_OP("xor", XOR)
    3784               0 :   else return NS_ERROR_FAILURE;
    3785                 : 
    3786                 : #undef CANVAS_OP_TO_GFX_OP
    3787                 :     
    3788               0 :   return NS_OK;
    3789                 : }
    3790                 : 
    3791                 : NS_IMETHODIMP
    3792               0 : nsCanvasRenderingContext2DAzure::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY,
    3793                 :                                             float aW, float aH,
    3794                 :                                             const nsAString& aBGColor,
    3795                 :                                             PRUint32 flags)
    3796                 : {
    3797               0 :   NS_ENSURE_ARG(aWindow != nsnull);
    3798                 : 
    3799                 :   // protect against too-large surfaces that will cause allocation
    3800                 :   // or overflow issues
    3801               0 :   if (!gfxASurface::CheckSurfaceSize(gfxIntSize(PRInt32(aW), PRInt32(aH)),
    3802               0 :                                       0xffff))
    3803               0 :     return NS_ERROR_FAILURE;
    3804                 : 
    3805               0 :   nsRefPtr<gfxASurface> drawSurf;
    3806               0 :   GetThebesSurface(getter_AddRefs(drawSurf));
    3807                 : 
    3808               0 :   nsRefPtr<gfxContext> thebes = new gfxContext(drawSurf);
    3809                 : 
    3810               0 :   Matrix matrix = mTarget->GetTransform();
    3811                 :   thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
    3812               0 :                               matrix._22, matrix._31, matrix._32));
    3813                 : 
    3814                 :   // We can't allow web apps to call this until we fix at least the
    3815                 :   // following potential security issues:
    3816                 :   // -- rendering cross-domain IFRAMEs and then extracting the results
    3817                 :   // -- rendering the user's theme and then extracting the results
    3818                 :   // -- rendering native anonymous content (e.g., file input paths;
    3819                 :   // scrollbars should be allowed)
    3820               0 :   if (!nsContentUtils::IsCallerTrustedForRead()) {
    3821                 :     // not permitted to use DrawWindow
    3822                 :     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
    3823               0 :     return NS_ERROR_DOM_SECURITY_ERR;
    3824                 :   }
    3825                 : 
    3826                 :   // Flush layout updates
    3827               0 :   if (!(flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH))
    3828               0 :       nsContentUtils::FlushLayoutForTree(aWindow);
    3829                 : 
    3830               0 :   nsRefPtr<nsPresContext> presContext;
    3831               0 :   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aWindow);
    3832               0 :   if (win) {
    3833               0 :     nsIDocShell* docshell = win->GetDocShell();
    3834               0 :     if (docshell) {
    3835               0 :       docshell->GetPresContext(getter_AddRefs(presContext));
    3836                 :     }
    3837                 :   }
    3838               0 :   if (!presContext)
    3839               0 :     return NS_ERROR_FAILURE;
    3840                 : 
    3841                 :   nscolor bgColor;
    3842                 : 
    3843                 :   nsIDocument* elementDoc = mCanvasElement ?
    3844               0 :                             HTMLCanvasElement()->OwnerDoc() : nsnull;
    3845                 : 
    3846                 :   // Pass the CSS Loader object to the parser, to allow parser error reports
    3847                 :   // to include the outer window ID.
    3848               0 :   nsCSSParser parser(elementDoc ? elementDoc->CSSLoader() : nsnull);
    3849               0 :   nsresult rv = parser.ParseColorString(PromiseFlatString(aBGColor),
    3850               0 :                                         nsnull, 0, &bgColor);
    3851               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3852                 : 
    3853               0 :   nsIPresShell* presShell = presContext->PresShell();
    3854               0 :   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
    3855                 : 
    3856                 :   nsRect r(nsPresContext::CSSPixelsToAppUnits(aX),
    3857                 :            nsPresContext::CSSPixelsToAppUnits(aY),
    3858                 :            nsPresContext::CSSPixelsToAppUnits(aW),
    3859               0 :            nsPresContext::CSSPixelsToAppUnits(aH));
    3860                 :   PRUint32 renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
    3861               0 :                              nsIPresShell::RENDER_DOCUMENT_RELATIVE);
    3862               0 :   if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_CARET) {
    3863               0 :     renderDocFlags |= nsIPresShell::RENDER_CARET;
    3864                 :   }
    3865               0 :   if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_VIEW) {
    3866                 :     renderDocFlags &= ~(nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
    3867               0 :                         nsIPresShell::RENDER_DOCUMENT_RELATIVE);
    3868                 :   }
    3869               0 :   if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_USE_WIDGET_LAYERS) {
    3870               0 :     renderDocFlags |= nsIPresShell::RENDER_USE_WIDGET_LAYERS;
    3871                 :   }
    3872               0 :   if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_ASYNC_DECODE_IMAGES) {
    3873               0 :     renderDocFlags |= nsIPresShell::RENDER_ASYNC_DECODE_IMAGES;
    3874                 :   }
    3875                 : 
    3876               0 :   rv = presShell->RenderDocument(r, renderDocFlags, bgColor, thebes);
    3877                 : 
    3878                 :   // note that aX and aY are coordinates in the document that
    3879                 :   // we're drawing; aX and aY are drawn to 0,0 in current user
    3880                 :   // space.
    3881               0 :   RedrawUser(gfxRect(0, 0, aW, aH));
    3882                 : 
    3883               0 :   return NS_OK;
    3884                 : }
    3885                 : 
    3886                 : NS_IMETHODIMP
    3887               0 : nsCanvasRenderingContext2DAzure::AsyncDrawXULElement(nsIDOMXULElement* aElem,
    3888                 :                                                      float aX, float aY,
    3889                 :                                                      float aW, float aH,
    3890                 :                                                      const nsAString& aBGColor,
    3891                 :                                                      PRUint32 flags)
    3892                 : {
    3893               0 :     NS_ENSURE_ARG(aElem != nsnull);
    3894                 : 
    3895                 :     // We can't allow web apps to call this until we fix at least the
    3896                 :     // following potential security issues:
    3897                 :     // -- rendering cross-domain IFRAMEs and then extracting the results
    3898                 :     // -- rendering the user's theme and then extracting the results
    3899                 :     // -- rendering native anonymous content (e.g., file input paths;
    3900                 :     // scrollbars should be allowed)
    3901               0 :     if (!nsContentUtils::IsCallerTrustedForRead()) {
    3902                 :         // not permitted to use DrawWindow
    3903                 :         // XXX ERRMSG we need to report an error to developers here! (bug 329026)
    3904               0 :         return NS_ERROR_DOM_SECURITY_ERR;
    3905                 :     }
    3906                 : 
    3907                 : #if 0
    3908                 :     nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aElem);
    3909                 :     if (!loaderOwner)
    3910                 :         return NS_ERROR_FAILURE;
    3911                 : 
    3912                 :     nsRefPtr<nsFrameLoader> frameloader = loaderOwner->GetFrameLoader();
    3913                 :     if (!frameloader)
    3914                 :         return NS_ERROR_FAILURE;
    3915                 : 
    3916                 :     PBrowserParent *child = frameloader->GetRemoteBrowser();
    3917                 :     if (!child) {
    3918                 :         nsCOMPtr<nsIDOMWindow> window =
    3919                 :             do_GetInterface(frameloader->GetExistingDocShell());
    3920                 :         if (!window)
    3921                 :             return NS_ERROR_FAILURE;
    3922                 : 
    3923                 :         return DrawWindow(window, aX, aY, aW, aH, aBGColor, flags);
    3924                 :     }
    3925                 : 
    3926                 :     // protect against too-large surfaces that will cause allocation
    3927                 :     // or overflow issues
    3928                 :     if (!gfxASurface::CheckSurfaceSize(gfxIntSize(aW, aH), 0xffff))
    3929                 :         return NS_ERROR_FAILURE;
    3930                 : 
    3931                 :     bool flush =
    3932                 :         (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH) == 0;
    3933                 : 
    3934                 :     PRUint32 renderDocFlags = nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
    3935                 :     if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_CARET) {
    3936                 :         renderDocFlags |= nsIPresShell::RENDER_CARET;
    3937                 :     }
    3938                 :     if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_VIEW) {
    3939                 :         renderDocFlags &= ~nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
    3940                 :     }
    3941                 : 
    3942                 :     nsRect rect(nsPresContext::CSSPixelsToAppUnits(aX),
    3943                 :                 nsPresContext::CSSPixelsToAppUnits(aY),
    3944                 :                 nsPresContext::CSSPixelsToAppUnits(aW),
    3945                 :                 nsPresContext::CSSPixelsToAppUnits(aH));
    3946                 :     if (mIPC) {
    3947                 :         PDocumentRendererParent *pdocrender =
    3948                 :             child->SendPDocumentRendererConstructor(rect,
    3949                 :                                                     mThebes->CurrentMatrix(),
    3950                 :                                                     nsString(aBGColor),
    3951                 :                                                     renderDocFlags, flush,
    3952                 :                                                     nsIntSize(mWidth, mHeight));
    3953                 :         if (!pdocrender)
    3954                 :             return NS_ERROR_FAILURE;
    3955                 : 
    3956                 :         DocumentRendererParent *docrender =
    3957                 :             static_cast<DocumentRendererParent *>(pdocrender);
    3958                 : 
    3959                 :         docrender->SetCanvasContext(this, mThebes);
    3960                 :     }
    3961                 : #endif
    3962               0 :     return NS_OK;
    3963                 : }
    3964                 : 
    3965                 : //
    3966                 : // device pixel getting/setting
    3967                 : //
    3968                 : 
    3969                 : void
    3970               0 : nsCanvasRenderingContext2DAzure::EnsureUnpremultiplyTable() {
    3971               0 :   if (sUnpremultiplyTable)
    3972               0 :     return;
    3973                 : 
    3974                 :   // Infallably alloc the unpremultiply table.
    3975               0 :   sUnpremultiplyTable = new PRUint8[256][256];
    3976                 : 
    3977                 :   // It's important that the array be indexed first by alpha and then by rgb
    3978                 :   // value.  When we unpremultiply a pixel, we're guaranteed to do three
    3979                 :   // lookups with the same alpha; indexing by alpha first makes it likely that
    3980                 :   // those three lookups will be close to one another in memory, thus
    3981                 :   // increasing the chance of a cache hit.
    3982                 : 
    3983                 :   // a == 0 case
    3984               0 :   for (PRUint32 c = 0; c <= 255; c++) {
    3985               0 :     sUnpremultiplyTable[0][c] = c;
    3986                 :   }
    3987                 : 
    3988               0 :   for (int a = 1; a <= 255; a++) {
    3989               0 :     for (int c = 0; c <= 255; c++) {
    3990               0 :       sUnpremultiplyTable[a][c] = (PRUint8)((c * 255) / a);
    3991                 :     }
    3992                 :   }
    3993                 : }
    3994                 : 
    3995                 : 
    3996                 : NS_IMETHODIMP
    3997               0 : nsCanvasRenderingContext2DAzure::GetImageData()
    3998                 : {
    3999                 :   /* Should never be called -- GetImageData_explicit is the QS entry point */
    4000               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4001                 : }
    4002                 : 
    4003                 : NS_IMETHODIMP
    4004               0 : nsCanvasRenderingContext2DAzure::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h,
    4005                 :                                                        PRUint8 *aData, PRUint32 aDataLen)
    4006                 : {
    4007               0 :   if (!mValid)
    4008               0 :     return NS_ERROR_FAILURE;
    4009                 : 
    4010               0 :   if (!mCanvasElement && !mDocShell) {
    4011               0 :     NS_ERROR("No canvas element and no docshell in GetImageData!!!");
    4012               0 :     return NS_ERROR_DOM_SECURITY_ERR;
    4013                 :   }
    4014                 : 
    4015                 :   // Check only if we have a canvas element; if we were created with a docshell,
    4016                 :   // then it's special internal use.
    4017               0 :   if (mCanvasElement &&
    4018               0 :       HTMLCanvasElement()->IsWriteOnly() &&
    4019               0 :       !nsContentUtils::IsCallerTrustedForRead())
    4020                 :   {
    4021                 :     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
    4022               0 :     return NS_ERROR_DOM_SECURITY_ERR;
    4023                 :   }
    4024                 : 
    4025               0 :   if (w == 0 || h == 0 || aDataLen != w * h * 4)
    4026               0 :     return NS_ERROR_DOM_SYNTAX_ERR;
    4027                 : 
    4028               0 :   CheckedInt32 rightMost = CheckedInt32(x) + w;
    4029               0 :   CheckedInt32 bottomMost = CheckedInt32(y) + h;
    4030                 : 
    4031               0 :   if (!rightMost.valid() || !bottomMost.valid())
    4032               0 :     return NS_ERROR_DOM_SYNTAX_ERR;
    4033                 : 
    4034               0 :   if (mZero) {
    4035               0 :     return NS_OK;
    4036                 :   }
    4037                 : 
    4038               0 :   IntRect srcRect(0, 0, mWidth, mHeight);
    4039               0 :   IntRect destRect(x, y, w, h);
    4040                 : 
    4041               0 :   if (!srcRect.Contains(destRect)) {
    4042                 :     // Some data is outside the canvas surface, clear the destination.
    4043               0 :     memset(aData, 0, aDataLen);
    4044                 :   }
    4045                 : 
    4046               0 :   IntRect srcReadRect = srcRect.Intersect(destRect);
    4047               0 :   IntRect dstWriteRect = srcReadRect;
    4048               0 :   dstWriteRect.MoveBy(-x, -y);
    4049                 : 
    4050               0 :   PRUint8 *src = aData;
    4051               0 :   PRUint32 srcStride = w * 4;
    4052                 :   
    4053               0 :   RefPtr<DataSourceSurface> readback;
    4054               0 :   if (!srcReadRect.IsEmpty()) {
    4055               0 :     RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
    4056                 : 
    4057               0 :     readback = snapshot->GetDataSurface();
    4058                 : 
    4059               0 :     srcStride = readback->Stride();
    4060               0 :     src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4;
    4061                 :   }
    4062                 : 
    4063                 :   // make sure sUnpremultiplyTable has been created
    4064               0 :   EnsureUnpremultiplyTable();
    4065                 : 
    4066                 :   // NOTE! dst is the same as src, and this relies on reading
    4067                 :   // from src and advancing that ptr before writing to dst.
    4068               0 :   PRUint8 *dst = aData + dstWriteRect.y * (w * 4) + dstWriteRect.x * 4;
    4069                 : 
    4070               0 :   for (int j = 0; j < dstWriteRect.height; j++) {
    4071               0 :     for (int i = 0; i < dstWriteRect.width; i++) {
    4072                 :       // XXX Is there some useful swizzle MMX we can use here?
    4073                 : #ifdef IS_LITTLE_ENDIAN
    4074               0 :       PRUint8 b = *src++;
    4075               0 :       PRUint8 g = *src++;
    4076               0 :       PRUint8 r = *src++;
    4077               0 :       PRUint8 a = *src++;
    4078                 : #else
    4079                 :       PRUint8 a = *src++;
    4080                 :       PRUint8 r = *src++;
    4081                 :       PRUint8 g = *src++;
    4082                 :       PRUint8 b = *src++;
    4083                 : #endif
    4084                 :       // Convert to non-premultiplied color
    4085               0 :       *dst++ = sUnpremultiplyTable[a][r];
    4086               0 :       *dst++ = sUnpremultiplyTable[a][g];
    4087               0 :       *dst++ = sUnpremultiplyTable[a][b];
    4088               0 :       *dst++ = a;
    4089                 :     }
    4090               0 :     src += srcStride - (dstWriteRect.width * 4);
    4091               0 :     dst += (w * 4) - (dstWriteRect.width * 4);
    4092                 :   }
    4093               0 :   return NS_OK;
    4094                 : }
    4095                 : 
    4096                 : void
    4097               0 : nsCanvasRenderingContext2DAzure::EnsurePremultiplyTable() {
    4098               0 :   if (sPremultiplyTable)
    4099               0 :     return;
    4100                 : 
    4101                 :   // Infallably alloc the premultiply table.
    4102               0 :   sPremultiplyTable = new PRUint8[256][256];
    4103                 : 
    4104                 :   // Like the unpremultiply table, it's important that we index the premultiply
    4105                 :   // table with the alpha value as the first index to ensure good cache
    4106                 :   // performance.
    4107                 : 
    4108               0 :   for (int a = 0; a <= 255; a++) {
    4109               0 :     for (int c = 0; c <= 255; c++) {
    4110               0 :       sPremultiplyTable[a][c] = (a * c + 254) / 255;
    4111                 :     }
    4112                 :   }
    4113                 : }
    4114                 : 
    4115                 : void
    4116               0 : nsCanvasRenderingContext2DAzure::FillRuleChanged()
    4117                 : {
    4118               0 :   if (mPath) {
    4119               0 :     mPathBuilder = mPath->CopyToBuilder(CurrentState().fillRule);
    4120               0 :     mPath = nsnull;
    4121                 :   }
    4122               0 : }
    4123                 : 
    4124                 : // void putImageData (in ImageData d, in float x, in float y);
    4125                 : NS_IMETHODIMP
    4126               0 : nsCanvasRenderingContext2DAzure::PutImageData()
    4127                 : {
    4128                 :   /* Should never be called -- PutImageData_explicit is the QS entry point */
    4129               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4130                 : }
    4131                 : 
    4132                 : NS_IMETHODIMP
    4133               0 : nsCanvasRenderingContext2DAzure::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h,
    4134                 :                                                        unsigned char *aData, PRUint32 aDataLen,
    4135                 :                                                        bool hasDirtyRect, PRInt32 dirtyX, PRInt32 dirtyY,
    4136                 :                                                        PRInt32 dirtyWidth, PRInt32 dirtyHeight)
    4137                 : {
    4138               0 :   if (!mValid) {
    4139               0 :     return NS_ERROR_FAILURE;
    4140                 :   }
    4141                 : 
    4142               0 :   if (w == 0 || h == 0) {
    4143               0 :     return NS_ERROR_DOM_SYNTAX_ERR;
    4144                 :   }
    4145                 : 
    4146               0 :   IntRect dirtyRect;
    4147               0 :   IntRect imageDataRect(0, 0, w, h);
    4148                 : 
    4149               0 :   if (hasDirtyRect) {
    4150                 :     // fix up negative dimensions
    4151               0 :     if (dirtyWidth < 0) {
    4152               0 :       NS_ENSURE_TRUE(dirtyWidth != INT_MIN, NS_ERROR_DOM_INDEX_SIZE_ERR);
    4153                 : 
    4154               0 :       CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth;
    4155                 : 
    4156               0 :       if (!checkedDirtyX.valid())
    4157               0 :           return NS_ERROR_DOM_INDEX_SIZE_ERR;
    4158                 : 
    4159               0 :       dirtyX = checkedDirtyX.value();
    4160               0 :       dirtyWidth = -(int32)dirtyWidth;
    4161                 :     }
    4162                 : 
    4163               0 :     if (dirtyHeight < 0) {
    4164               0 :       NS_ENSURE_TRUE(dirtyHeight != INT_MIN, NS_ERROR_DOM_INDEX_SIZE_ERR);
    4165                 : 
    4166               0 :       CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight;
    4167                 : 
    4168               0 :       if (!checkedDirtyY.valid())
    4169               0 :           return NS_ERROR_DOM_INDEX_SIZE_ERR;
    4170                 : 
    4171               0 :       dirtyY = checkedDirtyY.value();
    4172               0 :       dirtyHeight = -(int32)dirtyHeight;
    4173                 :     }
    4174                 : 
    4175                 :     // bound the dirty rect within the imageData rectangle
    4176               0 :     dirtyRect = imageDataRect.Intersect(IntRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight));
    4177                 : 
    4178               0 :     if (dirtyRect.Width() <= 0 || dirtyRect.Height() <= 0)
    4179               0 :         return NS_OK;
    4180                 :   } else {
    4181               0 :     dirtyRect = imageDataRect;
    4182                 :   }
    4183                 : 
    4184               0 :   dirtyRect.MoveBy(IntPoint(x, y));
    4185               0 :   dirtyRect = IntRect(0, 0, mWidth, mHeight).Intersect(dirtyRect);
    4186                 : 
    4187               0 :   if (dirtyRect.Width() <= 0 || dirtyRect.Height() <= 0) {
    4188               0 :     return NS_OK;
    4189                 :   }
    4190                 : 
    4191               0 :   PRUint32 len = w * h * 4;
    4192               0 :   if (aDataLen != len) {
    4193               0 :     return NS_ERROR_DOM_SYNTAX_ERR;
    4194                 :   }
    4195                 : 
    4196                 :   nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(gfxIntSize(w, h),
    4197               0 :                                                           gfxASurface::ImageFormatARGB32);
    4198               0 :   if (!imgsurf || imgsurf->CairoStatus()) {
    4199               0 :     return NS_ERROR_FAILURE;
    4200                 :   }
    4201                 : 
    4202                 :   // ensure premultiply table has been created
    4203               0 :   EnsurePremultiplyTable();
    4204                 : 
    4205               0 :   PRUint8 *src = aData;
    4206               0 :   PRUint8 *dst = imgsurf->Data();
    4207                 : 
    4208               0 :   for (PRUint32 j = 0; j < h; j++) {
    4209               0 :     for (PRUint32 i = 0; i < w; i++) {
    4210               0 :       PRUint8 r = *src++;
    4211               0 :       PRUint8 g = *src++;
    4212               0 :       PRUint8 b = *src++;
    4213               0 :       PRUint8 a = *src++;
    4214                 : 
    4215                 :       // Convert to premultiplied color (losslessly if the input came from getImageData)
    4216                 : #ifdef IS_LITTLE_ENDIAN
    4217               0 :       *dst++ = sPremultiplyTable[a][b];
    4218               0 :       *dst++ = sPremultiplyTable[a][g];
    4219               0 :       *dst++ = sPremultiplyTable[a][r];
    4220               0 :       *dst++ = a;
    4221                 : #else
    4222                 :       *dst++ = a;
    4223                 :       *dst++ = sPremultiplyTable[a][r];
    4224                 :       *dst++ = sPremultiplyTable[a][g];
    4225                 :       *dst++ = sPremultiplyTable[a][b];
    4226                 : #endif
    4227                 :     }
    4228                 :   }
    4229                 : 
    4230                 :   RefPtr<SourceSurface> sourceSurface =
    4231               0 :     mTarget->CreateSourceSurfaceFromData(imgsurf->Data(), IntSize(w, h), imgsurf->Stride(), FORMAT_B8G8R8A8);
    4232                 : 
    4233                 : 
    4234               0 :   mTarget->CopySurface(sourceSurface,
    4235                 :                        IntRect(dirtyRect.x - x, dirtyRect.y - y,
    4236                 :                                dirtyRect.width, dirtyRect.height),
    4237               0 :                        IntPoint(dirtyRect.x, dirtyRect.y));
    4238                 : 
    4239               0 :   Redraw(mgfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
    4240                 : 
    4241               0 :   return NS_OK;
    4242                 : }
    4243                 : 
    4244                 : NS_IMETHODIMP
    4245               0 : nsCanvasRenderingContext2DAzure::GetThebesSurface(gfxASurface **surface)
    4246                 : {
    4247               0 :   if (!mTarget) {
    4248                 :     nsRefPtr<gfxASurface> tmpSurf =
    4249               0 :       gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR_ALPHA);
    4250               0 :     *surface = tmpSurf.forget().get();
    4251               0 :     return NS_OK;
    4252                 :   }
    4253                 : 
    4254               0 :   if (!mThebesSurface) {
    4255                 :     mThebesSurface =
    4256               0 :       gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);    
    4257                 : 
    4258               0 :     if (!mThebesSurface) {
    4259               0 :       return NS_ERROR_FAILURE;
    4260                 :     }
    4261                 :   } else {
    4262                 :     // Normally GetThebesSurfaceForDrawTarget will handle the flush, when
    4263                 :     // we're returning a cached ThebesSurface we need to flush here.
    4264               0 :     mTarget->Flush();
    4265                 :   }
    4266                 : 
    4267               0 :   *surface = mThebesSurface;
    4268               0 :   NS_ADDREF(*surface);
    4269                 : 
    4270               0 :   return NS_OK;
    4271                 : }
    4272                 : 
    4273                 : NS_IMETHODIMP
    4274               0 : nsCanvasRenderingContext2DAzure::CreateImageData()
    4275                 : {
    4276                 :   /* Should never be called; handled entirely in the quickstub */
    4277               0 :   return NS_ERROR_NOT_IMPLEMENTED;
    4278                 : }
    4279                 : 
    4280                 : NS_IMETHODIMP
    4281               0 : nsCanvasRenderingContext2DAzure::GetMozImageSmoothingEnabled(bool *retVal)
    4282                 : {
    4283               0 :   *retVal = CurrentState().imageSmoothingEnabled;
    4284               0 :   return NS_OK;
    4285                 : }
    4286                 : 
    4287                 : NS_IMETHODIMP
    4288               0 : nsCanvasRenderingContext2DAzure::SetMozImageSmoothingEnabled(bool val)
    4289                 : {
    4290               0 :   if (val != CurrentState().imageSmoothingEnabled) {
    4291               0 :       CurrentState().imageSmoothingEnabled = val;
    4292                 :   }
    4293                 : 
    4294               0 :   return NS_OK;
    4295                 : }
    4296                 : 
    4297                 : static PRUint8 g2DContextLayerUserData;
    4298                 : 
    4299               0 : class CanvasRenderingContext2DUserData : public LayerUserData {
    4300                 : public:
    4301               0 :   CanvasRenderingContext2DUserData(nsHTMLCanvasElement *aContent)
    4302               0 :     : mContent(aContent) {}
    4303               0 :   static void DidTransactionCallback(void* aData)
    4304                 :   {
    4305               0 :     static_cast<CanvasRenderingContext2DUserData*>(aData)->mContent->MarkContextClean();
    4306               0 :   }
    4307                 : 
    4308                 : private:
    4309                 :   nsRefPtr<nsHTMLCanvasElement> mContent;
    4310                 : };
    4311                 : 
    4312                 : already_AddRefed<CanvasLayer>
    4313               0 : nsCanvasRenderingContext2DAzure::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
    4314                 :                                            CanvasLayer *aOldLayer,
    4315                 :                                            LayerManager *aManager)
    4316                 : {
    4317               0 :   if (!mValid) {
    4318               0 :     return nsnull;
    4319                 :   }
    4320                 : 
    4321               0 :   if (mTarget) {
    4322               0 :     mTarget->Flush();
    4323                 :   }
    4324                 : 
    4325               0 :   if (!mResetLayer && aOldLayer &&
    4326               0 :       aOldLayer->HasUserData(&g2DContextLayerUserData)) {
    4327               0 :       NS_ADDREF(aOldLayer);
    4328               0 :       return aOldLayer;
    4329                 :   }
    4330                 : 
    4331               0 :   nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
    4332               0 :   if (!canvasLayer) {
    4333               0 :       NS_WARNING("CreateCanvasLayer returned null!");
    4334               0 :       return nsnull;
    4335                 :   }
    4336               0 :   CanvasRenderingContext2DUserData *userData = nsnull;
    4337               0 :   if (aBuilder->IsPaintingToWindow()) {
    4338                 :     // Make the layer tell us whenever a transaction finishes (including
    4339                 :     // the current transaction), so we can clear our invalidation state and
    4340                 :     // start invalidating again. We need to do this for the layer that is
    4341                 :     // being painted to a window (there shouldn't be more than one at a time,
    4342                 :     // and if there is, flushing the invalidation state more often than
    4343                 :     // necessary is harmless).
    4344                 : 
    4345                 :     // The layer will be destroyed when we tear down the presentation
    4346                 :     // (at the latest), at which time this userData will be destroyed,
    4347                 :     // releasing the reference to the element.
    4348                 :     // The userData will receive DidTransactionCallbacks, which flush the
    4349                 :     // the invalidation state to indicate that the canvas is up to date.
    4350               0 :     userData = new CanvasRenderingContext2DUserData(HTMLCanvasElement());
    4351                 :     canvasLayer->SetDidTransactionCallback(
    4352               0 :             CanvasRenderingContext2DUserData::DidTransactionCallback, userData);
    4353                 :   }
    4354               0 :   canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
    4355                 : 
    4356               0 :   CanvasLayer::Data data;
    4357                 : 
    4358               0 :   data.mDrawTarget = mTarget;
    4359               0 :   data.mSize = nsIntSize(mWidth, mHeight);
    4360                 : 
    4361               0 :   canvasLayer->Initialize(data);
    4362               0 :   PRUint32 flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
    4363               0 :   canvasLayer->SetContentFlags(flags);
    4364               0 :   canvasLayer->Updated();
    4365                 : 
    4366               0 :   mResetLayer = false;
    4367                 : 
    4368               0 :   return canvasLayer.forget();
    4369                 : }
    4370                 : 
    4371                 : void
    4372               0 : nsCanvasRenderingContext2DAzure::MarkContextClean()
    4373                 : {
    4374               0 :   if (mInvalidateCount > 0) {
    4375               0 :     mPredictManyRedrawCalls = mInvalidateCount > kCanvasMaxInvalidateCount;
    4376                 :   }
    4377               0 :   mIsEntireFrameInvalid = false;
    4378               0 :   mInvalidateCount = 0;
    4379            4392 : }
    4380                 : 

Generated by: LCOV version 1.7