tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gfxASurface.cpp (14279B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "nsIMemoryReporter.h"
      7 #include "mozilla/Base64.h"
      8 #include "mozilla/MemoryReporting.h"
      9 #include "nsISupportsImpl.h"
     10 #include "mozilla/gfx/2D.h"
     11 #include "mozilla/gfx/Logging.h"
     12 #include "mozilla/gfx/HelpersCairo.h"
     13 #include "gfx2DGlue.h"
     14 
     15 #include "gfxASurface.h"
     16 #include "gfxContext.h"
     17 #include "gfxImageSurface.h"
     18 #include "gfxPlatform.h"
     19 #include "gfxRect.h"
     20 
     21 #include "cairo.h"
     22 
     23 #ifdef CAIRO_HAS_WIN32_SURFACE
     24 #  include "gfxWindowsSurface.h"
     25 #endif
     26 
     27 #ifdef MOZ_X11
     28 #  include "gfxXlibSurface.h"
     29 #endif
     30 
     31 #ifdef CAIRO_HAS_QUARTZ_SURFACE
     32 #  include "gfxQuartzSurface.h"
     33 #endif
     34 
     35 #include <stdio.h>
     36 #include <limits.h>
     37 
     38 #include "nsComponentManagerUtils.h"
     39 #include "nsISupportsUtils.h"
     40 #include "nsCOMPtr.h"
     41 #include "nsServiceManagerUtils.h"
     42 #include "nsString.h"
     43 
     44 using namespace mozilla;
     45 using namespace mozilla::gfx;
     46 
     47 static cairo_user_data_key_t gfxasurface_pointer_key;
     48 
     49 gfxASurface::gfxASurface()
     50    : mSurface(nullptr),
     51      mFloatingRefs(0),
     52      mBytesRecorded(0),
     53      mSurfaceValid(false) {
     54  MOZ_COUNT_CTOR(gfxASurface);
     55 }
     56 
     57 gfxASurface::~gfxASurface() {
     58  RecordMemoryFreed();
     59 
     60  MOZ_COUNT_DTOR(gfxASurface);
     61 }
     62 
     63 // Surfaces use refcounting that's tied to the cairo surface refcnt, to avoid
     64 // refcount mismatch issues.
     65 nsrefcnt gfxASurface::AddRef(void) {
     66  if (mSurfaceValid) {
     67    if (mFloatingRefs) {
     68      // eat a floating ref
     69      mFloatingRefs--;
     70    } else {
     71      cairo_surface_reference(mSurface);
     72    }
     73 
     74    return (nsrefcnt)cairo_surface_get_reference_count(mSurface);
     75  }
     76  // the surface isn't valid, but we still need to refcount
     77  // the gfxASurface
     78  return ++mFloatingRefs;
     79 }
     80 
     81 nsrefcnt gfxASurface::Release(void) {
     82  if (mSurfaceValid) {
     83    NS_ASSERTION(
     84        mFloatingRefs == 0,
     85        "gfxASurface::Release with floating refs still hanging around!");
     86 
     87    // Note that there is a destructor set on user data for mSurface,
     88    // which will delete this gfxASurface wrapper when the surface's refcount
     89    // goes out of scope.
     90    nsrefcnt refcnt = (nsrefcnt)cairo_surface_get_reference_count(mSurface);
     91    cairo_surface_destroy(mSurface);
     92 
     93    // |this| may not be valid any more, don't use it!
     94 
     95    return --refcnt;
     96  }
     97  if (--mFloatingRefs == 0) {
     98    delete this;
     99    return 0;
    100  }
    101  return mFloatingRefs;
    102 }
    103 
    104 void gfxASurface::SurfaceDestroyFunc(void* data) {
    105  gfxASurface* surf = (gfxASurface*)data;
    106  // fprintf (stderr, "Deleting wrapper for %p (wrapper: %p)\n", surf->mSurface,
    107  //          data);
    108  delete surf;
    109 }
    110 
    111 gfxASurface* gfxASurface::GetSurfaceWrapper(cairo_surface_t* csurf) {
    112  if (!csurf) return nullptr;
    113  return (gfxASurface*)cairo_surface_get_user_data(csurf,
    114                                                   &gfxasurface_pointer_key);
    115 }
    116 
    117 void gfxASurface::SetSurfaceWrapper(cairo_surface_t* csurf,
    118                                    gfxASurface* asurf) {
    119  if (!csurf) return;
    120  cairo_surface_set_user_data(csurf, &gfxasurface_pointer_key, asurf,
    121                              SurfaceDestroyFunc);
    122 }
    123 
    124 already_AddRefed<gfxASurface> gfxASurface::Wrap(cairo_surface_t* csurf,
    125                                                const IntSize& aSize) {
    126  RefPtr<gfxASurface> result;
    127 
    128  /* Do we already have a wrapper for this surface? */
    129  result = GetSurfaceWrapper(csurf);
    130  if (result) {
    131    // fprintf(stderr, "Existing wrapper for %p -> %p\n", csurf, result);
    132    return result.forget();
    133  }
    134 
    135  /* No wrapper; figure out the surface type and create it */
    136  cairo_surface_type_t stype = cairo_surface_get_type(csurf);
    137 
    138  if (stype == CAIRO_SURFACE_TYPE_IMAGE) {
    139    result = new gfxImageSurface(csurf);
    140  }
    141 #ifdef CAIRO_HAS_WIN32_SURFACE
    142  else if (stype == CAIRO_SURFACE_TYPE_WIN32 ||
    143           stype == CAIRO_SURFACE_TYPE_WIN32_PRINTING) {
    144    result = new gfxWindowsSurface(csurf);
    145  }
    146 #endif
    147 #ifdef MOZ_X11
    148  else if (stype == CAIRO_SURFACE_TYPE_XLIB) {
    149    result = new gfxXlibSurface(csurf);
    150  }
    151 #endif
    152 #ifdef CAIRO_HAS_QUARTZ_SURFACE
    153  else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
    154    result = new gfxQuartzSurface(csurf, aSize);
    155  }
    156 #endif
    157  else {
    158    result = new gfxUnknownSurface(csurf, aSize);
    159  }
    160 
    161  // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result);
    162 
    163  return result.forget();
    164 }
    165 
    166 void gfxASurface::Init(cairo_surface_t* surface, bool existingSurface) {
    167  SetSurfaceWrapper(surface, this);
    168  MOZ_ASSERT(surface, "surface should be a valid pointer");
    169 
    170  mSurface = surface;
    171  mSurfaceValid = !cairo_surface_status(surface);
    172  if (!mSurfaceValid) {
    173    gfxWarning() << "ASurface Init failed with Cairo status "
    174                 << cairo_surface_status(surface) << " on " << hexa(surface);
    175  }
    176 
    177  if (existingSurface || !mSurfaceValid) {
    178    mFloatingRefs = 0;
    179  } else {
    180    mFloatingRefs = 1;
    181    if (cairo_surface_get_content(surface) != CAIRO_CONTENT_COLOR) {
    182      cairo_surface_set_subpixel_antialiasing(
    183          surface, CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
    184    }
    185  }
    186 }
    187 
    188 gfxSurfaceType gfxASurface::GetType() const {
    189  if (!mSurfaceValid) return (gfxSurfaceType)-1;
    190 
    191  return (gfxSurfaceType)cairo_surface_get_type(mSurface);
    192 }
    193 
    194 gfxContentType gfxASurface::GetContentType() const {
    195  if (!mSurfaceValid) return (gfxContentType)-1;
    196 
    197  return (gfxContentType)cairo_surface_get_content(mSurface);
    198 }
    199 
    200 void gfxASurface::SetDeviceOffset(const gfxPoint& offset) {
    201  if (!mSurfaceValid) return;
    202  cairo_surface_set_device_offset(mSurface, offset.x, offset.y);
    203 }
    204 
    205 gfxPoint gfxASurface::GetDeviceOffset() const {
    206  if (!mSurfaceValid) return gfxPoint(0.0, 0.0);
    207  gfxPoint pt;
    208  cairo_surface_get_device_offset(mSurface, &pt.x.value, &pt.y.value);
    209  return pt;
    210 }
    211 
    212 void gfxASurface::Flush() const {
    213  if (!mSurfaceValid) return;
    214  cairo_surface_flush(mSurface);
    215  gfxPlatform::ClearSourceSurfaceForSurface(const_cast<gfxASurface*>(this));
    216 }
    217 
    218 void gfxASurface::MarkDirty() {
    219  if (!mSurfaceValid) return;
    220  cairo_surface_mark_dirty(mSurface);
    221  gfxPlatform::ClearSourceSurfaceForSurface(this);
    222 }
    223 
    224 void gfxASurface::MarkDirty(const gfxRect& r) {
    225  if (!mSurfaceValid) return;
    226  cairo_surface_mark_dirty_rectangle(mSurface, (int)r.X(), (int)r.Y(),
    227                                     (int)r.Width(), (int)r.Height());
    228  gfxPlatform::ClearSourceSurfaceForSurface(this);
    229 }
    230 
    231 void gfxASurface::SetData(const cairo_user_data_key_t* key, void* user_data,
    232                          thebes_destroy_func_t destroy) {
    233  if (!mSurfaceValid) return;
    234  cairo_surface_set_user_data(mSurface, key, user_data, destroy);
    235 }
    236 
    237 void* gfxASurface::GetData(const cairo_user_data_key_t* key) {
    238  if (!mSurfaceValid) return nullptr;
    239  return cairo_surface_get_user_data(mSurface, key);
    240 }
    241 
    242 void gfxASurface::Finish() {
    243  // null surfaces are allowed here
    244  cairo_surface_finish(mSurface);
    245 }
    246 
    247 int gfxASurface::CairoStatus() {
    248  if (!mSurfaceValid) return -1;
    249 
    250  return cairo_surface_status(mSurface);
    251 }
    252 
    253 nsresult gfxASurface::BeginPrinting(const nsAString& aTitle,
    254                                    const nsAString& aPrintToFileName) {
    255  return NS_OK;
    256 }
    257 
    258 nsresult gfxASurface::EndPrinting() { return NS_OK; }
    259 
    260 nsresult gfxASurface::AbortPrinting() { return NS_OK; }
    261 
    262 nsresult gfxASurface::BeginPage() { return NS_OK; }
    263 
    264 nsresult gfxASurface::EndPage() { return NS_OK; }
    265 
    266 gfxContentType gfxASurface::ContentFromFormat(gfxImageFormat format) {
    267  switch (format) {
    268    case SurfaceFormat::A8R8G8B8_UINT32:
    269      return gfxContentType::COLOR_ALPHA;
    270    case SurfaceFormat::X8R8G8B8_UINT32:
    271    case SurfaceFormat::R5G6B5_UINT16:
    272      return gfxContentType::COLOR;
    273    case SurfaceFormat::A8:
    274      return gfxContentType::ALPHA;
    275 
    276    case SurfaceFormat::UNKNOWN:
    277    default:
    278      return gfxContentType::COLOR;
    279  }
    280 }
    281 
    282 int32_t gfxASurface::BytePerPixelFromFormat(gfxImageFormat format) {
    283  switch (format) {
    284    case SurfaceFormat::A8R8G8B8_UINT32:
    285    case SurfaceFormat::X8R8G8B8_UINT32:
    286      return 4;
    287    case SurfaceFormat::R5G6B5_UINT16:
    288      return 2;
    289    case SurfaceFormat::A8:
    290      return 1;
    291    default:
    292      NS_WARNING("Unknown byte per pixel value for Image format");
    293  }
    294  return 0;
    295 }
    296 
    297 /** Memory reporting **/
    298 
    299 static const char* sDefaultSurfaceDescription =
    300    "Memory used by gfx surface of the given type.";
    301 
    302 struct SurfaceMemoryReporterAttrs {
    303  const char* path;
    304  const char* description;
    305 };
    306 
    307 static const SurfaceMemoryReporterAttrs sSurfaceMemoryReporterAttrs[] = {
    308    {"gfx-surface-image", nullptr},
    309    {"gfx-surface-pdf", nullptr},
    310    {"gfx-surface-ps", nullptr},
    311    {"gfx-surface-xlib",
    312     "Memory used by xlib surfaces to store pixmaps. This memory lives in "
    313     "the X server's process rather than in this application, so the bytes "
    314     "accounted for here aren't counted in vsize, resident, explicit, or any "
    315     "of "
    316     "the other measurements on this page."},
    317    {"gfx-surface-xcb", nullptr},
    318    {"gfx-surface-glitz???", nullptr},  // should never be used
    319    {"gfx-surface-quartz", nullptr},
    320    {"gfx-surface-win32", nullptr},
    321    {"gfx-surface-beos", nullptr},
    322    {"gfx-surface-directfb???", nullptr},  // should never be used
    323    {"gfx-surface-svg", nullptr},
    324    {"gfx-surface-os2", nullptr},
    325    {"gfx-surface-win32printing", nullptr},
    326    {"gfx-surface-quartzimage", nullptr},
    327    {"gfx-surface-script", nullptr},
    328    {"gfx-surface-qpainter", nullptr},
    329    {"gfx-surface-recording", nullptr},
    330    {"gfx-surface-vg", nullptr},
    331    {"gfx-surface-gl", nullptr},
    332    {"gfx-surface-drm", nullptr},
    333    {"gfx-surface-tee", nullptr},
    334    {"gfx-surface-xml", nullptr},
    335    {"gfx-surface-skia", nullptr},
    336    {"gfx-surface-subsurface", nullptr},
    337 };
    338 
    339 static_assert(std::size(sSurfaceMemoryReporterAttrs) ==
    340                  size_t(gfxSurfaceType::Max),
    341              "sSurfaceMemoryReporterAttrs exceeds max capacity");
    342 static_assert(uint32_t(CAIRO_SURFACE_TYPE_SKIA) ==
    343                  uint32_t(gfxSurfaceType::Skia),
    344              "CAIRO_SURFACE_TYPE_SKIA not equal to gfxSurfaceType::Skia");
    345 
    346 /* Surface size memory reporting */
    347 
    348 class SurfaceMemoryReporter final : public nsIMemoryReporter {
    349  ~SurfaceMemoryReporter() = default;
    350 
    351  // We can touch this array on several different threads, and we don't
    352  // want to introduce memory barriers when recording the memory used.  To
    353  // assure dynamic race checkers like TSan that this is OK, we use
    354  // relaxed memory ordering here.
    355  static Atomic<size_t, Relaxed>
    356      sSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)];
    357 
    358 public:
    359  static void AdjustUsedMemory(gfxSurfaceType aType, int32_t aBytes) {
    360    // A read-modify-write operation like += would require a memory barrier
    361    // here, which would defeat the purpose of using relaxed memory
    362    // ordering.  So separate out the read and write operations.
    363    sSurfaceMemoryUsed[size_t(aType)] =
    364        sSurfaceMemoryUsed[size_t(aType)] + aBytes;
    365  };
    366 
    367  // This memory reporter is sometimes allocated on the compositor thread,
    368  // but always released on the main thread, so its refcounting needs to be
    369  // threadsafe.
    370  NS_DECL_THREADSAFE_ISUPPORTS
    371 
    372  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
    373                            nsISupports* aData, bool aAnonymize) override {
    374    const size_t len = std::size(sSurfaceMemoryReporterAttrs);
    375    for (size_t i = 0; i < len; i++) {
    376      int64_t amount = sSurfaceMemoryUsed[i];
    377 
    378      if (amount != 0) {
    379        const char* path = sSurfaceMemoryReporterAttrs[i].path;
    380        const char* desc = sSurfaceMemoryReporterAttrs[i].description;
    381        if (!desc) {
    382          desc = sDefaultSurfaceDescription;
    383        }
    384 
    385        aHandleReport->Callback(""_ns, nsCString(path), KIND_OTHER, UNITS_BYTES,
    386                                amount, nsCString(desc), aData);
    387      }
    388    }
    389 
    390    return NS_OK;
    391  }
    392 };
    393 
    394 Atomic<size_t, Relaxed>
    395    SurfaceMemoryReporter::sSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)];
    396 
    397 NS_IMPL_ISUPPORTS(SurfaceMemoryReporter, nsIMemoryReporter)
    398 
    399 void gfxASurface::RecordMemoryUsedForSurfaceType(gfxSurfaceType aType,
    400                                                 int32_t aBytes) {
    401  if (int(aType) < 0 || aType >= gfxSurfaceType::Max) {
    402    NS_WARNING("Invalid type to RecordMemoryUsedForSurfaceType!");
    403    return;
    404  }
    405 
    406  static bool registered = false;
    407  if (!registered) {
    408    RegisterStrongMemoryReporter(new SurfaceMemoryReporter());
    409    registered = true;
    410  }
    411 
    412  SurfaceMemoryReporter::AdjustUsedMemory(aType, aBytes);
    413 }
    414 
    415 void gfxASurface::RecordMemoryUsed(int32_t aBytes) {
    416  RecordMemoryUsedForSurfaceType(GetType(), aBytes);
    417  mBytesRecorded += aBytes;
    418 }
    419 
    420 void gfxASurface::RecordMemoryFreed() {
    421  if (mBytesRecorded) {
    422    RecordMemoryUsedForSurfaceType(GetType(), -mBytesRecorded);
    423    mBytesRecorded = 0;
    424  }
    425 }
    426 
    427 size_t gfxASurface::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
    428  // We don't measure mSurface because cairo doesn't allow it.
    429  return 0;
    430 }
    431 
    432 size_t gfxASurface::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    433  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    434 }
    435 
    436 /* static */
    437 uint8_t gfxASurface::BytesPerPixel(gfxImageFormat aImageFormat) {
    438  switch (aImageFormat) {
    439    case SurfaceFormat::A8R8G8B8_UINT32:
    440      return 4;
    441    case SurfaceFormat::X8R8G8B8_UINT32:
    442      return 4;
    443    case SurfaceFormat::R5G6B5_UINT16:
    444      return 2;
    445    case SurfaceFormat::A8:
    446      return 1;
    447    case SurfaceFormat::UNKNOWN:
    448    default:
    449      MOZ_ASSERT_UNREACHABLE("Not really sure what you want me to say here");
    450      return 0;
    451  }
    452 }
    453 
    454 void gfxASurface::SetOpaqueRect(const gfxRect& aRect) {
    455  if (aRect.IsEmpty()) {
    456    mOpaqueRect = nullptr;
    457  } else if (!!mOpaqueRect) {
    458    *mOpaqueRect = aRect;
    459  } else {
    460    mOpaqueRect = MakeUnique<gfxRect>(aRect);
    461  }
    462 }
    463 
    464 /* static */ const gfxRect& gfxASurface::GetEmptyOpaqueRect() {
    465  static const gfxRect empty(0, 0, 0, 0);
    466  return empty;
    467 }
    468 
    469 const IntSize gfxASurface::GetSize() const { return IntSize(-1, -1); }
    470 
    471 SurfaceFormat gfxASurface::GetSurfaceFormat() const {
    472  if (!mSurfaceValid) {
    473    return SurfaceFormat::UNKNOWN;
    474  }
    475  return GfxFormatForCairoSurface(mSurface);
    476 }
    477 
    478 already_AddRefed<gfxImageSurface> gfxASurface::GetAsImageSurface() {
    479  return nullptr;
    480 }