LCOV - app.info - content/html/content/src/nsHTMLCanvasElement.cpp

LCOV - code coverage report
| Current view: | directory - content/html/content/src - nsHTMLCanvasElement.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 362 | 2 | 0.6 %
| Date: | 2012-07-07 | Functions: | 50 | 2 | 4.0 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is mozilla.org code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  *   Vladimir Vukicevic <vladimir@pobox.com>
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2005
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *
          24                 :  * Alternatively, the contents of this file may be used under the terms of
          25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          28                 :  * of those above. If you wish to allow use of your version of this file only
          29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          30                 :  * use your version of this file under the terms of the MPL, indicate your
          31                 :  * decision by deleting the provisions above and replace them with the notice
          32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          33                 :  * the provisions above, a recipient may use your version of this file under
          34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          35                 :  *
          36                 :  * ***** END LICENSE BLOCK ***** */
          37                 :
          38                 : #include "nsHTMLCanvasElement.h"
          39                 :
          40                 : #include "mozilla/Base64.h"
          41                 : #include "nsNetUtil.h"
          42                 : #include "prmem.h"
          43                 : #include "nsDOMFile.h"
          44                 : #include "CheckedInt.h"
          45                 :
          46                 : #include "nsIScriptSecurityManager.h"
          47                 : #include "nsIXPConnect.h"
          48                 : #include "jsapi.h"
          49                 : #include "nsContentUtils.h"
          50                 : #include "nsJSUtils.h"
          51                 : #include "nsMathUtils.h"
          52                 : #include "nsStreamUtils.h"
          53                 : #include "mozilla/Preferences.h"
          54                 : #include "mozilla/Telemetry.h"
          55                 :
          56                 : #include "nsFrameManager.h"
          57                 : #include "nsDisplayList.h"
          58                 : #include "ImageLayers.h"
          59                 : #include "BasicLayers.h"
          60                 : #include "imgIEncoder.h"
          61                 :
          62                 : #include "nsIWritablePropertyBag2.h"
          63                 :
          64                 : #define DEFAULT_CANVAS_WIDTH 300
          65                 : #define DEFAULT_CANVAS_HEIGHT 150
          66                 :
          67                 : using namespace mozilla;
          68                 : using namespace mozilla::dom;
          69                 : using namespace mozilla::layers;
          70                 :
          71                 : nsGenericHTMLElement*
          72               0 : NS_NewHTMLCanvasElement(already_AddRefed<nsINodeInfo> aNodeInfo,
          73                 :                         FromParser aFromParser)
          74                 : {
          75               0 :   return new nsHTMLCanvasElement(aNodeInfo);
          76                 : }
          77                 :
          78               0 : nsHTMLCanvasElement::nsHTMLCanvasElement(already_AddRefed<nsINodeInfo> aNodeInfo)
          79               0 :   : nsGenericHTMLElement(aNodeInfo), mWriteOnly(false)
          80                 : {
          81               0 : }
          82                 :
          83               0 : nsHTMLCanvasElement::~nsHTMLCanvasElement()
          84                 : {
          85               0 : }
          86                 :
          87            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLCanvasElement)
          88               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLCanvasElement,
          89                 :                                                   nsGenericHTMLElement)
          90               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentContext)
          91               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
          92                 :
          93               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLCanvasElement,
          94                 :                                                 nsGenericHTMLElement)
          95               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCurrentContext)
          96               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
          97                 :
          98               0 : NS_IMPL_ADDREF_INHERITED(nsHTMLCanvasElement, nsGenericElement)
          99               0 : NS_IMPL_RELEASE_INHERITED(nsHTMLCanvasElement, nsGenericElement)
         100                 :
         101               0 : DOMCI_NODE_DATA(HTMLCanvasElement, nsHTMLCanvasElement)
         102                 :
         103               0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLCanvasElement)
         104               0 :   NS_HTML_CONTENT_INTERFACE_TABLE2(nsHTMLCanvasElement,
         105                 :                                    nsIDOMHTMLCanvasElement,
         106                 :                                    nsICanvasElementExternal)
         107               0 :   NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLCanvasElement,
         108                 :                                                nsGenericHTMLElement)
         109               0 : NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLCanvasElement)
         110                 :
         111               0 : NS_IMPL_ELEMENT_CLONE(nsHTMLCanvasElement)
         112                 :
         113                 : nsIntSize
         114               0 : nsHTMLCanvasElement::GetWidthHeight()
         115                 : {
         116               0 :   nsIntSize size(DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT);
         117                 :   const nsAttrValue* value;
         118                 :
         119               0 :   if ((value = GetParsedAttr(nsGkAtoms::width)) &&
         120               0 :       value->Type() == nsAttrValue::eInteger)
         121                 :   {
         122               0 :       size.width = value->GetIntegerValue();
         123                 :   }
         124                 :
         125               0 :   if ((value = GetParsedAttr(nsGkAtoms::height)) &&
         126               0 :       value->Type() == nsAttrValue::eInteger)
         127                 :   {
         128               0 :       size.height = value->GetIntegerValue();
         129                 :   }
         130                 :
         131                 :   return size;
         132                 : }
         133                 :
         134               0 : NS_IMPL_UINT_ATTR_DEFAULT_VALUE(nsHTMLCanvasElement, Width, width, DEFAULT_CANVAS_WIDTH)
         135               0 : NS_IMPL_UINT_ATTR_DEFAULT_VALUE(nsHTMLCanvasElement, Height, height, DEFAULT_CANVAS_HEIGHT)
         136               0 : NS_IMPL_BOOL_ATTR(nsHTMLCanvasElement, MozOpaque, moz_opaque)
         137                 :
         138                 : nsresult
         139               0 : nsHTMLCanvasElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
         140                 :                              nsIAtom* aPrefix, const nsAString& aValue,
         141                 :                              bool aNotify)
         142                 : {
         143                 :   nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
         144               0 :                                               aNotify);
         145               0 :   if (NS_SUCCEEDED(rv) && mCurrentContext &&
         146                 :       (aName == nsGkAtoms::width || aName == nsGkAtoms::height || aName == nsGkAtoms::moz_opaque))
         147                 :   {
         148               0 :     rv = UpdateContext();
         149               0 :     NS_ENSURE_SUCCESS(rv, rv);
         150                 :   }
         151                 :
         152               0 :   return rv;
         153                 : }
         154                 :
         155                 : nsresult
         156               0 : nsHTMLCanvasElement::CopyInnerTo(nsGenericElement* aDest) const
         157                 : {
         158               0 :   nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
         159               0 :   NS_ENSURE_SUCCESS(rv, rv);
         160               0 :   if (aDest->OwnerDoc()->IsStaticDocument()) {
         161               0 :     nsHTMLCanvasElement* dest = static_cast<nsHTMLCanvasElement*>(aDest);
         162               0 :     nsCOMPtr<nsISupports> cxt;
         163               0 :     dest->GetContext(NS_LITERAL_STRING("2d"), JSVAL_VOID, getter_AddRefs(cxt));
         164               0 :     nsCOMPtr<nsIDOMCanvasRenderingContext2D> context2d = do_QueryInterface(cxt);
         165               0 :     if (context2d) {
         166               0 :       context2d->DrawImage(const_cast<nsHTMLCanvasElement*>(this),
         167               0 :                            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
         168                 :     }
         169                 :   }
         170               0 :   return rv;
         171                 : }
         172                 :
         173                 : nsChangeHint
         174               0 : nsHTMLCanvasElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
         175                 :                                             PRInt32 aModType) const
         176                 : {
         177                 :   nsChangeHint retval =
         178               0 :     nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
         179               0 :   if (aAttribute == nsGkAtoms::width ||
         180                 :       aAttribute == nsGkAtoms::height)
         181                 :   {
         182               0 :     NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
         183               0 :   } else if (aAttribute == nsGkAtoms::moz_opaque)
         184                 :   {
         185               0 :     NS_UpdateHint(retval, NS_STYLE_HINT_VISUAL);
         186                 :   }
         187               0 :   return retval;
         188                 : }
         189                 :
         190                 : bool
         191               0 : nsHTMLCanvasElement::ParseAttribute(PRInt32 aNamespaceID,
         192                 :                                     nsIAtom* aAttribute,
         193                 :                                     const nsAString& aValue,
         194                 :                                     nsAttrValue& aResult)
         195                 : {
         196               0 :   if (aNamespaceID == kNameSpaceID_None &&
         197                 :       (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
         198               0 :     return aResult.ParseNonNegativeIntValue(aValue);
         199                 :   }
         200                 :
         201                 :   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
         202               0 :                                               aResult);
         203                 : }
         204                 :
         205                 :
         206                 : // nsHTMLCanvasElement::toDataURL
         207                 :
         208                 : NS_IMETHODIMP
         209               0 : nsHTMLCanvasElement::ToDataURL(const nsAString& aType, nsIVariant* aParams,
         210                 :                                PRUint8 optional_argc, nsAString& aDataURL)
         211                 : {
         212                 :   // do a trust check if this is a write-only canvas
         213               0 :   if (mWriteOnly && !nsContentUtils::IsCallerTrustedForRead()) {
         214               0 :     return NS_ERROR_DOM_SECURITY_ERR;
         215                 :   }
         216                 :
         217               0 :   return ToDataURLImpl(aType, aParams, aDataURL);
         218                 : }
         219                 :
         220                 : // nsHTMLCanvasElement::mozFetchAsStream
         221                 :
         222                 : NS_IMETHODIMP
         223               0 : nsHTMLCanvasElement::MozFetchAsStream(nsIInputStreamCallback *aCallback,
         224                 :                                       const nsAString& aType)
         225                 : {
         226               0 :   if (!nsContentUtils::IsCallerChrome())
         227               0 :     return NS_ERROR_FAILURE;
         228                 :
         229                 :   nsresult rv;
         230               0 :   bool fellBackToPNG = false;
         231               0 :   nsCOMPtr<nsIInputStream> inputData;
         232                 :
         233               0 :   rv = ExtractData(aType, EmptyString(), getter_AddRefs(inputData), fellBackToPNG);
         234               0 :   NS_ENSURE_SUCCESS(rv, rv);
         235                 :
         236               0 :   nsCOMPtr<nsIAsyncInputStream> asyncData = do_QueryInterface(inputData, &rv);
         237               0 :   NS_ENSURE_SUCCESS(rv, rv);
         238                 :
         239               0 :   nsCOMPtr<nsIThread> mainThread;
         240               0 :   rv = NS_GetMainThread(getter_AddRefs(mainThread));
         241               0 :   NS_ENSURE_SUCCESS(rv, rv);
         242                 :
         243               0 :   nsCOMPtr<nsIInputStreamCallback> asyncCallback;
         244               0 :   rv = NS_NewInputStreamReadyEvent(getter_AddRefs(asyncCallback), aCallback, mainThread);
         245               0 :   NS_ENSURE_SUCCESS(rv, rv);
         246                 :
         247               0 :   return asyncCallback->OnInputStreamReady(asyncData);
         248                 : }
         249                 :
         250                 : nsresult
         251               0 : nsHTMLCanvasElement::ExtractData(const nsAString& aType,
         252                 :                                  const nsAString& aOptions,
         253                 :                                  nsIInputStream** aStream,
         254                 :                                  bool& aFellBackToPNG)
         255                 : {
         256                 :   // note that if we don't have a current context, the spec says we're
         257                 :   // supposed to just return transparent black pixels of the canvas
         258                 :   // dimensions.
         259               0 :   nsRefPtr<gfxImageSurface> emptyCanvas;
         260               0 :   nsIntSize size = GetWidthHeight();
         261               0 :   if (!mCurrentContext) {
         262               0 :     emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxASurface::ImageFormatARGB32);
         263               0 :     if (emptyCanvas->CairoStatus()) {
         264               0 :       return NS_ERROR_INVALID_ARG;
         265                 :     }
         266                 :   }
         267                 :
         268                 :   nsresult rv;
         269                 :
         270                 :   // get image bytes
         271               0 :   nsCOMPtr<nsIInputStream> imgStream;
         272               0 :   NS_ConvertUTF16toUTF8 encoderType(aType);
         273                 :
         274                 :  try_again:
         275               0 :   if (mCurrentContext) {
         276               0 :     rv = mCurrentContext->GetInputStream(encoderType.get(),
         277               0 :                                          nsPromiseFlatString(aOptions).get(),
         278               0 :                                          getter_AddRefs(imgStream));
         279                 :   } else {
         280                 :     // no context, so we have to encode the empty image we created above
         281               0 :     nsCString enccid("@mozilla.org/image/encoder;2?type=");
         282               0 :     enccid += encoderType;
         283                 :
         284               0 :     nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get(), &rv);
         285               0 :     if (NS_SUCCEEDED(rv) && encoder) {
         286               0 :       rv = encoder->InitFromData(emptyCanvas->Data(),
         287                 :                                  size.width * size.height * 4,
         288                 :                                  size.width,
         289                 :                                  size.height,
         290                 :                                  size.width * 4,
         291                 :                                  imgIEncoder::INPUT_FORMAT_HOSTARGB,
         292               0 :                                  aOptions);
         293               0 :       if (NS_SUCCEEDED(rv)) {
         294               0 :         imgStream = do_QueryInterface(encoder);
         295                 :       }
         296                 :     } else {
         297               0 :       rv = NS_ERROR_FAILURE;
         298                 :     }
         299                 :   }
         300                 :
         301               0 :   if (NS_FAILED(rv) && !aFellBackToPNG) {
         302                 :     // Try image/png instead.
         303                 :     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         304               0 :     aFellBackToPNG = true;
         305               0 :     encoderType.AssignLiteral("image/png");
         306               0 :     goto try_again;
         307                 :   }
         308                 :
         309               0 :   NS_ENSURE_SUCCESS(rv, rv);
         310                 :
         311               0 :   imgStream.forget(aStream);
         312               0 :   return NS_OK;
         313                 : }
         314                 :
         315                 : nsresult
         316               0 : nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
         317                 :                                    nsIVariant* aEncoderOptions,
         318                 :                                    nsAString& aDataURL)
         319                 : {
         320               0 :   bool fallbackToPNG = false;
         321                 :
         322               0 :   nsIntSize size = GetWidthHeight();
         323               0 :   if (size.height == 0 || size.width == 0) {
         324               0 :     aDataURL = NS_LITERAL_STRING("data:,");
         325               0 :     return NS_OK;
         326                 :   }
         327                 :
         328               0 :   nsAutoString type;
         329               0 :   nsresult rv = nsContentUtils::ASCIIToLower(aMimeType, type);
         330               0 :   if (NS_FAILED(rv)) {
         331               0 :     return rv;
         332                 :   }
         333                 :
         334               0 :   nsAutoString params;
         335                 :
         336                 :   // Quality parameter is only valid for the image/jpeg MIME type
         337               0 :   if (type.EqualsLiteral("image/jpeg")) {
         338                 :     PRUint16 vartype;
         339                 :
         340               0 :     if (aEncoderOptions &&
         341               0 :         NS_SUCCEEDED(aEncoderOptions->GetDataType(&vartype)) &&
         342                 :         vartype <= nsIDataType::VTYPE_DOUBLE) {
         343                 :
         344                 :       double quality;
         345                 :       // Quality must be between 0.0 and 1.0, inclusive
         346               0 :       if (NS_SUCCEEDED(aEncoderOptions->GetAsDouble(&quality)) &&
         347                 :           quality >= 0.0 && quality <= 1.0) {
         348               0 :         params.AppendLiteral("quality=");
         349               0 :         params.AppendInt(NS_lround(quality * 100.0));
         350                 :       }
         351                 :     }
         352                 :   }
         353                 :
         354                 :   // If we haven't parsed the params check for proprietary options.
         355                 :   // The proprietary option -moz-parse-options will take a image lib encoder
         356                 :   // parse options string as is and pass it to the encoder.
         357               0 :   bool usingCustomParseOptions = false;
         358               0 :   if (params.Length() == 0) {
         359               0 :     NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:");
         360               0 :     nsAutoString paramString;
         361               0 :     if (NS_SUCCEEDED(aEncoderOptions->GetAsAString(paramString)) &&
         362               0 :         StringBeginsWith(paramString, mozParseOptions)) {
         363                 :       nsDependentSubstring parseOptions = Substring(paramString,
         364                 :                                                     mozParseOptions.Length(),
         365               0 :                                                     paramString.Length() -
         366               0 :                                                     mozParseOptions.Length());
         367               0 :       params.Append(parseOptions);
         368               0 :       usingCustomParseOptions = true;
         369                 :     }
         370                 :   }
         371                 :
         372               0 :   nsCOMPtr<nsIInputStream> stream;
         373               0 :   rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
         374                 :
         375                 :   // If there are unrecognized custom parse options, we should fall back to
         376                 :   // the default values for the encoder without any options at all.
         377               0 :   if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
         378               0 :     fallbackToPNG = false;
         379               0 :     rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
         380                 :   }
         381                 :
         382               0 :   NS_ENSURE_SUCCESS(rv, rv);
         383                 :
         384                 :   // build data URL string
         385               0 :   if (fallbackToPNG)
         386               0 :     aDataURL = NS_LITERAL_STRING("data:image/png;base64,");
         387                 :   else
         388               0 :     aDataURL = NS_LITERAL_STRING("data:") + type +
         389               0 :       NS_LITERAL_STRING(";base64,");
         390                 :
         391                 :   PRUint32 count;
         392               0 :   rv = stream->Available(&count);
         393               0 :   NS_ENSURE_SUCCESS(rv, rv);
         394                 :
         395               0 :   return Base64EncodeInputStream(stream, aDataURL, count, aDataURL.Length());
         396                 : }
         397                 :
         398                 : NS_IMETHODIMP
         399               0 : nsHTMLCanvasElement::MozGetAsFile(const nsAString& aName,
         400                 :                                   const nsAString& aType,
         401                 :                                   PRUint8 optional_argc,
         402                 :                                   nsIDOMFile** aResult)
         403                 : {
         404                 :   // do a trust check if this is a write-only canvas
         405               0 :   if ((mWriteOnly) &&
         406               0 :       !nsContentUtils::IsCallerTrustedForRead()) {
         407               0 :     return NS_ERROR_DOM_SECURITY_ERR;
         408                 :   }
         409                 :
         410               0 :   return MozGetAsFileImpl(aName, aType, aResult);
         411                 : }
         412                 :
         413                 : nsresult
         414               0 : nsHTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
         415                 :                                       const nsAString& aType,
         416                 :                                       nsIDOMFile** aResult)
         417                 : {
         418               0 :   bool fallbackToPNG = false;
         419                 :
         420               0 :   nsCOMPtr<nsIInputStream> stream;
         421               0 :   nsresult rv = ExtractData(aType, EmptyString(), getter_AddRefs(stream),
         422               0 :                             fallbackToPNG);
         423               0 :   NS_ENSURE_SUCCESS(rv, rv);
         424                 :
         425               0 :   nsAutoString type(aType);
         426               0 :   if (fallbackToPNG) {
         427               0 :     type.AssignLiteral("image/png");
         428                 :   }
         429                 :
         430                 :   PRUint32 imgSize;
         431               0 :   rv = stream->Available(&imgSize);
         432               0 :   NS_ENSURE_SUCCESS(rv, rv);
         433                 :
         434               0 :   void* imgData = nsnull;
         435               0 :   rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
         436               0 :   NS_ENSURE_SUCCESS(rv, rv);
         437                 :
         438                 :   // The DOMFile takes ownership of the buffer
         439                 :   nsRefPtr<nsDOMMemoryFile> file =
         440               0 :     new nsDOMMemoryFile(imgData, imgSize, aName, type);
         441                 :
         442               0 :   file.forget(aResult);
         443               0 :   return NS_OK;
         444                 : }
         445                 :
         446                 : nsresult
         447               0 : nsHTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
         448                 :                                       bool aForceThebes,
         449                 :                                       nsICanvasRenderingContextInternal **aContext)
         450                 : {
         451               0 :   NS_ENSURE_ARG(aContext);
         452                 :
         453               0 :   NS_ConvertUTF16toUTF8 ctxId(aContextId);
         454                 :
         455                 :   // check that ctxId is clamped to A-Za-z0-9_-
         456               0 :   for (PRUint32 i = 0; i < ctxId.Length(); i++) {
         457               0 :     if ((ctxId[i] < 'A' || ctxId[i] > 'Z') &&
         458               0 :         (ctxId[i] < 'a' || ctxId[i] > 'z') &&
         459               0 :         (ctxId[i] < '0' || ctxId[i] > '9') &&
         460               0 :         (ctxId[i] != '-') &&
         461               0 :         (ctxId[i] != '_'))
         462                 :     {
         463                 :       // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         464               0 :       return NS_OK;
         465                 :     }
         466                 :   }
         467                 :
         468               0 :   nsCString ctxString("@mozilla.org/content/canvas-rendering-context;1?id=");
         469               0 :   ctxString.Append(ctxId);
         470                 :
         471               0 :   if (aForceThebes && ctxId.EqualsASCII("2d")) {
         472               0 :     ctxString.AssignASCII("@mozilla.org/content/2dthebes-canvas-rendering-context;1");
         473                 :   }
         474                 :
         475                 :   nsresult rv;
         476                 :   nsCOMPtr<nsICanvasRenderingContextInternal> ctx =
         477               0 :     do_CreateInstance(ctxString.get(), &rv);
         478               0 :   if (rv == NS_ERROR_OUT_OF_MEMORY) {
         479               0 :     *aContext = nsnull;
         480               0 :     return NS_ERROR_OUT_OF_MEMORY;
         481                 :   }
         482               0 :   if (NS_FAILED(rv)) {
         483               0 :     *aContext = nsnull;
         484                 :     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         485               0 :     return NS_OK;
         486                 :   }
         487                 :
         488               0 :   rv = ctx->SetCanvasElement(this);
         489               0 :   if (NS_FAILED(rv)) {
         490               0 :     *aContext = nsnull;
         491               0 :     return rv;
         492                 :   }
         493                 :
         494               0 :   ctx.forget(aContext);
         495                 :
         496               0 :   return rv;
         497                 : }
         498                 :
         499                 : NS_IMETHODIMP
         500               0 : nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
         501                 :                                 const jsval& aContextOptions,
         502                 :                                 nsISupports **aContext)
         503                 : {
         504                 :   nsresult rv;
         505                 :
         506               0 :   bool forceThebes = false;
         507                 :
         508               0 :   while (mCurrentContextId.IsEmpty()) {
         509               0 :     rv = GetContextHelper(aContextId, forceThebes, getter_AddRefs(mCurrentContext));
         510               0 :     NS_ENSURE_SUCCESS(rv, rv);
         511               0 :     if (!mCurrentContext) {
         512               0 :       return NS_OK;
         513                 :     }
         514                 :
         515                 :     // Ensure that the context participates in CC.  Note that returning a
         516                 :     // CC participant from QI doesn't addref.
         517               0 :     nsXPCOMCycleCollectionParticipant *cp = nsnull;
         518               0 :     CallQueryInterface(mCurrentContext, &cp);
         519               0 :     if (!cp) {
         520               0 :       mCurrentContext = nsnull;
         521               0 :       return NS_ERROR_FAILURE;
         522                 :     }
         523                 :
         524               0 :     nsCOMPtr<nsIWritablePropertyBag2> contextProps;
         525               0 :     if (!JSVAL_IS_NULL(aContextOptions) &&
         526               0 :         !JSVAL_IS_VOID(aContextOptions))
         527                 :     {
         528               0 :       JSContext *cx = nsContentUtils::GetCurrentJSContext();
         529                 :
         530                 :       // note: if any contexts end up supporting something other
         531                 :       // than objects, e.g. plain strings, then we'll need to expand
         532                 :       // this to know how to create nsISupportsStrings etc.
         533               0 :       if (JSVAL_IS_OBJECT(aContextOptions)) {
         534               0 :         contextProps = do_CreateInstance("@mozilla.org/hash-property-bag;1");
         535                 :
         536               0 :         JSObject *opts = JSVAL_TO_OBJECT(aContextOptions);
         537               0 :         JS::AutoIdArray props(cx, JS_Enumerate(cx, opts));
         538               0 :         for (size_t i = 0; !!props && i < props.length(); ++i) {
         539               0 :           jsid propid = props[i];
         540                 :           jsval propname, propval;
         541               0 :           if (!JS_IdToValue(cx, propid, &propname) ||
         542               0 :               !JS_GetPropertyById(cx, opts, propid, &propval)) {
         543               0 :             continue;
         544                 :           }
         545                 :
         546               0 :           JSString *propnameString = JS_ValueToString(cx, propname);
         547               0 :           nsDependentJSString pstr;
         548               0 :           if (!propnameString || !pstr.init(cx, propnameString)) {
         549               0 :             mCurrentContext = nsnull;
         550               0 :             return NS_ERROR_FAILURE;
         551                 :           }
         552                 :
         553               0 :           if (JSVAL_IS_BOOLEAN(propval)) {
         554               0 :             contextProps->SetPropertyAsBool(pstr, JSVAL_TO_BOOLEAN(propval));
         555               0 :           } else if (JSVAL_IS_INT(propval)) {
         556               0 :             contextProps->SetPropertyAsInt32(pstr, JSVAL_TO_INT(propval));
         557               0 :           } else if (JSVAL_IS_DOUBLE(propval)) {
         558               0 :             contextProps->SetPropertyAsDouble(pstr, JSVAL_TO_DOUBLE(propval));
         559               0 :           } else if (JSVAL_IS_STRING(propval)) {
         560               0 :             JSString *propvalString = JS_ValueToString(cx, propval);
         561               0 :             nsDependentJSString vstr;
         562               0 :             if (!propvalString || !vstr.init(cx, propvalString)) {
         563               0 :               mCurrentContext = nsnull;
         564               0 :               return NS_ERROR_FAILURE;
         565                 :             }
         566                 :
         567               0 :             contextProps->SetPropertyAsAString(pstr, vstr);
         568                 :           }
         569                 :         }
         570                 :       }
         571                 :     }
         572                 :
         573               0 :     rv = UpdateContext(contextProps);
         574               0 :     if (NS_FAILED(rv)) {
         575               0 :       if (!forceThebes) {
         576                 :         // Try again with a Thebes context
         577               0 :         forceThebes = true;
         578               0 :         continue;
         579                 :       }
         580               0 :       return rv;
         581                 :     }
         582                 :
         583               0 :     mCurrentContextId.Assign(aContextId);
         584               0 :     break;
         585                 :   }
         586               0 :   if (!mCurrentContextId.Equals(aContextId)) {
         587                 :     //XXX eventually allow for more than one active context on a given canvas
         588               0 :     return NS_OK;
         589                 :   }
         590                 :
         591               0 :   NS_ADDREF (*aContext = mCurrentContext);
         592               0 :   return NS_OK;
         593                 : }
         594                 :
         595                 : NS_IMETHODIMP
         596               0 : nsHTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
         597                 :                                       nsISupports **aContext)
         598                 : {
         599               0 :   if(!nsContentUtils::IsCallerTrustedForRead()) {
         600                 :     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
         601               0 :     return NS_ERROR_DOM_SECURITY_ERR;
         602                 :   }
         603                 :
         604                 :   // We only support 2d shmem contexts for now.
         605               0 :   if (!aContextId.Equals(NS_LITERAL_STRING("2d")))
         606               0 :     return NS_ERROR_INVALID_ARG;
         607                 :
         608               0 :   if (mCurrentContextId.IsEmpty()) {
         609               0 :     nsresult rv = GetContextHelper(aContextId, false, getter_AddRefs(mCurrentContext));
         610               0 :     NS_ENSURE_SUCCESS(rv, rv);
         611               0 :     if (!mCurrentContext) {
         612               0 :       return NS_OK;
         613                 :     }
         614                 :
         615               0 :     mCurrentContext->SetIsIPC(true);
         616                 :
         617               0 :     rv = UpdateContext();
         618               0 :     NS_ENSURE_SUCCESS(rv, rv);
         619                 :
         620               0 :     mCurrentContextId.Assign(aContextId);
         621               0 :   } else if (!mCurrentContextId.Equals(aContextId)) {
         622                 :     //XXX eventually allow for more than one active context on a given canvas
         623               0 :     return NS_ERROR_INVALID_ARG;
         624                 :   }
         625                 :
         626               0 :   NS_ADDREF (*aContext = mCurrentContext);
         627               0 :   return NS_OK;
         628                 : }
         629                 :
         630                 : nsresult
         631               0 : nsHTMLCanvasElement::UpdateContext(nsIPropertyBag *aNewContextOptions)
         632                 : {
         633               0 :   if (!mCurrentContext)
         634               0 :     return NS_OK;
         635                 :
         636               0 :   nsIntSize sz = GetWidthHeight();
         637                 :
         638               0 :   nsresult rv = mCurrentContext->SetIsOpaque(GetIsOpaque());
         639               0 :   if (NS_FAILED(rv)) {
         640               0 :     mCurrentContext = nsnull;
         641               0 :     mCurrentContextId.Truncate();
         642               0 :     return rv;
         643                 :   }
         644                 :
         645               0 :   rv = mCurrentContext->SetContextOptions(aNewContextOptions);
         646               0 :   if (NS_FAILED(rv)) {
         647               0 :     mCurrentContext = nsnull;
         648               0 :     mCurrentContextId.Truncate();
         649               0 :     return rv;
         650                 :   }
         651                 :
         652               0 :   rv = mCurrentContext->SetDimensions(sz.width, sz.height);
         653               0 :   if (NS_FAILED(rv)) {
         654               0 :     mCurrentContext = nsnull;
         655               0 :     mCurrentContextId.Truncate();
         656               0 :     return rv;
         657                 :   }
         658                 :
         659               0 :   return rv;
         660                 : }
         661                 :
         662                 : nsIFrame *
         663               0 : nsHTMLCanvasElement::GetPrimaryCanvasFrame()
         664                 : {
         665               0 :   return GetPrimaryFrame(Flush_Frames);
         666                 : }
         667                 :
         668                 : nsIntSize
         669               0 : nsHTMLCanvasElement::GetSize()
         670                 : {
         671               0 :   return GetWidthHeight();
         672                 : }
         673                 :
         674                 : bool
         675               0 : nsHTMLCanvasElement::IsWriteOnly()
         676                 : {
         677               0 :   return mWriteOnly;
         678                 : }
         679                 :
         680                 : void
         681               0 : nsHTMLCanvasElement::SetWriteOnly()
         682                 : {
         683               0 :   mWriteOnly = true;
         684               0 : }
         685                 :
         686                 : void
         687               0 : nsHTMLCanvasElement::InvalidateCanvasContent(const gfxRect* damageRect)
         688                 : {
         689                 :   // We don't need to flush anything here; if there's no frame or if
         690                 :   // we plan to reframe we don't need to invalidate it anyway.
         691               0 :   nsIFrame *frame = GetPrimaryFrame();
         692               0 :   if (!frame)
         693               0 :     return;
         694                 :
         695               0 :   frame->MarkLayersActive(nsChangeHint(0));
         696                 :
         697               0 :   nsRect invalRect;
         698               0 :   nsRect contentArea = frame->GetContentRect();
         699               0 :   if (damageRect) {
         700               0 :     nsIntSize size = GetWidthHeight();
         701               0 :     if (size.width != 0 && size.height != 0) {
         702                 :
         703                 :       // damageRect and size are in CSS pixels; contentArea is in appunits
         704                 :       // We want a rect in appunits; so avoid doing pixels-to-appunits and
         705                 :       // vice versa conversion here.
         706               0 :       gfxRect realRect(*damageRect);
         707                 :       realRect.Scale(contentArea.width / gfxFloat(size.width),
         708               0 :                      contentArea.height / gfxFloat(size.height));
         709               0 :       realRect.RoundOut();
         710                 :
         711                 :       // then make it a nsRect
         712               0 :       invalRect = nsRect(realRect.X(), realRect.Y(),
         713               0 :                          realRect.Width(), realRect.Height());
         714                 :
         715               0 :       invalRect = invalRect.Intersect(nsRect(nsPoint(0,0), contentArea.Size()));
         716                 :     }
         717                 :   } else {
         718               0 :     invalRect = nsRect(nsPoint(0, 0), contentArea.Size());
         719                 :   }
         720               0 :   invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition());
         721                 :
         722               0 :   Layer* layer = frame->InvalidateLayer(invalRect, nsDisplayItem::TYPE_CANVAS);
         723               0 :   if (layer) {
         724               0 :     static_cast<CanvasLayer*>(layer)->Updated();
         725                 :   }
         726                 : }
         727                 :
         728                 : void
         729               0 : nsHTMLCanvasElement::InvalidateCanvas()
         730                 : {
         731                 :   // We don't need to flush anything here; if there's no frame or if
         732                 :   // we plan to reframe we don't need to invalidate it anyway.
         733               0 :   nsIFrame *frame = GetPrimaryFrame();
         734               0 :   if (!frame)
         735               0 :     return;
         736                 :
         737               0 :   frame->Invalidate(frame->GetContentRect() - frame->GetPosition());
         738                 : }
         739                 :
         740                 : PRInt32
         741               0 : nsHTMLCanvasElement::CountContexts()
         742                 : {
         743               0 :   if (mCurrentContext)
         744               0 :     return 1;
         745                 :
         746               0 :   return 0;
         747                 : }
         748                 :
         749                 : nsICanvasRenderingContextInternal *
         750               0 : nsHTMLCanvasElement::GetContextAtIndex(PRInt32 index)
         751                 : {
         752               0 :   if (mCurrentContext && index == 0)
         753               0 :     return mCurrentContext;
         754                 :
         755               0 :   return NULL;
         756                 : }
         757                 :
         758                 : bool
         759               0 : nsHTMLCanvasElement::GetIsOpaque()
         760                 : {
         761               0 :   return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
         762                 : }
         763                 :
         764                 : already_AddRefed<CanvasLayer>
         765               0 : nsHTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
         766                 :                                     CanvasLayer *aOldLayer,
         767                 :                                     LayerManager *aManager)
         768                 : {
         769               0 :   if (!mCurrentContext)
         770               0 :     return nsnull;
         771                 :
         772               0 :   return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager);
         773                 : }
         774                 :
         775                 : bool
         776               0 : nsHTMLCanvasElement::ShouldForceInactiveLayer(LayerManager *aManager)
         777                 : {
         778               0 :   return !mCurrentContext || mCurrentContext->ShouldForceInactiveLayer(aManager);
         779                 : }
         780                 :
         781                 : void
         782               0 : nsHTMLCanvasElement::MarkContextClean()
         783                 : {
         784               0 :   if (!mCurrentContext)
         785               0 :     return;
         786                 :
         787               0 :   mCurrentContext->MarkContextClean();
         788                 : }
         789                 :
         790                 : NS_IMETHODIMP_(nsIntSize)
         791               0 : nsHTMLCanvasElement::GetSizeExternal()
         792                 : {
         793               0 :   return GetWidthHeight();
         794                 : }
         795                 :
         796                 : NS_IMETHODIMP
         797               0 : nsHTMLCanvasElement::RenderContextsExternal(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter)
         798                 : {
         799               0 :   if (!mCurrentContext)
         800               0 :     return NS_OK;
         801                 :
         802               0 :   return mCurrentContext->Render(aContext, aFilter);
         803                 : }
         804                 :
         805                 : nsresult NS_NewCanvasRenderingContext2DThebes(nsIDOMCanvasRenderingContext2D** aResult);
         806                 : nsresult NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult);
         807                 :
         808                 : nsresult
         809               0 : NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult)
         810                 : {
         811               0 :   Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
         812               0 :   if (Preferences::GetBool("gfx.canvas.azure.enabled", false)) {
         813               0 :     nsresult rv = NS_NewCanvasRenderingContext2DAzure(aResult);
         814                 :     // If Azure fails, fall back to a classic canvas.
         815               0 :     if (NS_SUCCEEDED(rv)) {
         816               0 :       return rv;
         817                 :     }
         818                 :   }
         819                 :
         820               0 :   return NS_NewCanvasRenderingContext2DThebes(aResult);
         821            4392 : }

Generated by: LCOV version 1.7