LCOV - code coverage report
Current view: directory - gfx/thebes - gfxASurface.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 313 78 24.9 %
Date: 2012-06-02 Functions: 54 19 35.2 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Foundation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2006
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Stuart Parmenter <stuart@mozilla.com>
      23                 :  *   Vladimir Vukicevic <vladimir@pobox.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsIMemoryReporter.h"
      40                 : #include "nsMemory.h"
      41                 : #include "CheckedInt.h"
      42                 : 
      43                 : #include "gfxASurface.h"
      44                 : #include "gfxContext.h"
      45                 : #include "gfxImageSurface.h"
      46                 : 
      47                 : #include "nsRect.h"
      48                 : 
      49                 : #include "cairo.h"
      50                 : 
      51                 : #ifdef CAIRO_HAS_WIN32_SURFACE
      52                 : #include "gfxWindowsSurface.h"
      53                 : #endif
      54                 : #ifdef CAIRO_HAS_D2D_SURFACE
      55                 : #include "gfxD2DSurface.h"
      56                 : #endif
      57                 : 
      58                 : #ifdef MOZ_X11
      59                 : #include "gfxXlibSurface.h"
      60                 : #endif
      61                 : 
      62                 : #ifdef CAIRO_HAS_QUARTZ_SURFACE
      63                 : #include "gfxQuartzSurface.h"
      64                 : #include "gfxQuartzImageSurface.h"
      65                 : #endif
      66                 : 
      67                 : #if defined(CAIRO_HAS_QT_SURFACE) && defined(MOZ_WIDGET_QT)
      68                 : #include "gfxQPainterSurface.h"
      69                 : #endif
      70                 : 
      71                 : #include <stdio.h>
      72                 : #include <limits.h>
      73                 : 
      74                 : #include "imgIEncoder.h"
      75                 : #include "nsComponentManagerUtils.h"
      76                 : #include "prmem.h"
      77                 : #include "nsISupportsUtils.h"
      78                 : #include "plbase64.h"
      79                 : #include "nsCOMPtr.h"
      80                 : #include "nsIConsoleService.h"
      81                 : #include "nsServiceManagerUtils.h"
      82                 : #include "nsStringGlue.h"
      83                 : #include "nsIClipboardHelper.h"
      84                 : 
      85                 : using mozilla::CheckedInt;
      86                 : 
      87                 : static cairo_user_data_key_t gfxasurface_pointer_key;
      88                 : 
      89                 : // Surfaces use refcounting that's tied to the cairo surface refcnt, to avoid
      90                 : // refcount mismatch issues.
      91                 : nsrefcnt
      92             143 : gfxASurface::AddRef(void)
      93                 : {
      94             143 :     if (mSurfaceValid) {
      95             143 :         if (mFloatingRefs) {
      96                 :             // eat a floating ref
      97              65 :             mFloatingRefs--;
      98                 :         } else {
      99              78 :             cairo_surface_reference(mSurface);
     100                 :         }
     101                 : 
     102             143 :         return (nsrefcnt) cairo_surface_get_reference_count(mSurface);
     103                 :     } else {
     104                 :         // the surface isn't valid, but we still need to refcount
     105                 :         // the gfxASurface
     106               0 :         return ++mFloatingRefs;
     107                 :     }
     108                 : }
     109                 : 
     110                 : nsrefcnt
     111             143 : gfxASurface::Release(void)
     112                 : {
     113             143 :     if (mSurfaceValid) {
     114             143 :         NS_ASSERTION(mFloatingRefs == 0, "gfxASurface::Release with floating refs still hanging around!");
     115                 : 
     116                 :         // Note that there is a destructor set on user data for mSurface,
     117                 :         // which will delete this gfxASurface wrapper when the surface's refcount goes
     118                 :         // out of scope.
     119             143 :         nsrefcnt refcnt = (nsrefcnt) cairo_surface_get_reference_count(mSurface);
     120             143 :         cairo_surface_destroy(mSurface);
     121                 : 
     122                 :         // |this| may not be valid any more, don't use it!
     123                 : 
     124             143 :         return --refcnt;
     125                 :     } else {
     126               0 :         if (--mFloatingRefs == 0) {
     127               0 :             delete this;
     128               0 :             return 0;
     129                 :         }
     130                 : 
     131               0 :         return mFloatingRefs;
     132                 :     }
     133                 : }
     134                 : 
     135                 : void
     136              65 : gfxASurface::SurfaceDestroyFunc(void *data) {
     137              65 :     gfxASurface *surf = (gfxASurface*) data;
     138                 :     // fprintf (stderr, "Deleting wrapper for %p (wrapper: %p)\n", surf->mSurface, data);
     139              65 :     delete surf;
     140              65 : }
     141                 : 
     142                 : gfxASurface*
     143               0 : gfxASurface::GetSurfaceWrapper(cairo_surface_t *csurf)
     144                 : {
     145               0 :     if (!csurf)
     146               0 :         return NULL;
     147               0 :     return (gfxASurface*) cairo_surface_get_user_data(csurf, &gfxasurface_pointer_key);
     148                 : }
     149                 : 
     150                 : void
     151              65 : gfxASurface::SetSurfaceWrapper(cairo_surface_t *csurf, gfxASurface *asurf)
     152                 : {
     153              65 :     if (!csurf)
     154               0 :         return;
     155              65 :     cairo_surface_set_user_data(csurf, &gfxasurface_pointer_key, asurf, SurfaceDestroyFunc);
     156                 : }
     157                 : 
     158                 : already_AddRefed<gfxASurface>
     159               0 : gfxASurface::Wrap (cairo_surface_t *csurf)
     160                 : {
     161                 :     gfxASurface *result;
     162                 : 
     163                 :     /* Do we already have a wrapper for this surface? */
     164               0 :     result = GetSurfaceWrapper(csurf);
     165               0 :     if (result) {
     166                 :         // fprintf(stderr, "Existing wrapper for %p -> %p\n", csurf, result);
     167               0 :         NS_ADDREF(result);
     168               0 :         return result;
     169                 :     }
     170                 : 
     171                 :     /* No wrapper; figure out the surface type and create it */
     172               0 :     cairo_surface_type_t stype = cairo_surface_get_type(csurf);
     173                 : 
     174               0 :     if (stype == CAIRO_SURFACE_TYPE_IMAGE) {
     175               0 :         result = new gfxImageSurface(csurf);
     176                 :     }
     177                 : #ifdef CAIRO_HAS_WIN32_SURFACE
     178                 :     else if (stype == CAIRO_SURFACE_TYPE_WIN32 ||
     179                 :              stype == CAIRO_SURFACE_TYPE_WIN32_PRINTING) {
     180                 :         result = new gfxWindowsSurface(csurf);
     181                 :     }
     182                 : #endif
     183                 : #ifdef CAIRO_HAS_D2D_SURFACE
     184                 :     else if (stype == CAIRO_SURFACE_TYPE_D2D) {
     185                 :         result = new gfxD2DSurface(csurf);
     186                 :     }
     187                 : #endif
     188                 : #ifdef MOZ_X11
     189               0 :     else if (stype == CAIRO_SURFACE_TYPE_XLIB) {
     190               0 :         result = new gfxXlibSurface(csurf);
     191                 :     }
     192                 : #endif
     193                 : #ifdef CAIRO_HAS_QUARTZ_SURFACE
     194                 :     else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
     195                 :         result = new gfxQuartzSurface(csurf);
     196                 :     }
     197                 :     else if (stype == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
     198                 :         result = new gfxQuartzImageSurface(csurf);
     199                 :     }
     200                 : #endif
     201                 : #if defined(CAIRO_HAS_QT_SURFACE) && defined(MOZ_WIDGET_QT)
     202                 :     else if (stype == CAIRO_SURFACE_TYPE_QT) {
     203                 :         result = new gfxQPainterSurface(csurf);
     204                 :     }
     205                 : #endif
     206                 :     else {
     207               0 :         result = new gfxUnknownSurface(csurf);
     208                 :     }
     209                 : 
     210                 :     // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result);
     211                 : 
     212               0 :     NS_ADDREF(result);
     213               0 :     return result;
     214                 : }
     215                 : 
     216                 : void
     217              65 : gfxASurface::Init(cairo_surface_t* surface, bool existingSurface)
     218                 : {
     219              65 :     SetSurfaceWrapper(surface, this);
     220                 : 
     221              65 :     mSurface = surface;
     222              65 :     mSurfaceValid = surface && !cairo_surface_status(surface);
     223                 : 
     224              65 :     if (existingSurface || !mSurfaceValid) {
     225               0 :         mFloatingRefs = 0;
     226                 :     } else {
     227              65 :         mFloatingRefs = 1;
     228                 : #ifdef MOZ_TREE_CAIRO
     229              65 :         if (cairo_surface_get_content(surface) != CAIRO_CONTENT_COLOR) {
     230              51 :             cairo_surface_set_subpixel_antialiasing(surface, CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
     231                 :         }
     232                 : #endif
     233                 :     }
     234              65 : }
     235                 : 
     236                 : gfxASurface::gfxSurfaceType
     237             130 : gfxASurface::GetType() const
     238                 : {
     239             130 :     if (!mSurfaceValid)
     240               0 :         return (gfxSurfaceType)-1;
     241                 : 
     242             130 :     return (gfxSurfaceType)cairo_surface_get_type(mSurface);
     243                 : }
     244                 : 
     245                 : gfxASurface::gfxContentType
     246               0 : gfxASurface::GetContentType() const
     247                 : {
     248               0 :     if (!mSurfaceValid)
     249               0 :         return (gfxContentType)-1;
     250                 : 
     251               0 :     return (gfxContentType)cairo_surface_get_content(mSurface);
     252                 : }
     253                 : 
     254                 : void
     255               0 : gfxASurface::SetDeviceOffset(const gfxPoint& offset)
     256                 : {
     257               0 :     if (!mSurfaceValid)
     258               0 :         return;
     259                 :     cairo_surface_set_device_offset(mSurface,
     260               0 :                                     offset.x, offset.y);
     261                 : }
     262                 : 
     263                 : gfxPoint
     264               0 : gfxASurface::GetDeviceOffset() const
     265                 : {
     266               0 :     if (!mSurfaceValid)
     267               0 :         return gfxPoint(0.0, 0.0);
     268               0 :     gfxPoint pt;
     269               0 :     cairo_surface_get_device_offset(mSurface, &pt.x, &pt.y);
     270               0 :     return pt;
     271                 : }
     272                 : 
     273                 : void
     274              36 : gfxASurface::Flush() const
     275                 : {
     276              36 :     if (!mSurfaceValid)
     277               0 :         return;
     278              36 :     cairo_surface_flush(mSurface);
     279                 : }
     280                 : 
     281                 : void
     282              27 : gfxASurface::MarkDirty()
     283                 : {
     284              27 :     if (!mSurfaceValid)
     285               0 :         return;
     286              27 :     cairo_surface_mark_dirty(mSurface);
     287                 : }
     288                 : 
     289                 : void
     290               0 : gfxASurface::MarkDirty(const gfxRect& r)
     291                 : {
     292               0 :     if (!mSurfaceValid)
     293               0 :         return;
     294                 :     cairo_surface_mark_dirty_rectangle(mSurface,
     295               0 :                                        (int) r.X(), (int) r.Y(),
     296               0 :                                        (int) r.Width(), (int) r.Height());
     297                 : }
     298                 : 
     299                 : void
     300               0 : gfxASurface::SetData(const cairo_user_data_key_t *key,
     301                 :                      void *user_data,
     302                 :                      thebes_destroy_func_t destroy)
     303                 : {
     304               0 :     if (!mSurfaceValid)
     305               0 :         return;
     306               0 :     cairo_surface_set_user_data(mSurface, key, user_data, destroy);
     307                 : }
     308                 : 
     309                 : void *
     310               0 : gfxASurface::GetData(const cairo_user_data_key_t *key)
     311                 : {
     312               0 :     if (!mSurfaceValid)
     313               0 :         return NULL;
     314               0 :     return cairo_surface_get_user_data(mSurface, key);
     315                 : }
     316                 : 
     317                 : void
     318               0 : gfxASurface::Finish()
     319                 : {
     320                 :     // null surfaces are allowed here
     321               0 :     cairo_surface_finish(mSurface);
     322               0 : }
     323                 : 
     324                 : already_AddRefed<gfxASurface>
     325               0 : gfxASurface::CreateSimilarSurface(gfxContentType aContent,
     326                 :                                   const gfxIntSize& aSize)
     327                 : {
     328               0 :     if (!mSurface || !mSurfaceValid) {
     329               0 :       return nsnull;
     330                 :     }
     331                 :     
     332                 :     cairo_surface_t *surface =
     333                 :         cairo_surface_create_similar(mSurface, cairo_content_t(aContent),
     334               0 :                                      aSize.width, aSize.height);
     335               0 :     if (cairo_surface_status(surface)) {
     336               0 :         cairo_surface_destroy(surface);
     337               0 :         return nsnull;
     338                 :     }
     339                 : 
     340               0 :     nsRefPtr<gfxASurface> result = Wrap(surface);
     341               0 :     cairo_surface_destroy(surface);
     342               0 :     return result.forget();
     343                 : }
     344                 : 
     345                 : int
     346              48 : gfxASurface::CairoStatus()
     347                 : {
     348              48 :     if (!mSurfaceValid)
     349               0 :         return -1;
     350                 : 
     351              48 :     return cairo_surface_status(mSurface);
     352                 : }
     353                 : 
     354                 : /* static */
     355                 : bool
     356              65 : gfxASurface::CheckSurfaceSize(const gfxIntSize& sz, PRInt32 limit)
     357                 : {
     358              65 :     if (sz.width < 0 || sz.height < 0) {
     359               0 :         NS_WARNING("Surface width or height < 0!");
     360               0 :         return false;
     361                 :     }
     362                 : 
     363                 :     // reject images with sides bigger than limit
     364              65 :     if (limit && (sz.width > limit || sz.height > limit)) {
     365               0 :         NS_WARNING("Surface size too large (exceeds caller's limit)!");
     366               0 :         return false;
     367                 :     }
     368                 : 
     369                 : #if defined(XP_MACOSX)
     370                 :     // CoreGraphics is limited to images < 32K in *height*,
     371                 :     // so clamp all surfaces on the Mac to that height
     372                 :     if (sz.height > SHRT_MAX) {
     373                 :         NS_WARNING("Surface size too large (exceeds CoreGraphics limit)!");
     374                 :         return false;
     375                 :     }
     376                 : #endif
     377                 : 
     378                 :     // make sure the surface area doesn't overflow a PRInt32
     379              65 :     CheckedInt<PRInt32> tmp = sz.width;
     380              65 :     tmp *= sz.height;
     381              65 :     if (!tmp.valid()) {
     382               0 :         NS_WARNING("Surface size too large (would overflow)!");
     383               0 :         return false;
     384                 :     }
     385                 : 
     386                 :     // assuming 4-byte stride, make sure the allocation size
     387                 :     // doesn't overflow a PRInt32 either
     388              65 :     tmp *= 4;
     389              65 :     if (!tmp.valid()) {
     390               0 :         NS_WARNING("Allocation too large (would overflow)!");
     391               0 :         return false;
     392                 :     }
     393                 : 
     394              65 :     return true;
     395                 : }
     396                 : 
     397                 : /* static */
     398                 : PRInt32
     399               0 : gfxASurface::FormatStrideForWidth(gfxImageFormat format, PRInt32 width)
     400                 : {
     401               0 :     return cairo_format_stride_for_width((cairo_format_t)format, (int)width);
     402                 : }
     403                 : 
     404                 : nsresult
     405               0 : gfxASurface::BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName)
     406                 : {
     407               0 :     return NS_OK;
     408                 : }
     409                 : 
     410                 : nsresult
     411               0 : gfxASurface::EndPrinting()
     412                 : {
     413               0 :     return NS_OK;
     414                 : }
     415                 : 
     416                 : nsresult
     417               0 : gfxASurface::AbortPrinting()
     418                 : {
     419               0 :     return NS_OK;
     420                 : }
     421                 : 
     422                 : nsresult
     423               0 : gfxASurface::BeginPage()
     424                 : {
     425               0 :     return NS_OK;
     426                 : }
     427                 : 
     428                 : nsresult
     429               0 : gfxASurface::EndPage()
     430                 : {
     431               0 :     return NS_OK;
     432                 : }
     433                 : 
     434                 : gfxASurface::gfxContentType
     435              14 : gfxASurface::ContentFromFormat(gfxImageFormat format)
     436                 : {
     437              14 :     switch (format) {
     438                 :         case ImageFormatARGB32:
     439               7 :             return CONTENT_COLOR_ALPHA;
     440                 :         case ImageFormatRGB24:
     441                 :         case ImageFormatRGB16_565:
     442               7 :             return CONTENT_COLOR;
     443                 :         case ImageFormatA8:
     444                 :         case ImageFormatA1:
     445               0 :             return CONTENT_ALPHA;
     446                 : 
     447                 :         case ImageFormatUnknown:
     448                 :         default:
     449               0 :             return CONTENT_COLOR;
     450                 :     }
     451                 : }
     452                 : 
     453                 : gfxASurface::gfxImageFormat
     454              17 : gfxASurface::FormatFromContent(gfxASurface::gfxContentType type)
     455                 : {
     456              17 :     switch (type) {
     457                 :         case CONTENT_COLOR_ALPHA:
     458              10 :             return ImageFormatARGB32;
     459                 :         case CONTENT_ALPHA:
     460               0 :             return ImageFormatA8;
     461                 :         case CONTENT_COLOR:
     462                 :         default:
     463               7 :             return ImageFormatRGB24;
     464                 :     }
     465                 : }
     466                 : 
     467                 : void
     468               0 : gfxASurface::SetSubpixelAntialiasingEnabled(bool aEnabled)
     469                 : {
     470                 : #ifdef MOZ_TREE_CAIRO
     471               0 :     if (!mSurfaceValid)
     472               0 :         return;
     473                 :     cairo_surface_set_subpixel_antialiasing(mSurface,
     474               0 :         aEnabled ? CAIRO_SUBPIXEL_ANTIALIASING_ENABLED : CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
     475                 : #endif
     476                 : }
     477                 : 
     478                 : bool
     479               0 : gfxASurface::GetSubpixelAntialiasingEnabled()
     480                 : {
     481               0 :     if (!mSurfaceValid)
     482               0 :       return false;
     483                 : #ifdef MOZ_TREE_CAIRO
     484               0 :     return cairo_surface_get_subpixel_antialiasing(mSurface) == CAIRO_SUBPIXEL_ANTIALIASING_ENABLED;
     485                 : #else
     486                 :     return true;
     487                 : #endif
     488                 : }
     489                 : 
     490                 : gfxASurface::MemoryLocation
     491               6 : gfxASurface::GetMemoryLocation() const
     492                 : {
     493               6 :     return MEMORY_IN_PROCESS_HEAP;
     494                 : }
     495                 : 
     496                 : PRInt32
     497               0 : gfxASurface::BytePerPixelFromFormat(gfxImageFormat format)
     498                 : {
     499               0 :     switch (format) {
     500                 :         case ImageFormatARGB32:
     501                 :         case ImageFormatRGB24:
     502               0 :             return 4;
     503                 :         case ImageFormatRGB16_565:
     504               0 :             return 2;
     505                 :         case ImageFormatA8:
     506               0 :             return 1;
     507                 :         default:
     508               0 :             NS_WARNING("Unknown byte per pixel value for Image format");
     509                 :     }
     510               0 :     return 0;
     511                 : }
     512                 : 
     513                 : void
     514               0 : gfxASurface::FastMovePixels(const nsIntRect& aSourceRect,
     515                 :                             const nsIntPoint& aDestTopLeft)
     516                 : {
     517                 :     // Used when the backend can internally handle self copies.
     518               0 :     nsIntRect dest(aDestTopLeft, aSourceRect.Size());
     519                 :     
     520               0 :     nsRefPtr<gfxContext> ctx = new gfxContext(this);
     521               0 :     ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
     522               0 :     nsIntPoint srcOrigin = dest.TopLeft() - aSourceRect.TopLeft();
     523               0 :     ctx->SetSource(this, gfxPoint(srcOrigin.x, srcOrigin.y));
     524               0 :     ctx->Rectangle(gfxRect(dest.x, dest.y, dest.width, dest.height));
     525               0 :     ctx->Fill();
     526               0 : }
     527                 : 
     528                 : void
     529               0 : gfxASurface::MovePixels(const nsIntRect& aSourceRect,
     530                 :                         const nsIntPoint& aDestTopLeft)
     531                 : {
     532                 :     // Assume the backend can't handle self copying well and allocate
     533                 :     // a temporary surface instead.
     534                 :     nsRefPtr<gfxASurface> tmp = 
     535                 :       CreateSimilarSurface(GetContentType(), 
     536               0 :                            gfxIntSize(aSourceRect.width, aSourceRect.height));
     537               0 :     nsRefPtr<gfxContext> ctx = new gfxContext(tmp);
     538               0 :     ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
     539               0 :     ctx->SetSource(this, gfxPoint(-aSourceRect.x, -aSourceRect.y));
     540               0 :     ctx->Paint();
     541                 : 
     542               0 :     ctx = new gfxContext(this);
     543               0 :     ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
     544               0 :     ctx->SetSource(tmp, gfxPoint(aDestTopLeft.x, aDestTopLeft.y));
     545                 :     ctx->Rectangle(gfxRect(aDestTopLeft.x, 
     546                 :                            aDestTopLeft.y, 
     547                 :                            aSourceRect.width, 
     548               0 :                            aSourceRect.height));
     549               0 :     ctx->Fill();
     550               0 : }
     551                 : 
     552                 : /** Memory reporting **/
     553                 : 
     554                 : static const char *sDefaultSurfaceDescription =
     555                 :     "Memory used by gfx surface of the given type.";
     556                 : 
     557                 : struct SurfaceMemoryReporterAttrs {
     558                 :   const char *name;
     559                 :   const char *description;
     560                 : };
     561                 : 
     562                 : static const SurfaceMemoryReporterAttrs sSurfaceMemoryReporterAttrs[] = {
     563                 :     {"gfx-surface-image", nsnull},
     564                 :     {"gfx-surface-pdf", nsnull},
     565                 :     {"gfx-surface-ps", nsnull},
     566                 :     {"gfx-surface-xlib",
     567                 :      "Memory used by xlib surfaces to store pixmaps. This memory lives in "
     568                 :      "the X server's process rather than in this application, so the bytes "
     569                 :      "accounted for here aren't counted in vsize, resident, explicit, or any of "
     570                 :      "the other measurements on this page."},
     571                 :     {"gfx-surface-xcb", nsnull},
     572                 :     {"gfx-surface-glitz???", nsnull},       // should never be used
     573                 :     {"gfx-surface-quartz", nsnull},
     574                 :     {"gfx-surface-win32", nsnull},
     575                 :     {"gfx-surface-beos", nsnull},
     576                 :     {"gfx-surface-directfb???", nsnull},    // should never be used
     577                 :     {"gfx-surface-svg", nsnull},
     578                 :     {"gfx-surface-os2", nsnull},
     579                 :     {"gfx-surface-win32printing", nsnull},
     580                 :     {"gfx-surface-quartzimage", nsnull},
     581                 :     {"gfx-surface-script", nsnull},
     582                 :     {"gfx-surface-qpainter", nsnull},
     583                 :     {"gfx-surface-recording", nsnull},
     584                 :     {"gfx-surface-vg", nsnull},
     585                 :     {"gfx-surface-gl", nsnull},
     586                 :     {"gfx-surface-drm", nsnull},
     587                 :     {"gfx-surface-tee", nsnull},
     588                 :     {"gfx-surface-xml", nsnull},
     589                 :     {"gfx-surface-skia", nsnull},
     590                 :     {"gfx-surface-subsurface", nsnull},
     591                 :     {"gfx-surface-d2d", nsnull},
     592                 : };
     593                 : 
     594                 : PR_STATIC_ASSERT(NS_ARRAY_LENGTH(sSurfaceMemoryReporterAttrs) ==
     595                 :                  gfxASurface::SurfaceTypeMax);
     596                 : #ifdef CAIRO_HAS_D2D_SURFACE
     597                 : PR_STATIC_ASSERT(PRUint32(CAIRO_SURFACE_TYPE_D2D) ==
     598                 :                  PRUint32(gfxASurface::SurfaceTypeD2D));
     599                 : #endif
     600                 : PR_STATIC_ASSERT(PRUint32(CAIRO_SURFACE_TYPE_SKIA) ==
     601                 :                  PRUint32(gfxASurface::SurfaceTypeSkia));
     602                 : 
     603                 : static const char *
     604               0 : SurfaceMemoryReporterPathForType(gfxASurface::gfxSurfaceType aType)
     605                 : {
     606               0 :     if (aType < 0 ||
     607                 :         aType >= gfxASurface::SurfaceTypeMax)
     608               0 :         return "gfx-surface-unknown";
     609                 : 
     610               0 :     return sSurfaceMemoryReporterAttrs[aType].name;
     611                 : }
     612                 : 
     613                 : static const char *
     614               0 : SurfaceMemoryReporterDescriptionForType(gfxASurface::gfxSurfaceType aType)
     615                 : {
     616               0 :     if (aType >= 0 && aType < gfxASurface::SurfaceTypeMax &&
     617                 :         sSurfaceMemoryReporterAttrs[aType].description)
     618               0 :         return sSurfaceMemoryReporterAttrs[aType].description;
     619                 : 
     620               0 :     return sDefaultSurfaceDescription;
     621                 : }
     622                 : 
     623                 : /* Surface size memory reporting */
     624                 : static nsIMemoryReporter *gSurfaceMemoryReporters[gfxASurface::SurfaceTypeMax] = { 0 };
     625                 : static PRInt64 gSurfaceMemoryUsed[gfxASurface::SurfaceTypeMax] = { 0 };
     626                 : 
     627                 : class SurfaceMemoryReporter :
     628                 :     public nsIMemoryReporter
     629                 : {
     630                 : public:
     631               4 :     SurfaceMemoryReporter(gfxASurface::gfxSurfaceType aType)
     632               4 :         : mType(aType)
     633               4 :     { }
     634                 : 
     635                 :     NS_DECL_ISUPPORTS
     636                 : 
     637               0 :     NS_IMETHOD GetProcess(nsACString &process) {
     638               0 :         process.Truncate();
     639               0 :         return NS_OK;
     640                 :     }
     641                 : 
     642               0 :     NS_IMETHOD GetPath(nsACString &path) {
     643               0 :         path.Assign(SurfaceMemoryReporterPathForType(mType));
     644               0 :         return NS_OK;
     645                 :     }
     646                 : 
     647               0 :     NS_IMETHOD GetKind(PRInt32 *kind) {
     648               0 :         *kind = KIND_OTHER;
     649               0 :         return NS_OK;
     650                 :     }
     651                 :     
     652               0 :     NS_IMETHOD GetUnits(PRInt32 *units) {
     653               0 :         *units = UNITS_BYTES;
     654               0 :         return NS_OK;
     655                 :     }
     656                 : 
     657               0 :     NS_IMETHOD GetAmount(PRInt64 *amount) {
     658               0 :         *amount = gSurfaceMemoryUsed[mType];
     659               0 :         return NS_OK;
     660                 :     }
     661                 : 
     662               0 :     NS_IMETHOD GetDescription(nsACString &desc) {
     663               0 :         desc.Assign(SurfaceMemoryReporterDescriptionForType(mType));
     664               0 :         return NS_OK;
     665                 :     }
     666                 : 
     667                 :     gfxASurface::gfxSurfaceType mType;
     668                 : };
     669                 : 
     670              12 : NS_IMPL_ISUPPORTS1(SurfaceMemoryReporter, nsIMemoryReporter)
     671                 : 
     672                 : void
     673             130 : gfxASurface::RecordMemoryUsedForSurfaceType(gfxASurface::gfxSurfaceType aType,
     674                 :                                             PRInt32 aBytes)
     675                 : {
     676             130 :     if (aType < 0 || aType >= SurfaceTypeMax) {
     677               0 :         NS_WARNING("Invalid type to RecordMemoryUsedForSurfaceType!");
     678               0 :         return;
     679                 :     }
     680                 : 
     681             130 :     if (gSurfaceMemoryReporters[aType] == 0) {
     682               8 :         gSurfaceMemoryReporters[aType] = new SurfaceMemoryReporter(aType);
     683               4 :         NS_RegisterMemoryReporter(gSurfaceMemoryReporters[aType]);
     684                 :     }
     685                 : 
     686             130 :     gSurfaceMemoryUsed[aType] += aBytes;
     687                 : }
     688                 : 
     689                 : void
     690              65 : gfxASurface::RecordMemoryUsed(PRInt32 aBytes)
     691                 : {
     692              65 :     RecordMemoryUsedForSurfaceType(GetType(), aBytes);
     693              65 :     mBytesRecorded += aBytes;
     694              65 : }
     695                 : 
     696                 : void
     697              65 : gfxASurface::RecordMemoryFreed()
     698                 : {
     699              65 :     if (mBytesRecorded) {
     700              65 :         RecordMemoryUsedForSurfaceType(GetType(), -mBytesRecorded);
     701              65 :         mBytesRecorded = 0;
     702                 :     }
     703              65 : }
     704                 : 
     705                 : #ifdef MOZ_DUMP_PAINTING
     706                 : void
     707               0 : gfxASurface::WriteAsPNG(const char* aFile)
     708                 : {
     709               0 :     FILE *file = fopen(aFile, "wb");
     710               0 :     if (file) {
     711               0 :       WriteAsPNG_internal(file, true);
     712               0 :       fclose(file);
     713                 :     } else {
     714               0 :       NS_WARNING("Failed to create file!\n");
     715                 :     }
     716               0 : }
     717                 :     
     718                 : void 
     719               0 : gfxASurface::DumpAsDataURL(FILE* aOutput) 
     720                 : { 
     721               0 :   WriteAsPNG_internal(aOutput, false);
     722               0 : }
     723                 : 
     724                 : void
     725               0 : gfxASurface::PrintAsDataURL()
     726                 : {
     727               0 :   WriteAsPNG_internal(stdout, false);
     728               0 :   fprintf(stdout, "\n");
     729               0 : }
     730                 : 
     731                 : void 
     732               0 : gfxASurface::CopyAsDataURL() 
     733                 : { 
     734               0 :   WriteAsPNG_internal(nsnull, false);
     735               0 : }
     736                 : 
     737                 : /**
     738                 :  * Write to a PNG file. If aBinary is true, then it is written
     739                 :  * as binary, otherwise as a data URL. If no file is specified then
     740                 :  * data is copied to the clipboard (must not be binary!).
     741                 :  */
     742                 : void
     743               0 : gfxASurface::WriteAsPNG_internal(FILE* aFile, bool aBinary)
     744                 : {
     745               0 :   nsRefPtr<gfxImageSurface> imgsurf = GetAsImageSurface();
     746               0 :   gfxIntSize size;
     747                 : 
     748               0 :   if (!imgsurf) {
     749               0 :     size = GetSize();
     750               0 :     if (size.width == -1 && size.height == -1) {
     751               0 :       printf("Could not determine surface size\n");
     752                 :       return;
     753                 :     }
     754                 : 
     755                 :     imgsurf = 
     756                 :       new gfxImageSurface(gfxIntSize(size.width, size.height),
     757               0 :                           gfxASurface::ImageFormatARGB32);
     758                 : 
     759               0 :     if (!imgsurf || imgsurf->CairoStatus()) {
     760               0 :       printf("Could not allocate image surface\n");
     761                 :       return;
     762                 :     }
     763                 : 
     764               0 :     nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
     765               0 :     if (!ctx || ctx->HasError()) {
     766               0 :       printf("Could not allocate image context\n");
     767                 :       return;
     768                 :     }
     769                 : 
     770               0 :     ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
     771               0 :     ctx->SetSource(this, gfxPoint(0, 0));
     772               0 :     ctx->Paint();
     773                 :   }
     774               0 :   size = imgsurf->GetSize();
     775                 : 
     776                 :   nsCOMPtr<imgIEncoder> encoder =
     777               0 :     do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
     778               0 :   if (!encoder) {
     779               0 :     PRInt32 w = NS_MIN(size.width, 8);
     780               0 :     PRInt32 h = NS_MIN(size.height, 8);
     781               0 :     printf("Could not create encoder. Printing %dx%d pixels.\n", w, h);
     782               0 :     for (PRInt32 y = 0; y < h; ++y) {
     783               0 :       for (PRInt32 x = 0; x < w; ++x) {
     784               0 :         printf("%x ", reinterpret_cast<PRUint32*>(imgsurf->Data())[y*imgsurf->Stride()+ x]);
     785                 :       }
     786                 :     }
     787                 :     return;
     788                 :   }
     789                 : 
     790               0 :   nsresult rv = encoder->InitFromData(imgsurf->Data(),
     791                 :                                       size.width * size.height * 4, 
     792                 :                                       size.width, 
     793                 :                                       size.height, 
     794               0 :                                       imgsurf->Stride(),
     795                 :                                       imgIEncoder::INPUT_FORMAT_HOSTARGB,
     796               0 :                                       NS_LITERAL_STRING(""));
     797               0 :   if (NS_FAILED(rv))
     798                 :     return;
     799                 : 
     800               0 :   nsCOMPtr<nsIInputStream> imgStream;
     801               0 :   CallQueryInterface(encoder.get(), getter_AddRefs(imgStream));
     802               0 :   if (!imgStream)
     803                 :     return;
     804                 : 
     805                 :   PRUint32 bufSize;
     806               0 :   rv = imgStream->Available(&bufSize);
     807               0 :   if (NS_FAILED(rv))
     808                 :     return;
     809                 : 
     810                 :   // ...leave a little extra room so we can call read again and make sure we
     811                 :   // got everything. 16 bytes for better padding (maybe)
     812               0 :   bufSize += 16;
     813               0 :   PRUint32 imgSize = 0;
     814               0 :   char* imgData = (char*)PR_Malloc(bufSize);
     815               0 :   if (!imgData)
     816                 :     return;
     817               0 :   PRUint32 numReadThisTime = 0;
     818               0 :   while ((rv = imgStream->Read(&imgData[imgSize], 
     819                 :                                bufSize - imgSize,
     820               0 :                                &numReadThisTime)) == NS_OK && numReadThisTime > 0) 
     821                 :   {
     822               0 :     imgSize += numReadThisTime;
     823               0 :     if (imgSize == bufSize) {
     824                 :       // need a bigger buffer, just double
     825               0 :       bufSize *= 2;
     826               0 :       char* newImgData = (char*)PR_Realloc(imgData, bufSize);
     827               0 :       if (!newImgData) {
     828               0 :         PR_Free(imgData);
     829                 :         return;
     830                 :       }
     831               0 :       imgData = newImgData;
     832                 :     }
     833                 :   }
     834                 : 
     835               0 :   if (aBinary) {
     836               0 :     if (aFile) {
     837               0 :       fwrite(imgData, 1, imgSize, aFile); 
     838                 :     } else {
     839               0 :       NS_WARNING("Can't write binary image data without a file!");
     840                 :     }
     841                 :     return;
     842                 :   }
     843                 :   
     844                 :   // base 64, result will be NULL terminated
     845               0 :   char* encodedImg = PL_Base64Encode(imgData, imgSize, nsnull);
     846               0 :   PR_Free(imgData);
     847               0 :   if (!encodedImg) // not sure why this would fail
     848                 :     return;
     849                 : 
     850               0 :   nsCString string("data:image/png;base64,");
     851               0 :   string.Append(encodedImg);
     852                 : 
     853               0 :   if (aFile) {
     854               0 :     fprintf(aFile, "%s", string.BeginReading());
     855                 :   } else {
     856               0 :     nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
     857               0 :     if (clipboard) {
     858               0 :       clipboard->CopyString(NS_ConvertASCIItoUTF16(string));
     859                 :     }
     860                 :   }
     861                 : 
     862               0 :   PR_Free(encodedImg);
     863                 : 
     864                 :   return;
     865                 : }
     866                 : #endif
     867                 : 

Generated by: LCOV version 1.7