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

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

Generated by: LCOV version 1.7