gecko-dev/gfx/thebes/gfxASurface.cpp
Gabriele Svelto 69790bc62e Bug 1600545 - Remove useless inclusions of header files generated from IDL files in accessible/, browser/, caps/, chrome/, devtools/, docshell/, editor/, extensions/, gfx/, hal/, image/, intl/, ipc/, js/, layout/, and media/ r=Ehsan
The inclusions were removed with the following very crude script and the
resulting breakage was fixed up by hand. The manual fixups did either
revert the changes done by the script, replace a generic header with a more
specific one or replace a header with a forward declaration.

find . -name "*.idl" | grep -v web-platform | grep -v third_party | while read path; do
    interfaces=$(grep "^\(class\|interface\).*:.*" "$path" | cut -d' ' -f2)
    if [ -n "$interfaces" ]; then
        if [[ "$interfaces" == *$'\n'* ]]; then
          regexp="\("
          for i in $interfaces; do regexp="$regexp$i\|"; done
          regexp="${regexp%%\\\|}\)"
        else
          regexp="$interfaces"
        fi
        interface=$(basename "$path")
        rg -l "#include.*${interface%%.idl}.h" . | while read path2; do
            hits=$(grep -v "#include.*${interface%%.idl}.h" "$path2" | grep -c "$regexp" )
            if [ $hits -eq 0 ]; then
                echo "Removing ${interface} from ${path2}"
                grep -v "#include.*${interface%%.idl}.h" "$path2" > "$path2".tmp
                mv -f "$path2".tmp "$path2"
            fi
        done
    fi
done

Differential Revision: https://phabricator.services.mozilla.com/D55443

--HG--
extra : moz-landing-system : lando
2019-12-06 09:16:44 +00:00

525 lines
15 KiB
C++

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIMemoryReporter.h"
#include "nsMemory.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Base64.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "nsISupportsImpl.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/HelpersCairo.h"
#include "gfx2DGlue.h"
#include "gfxASurface.h"
#include "gfxContext.h"
#include "gfxImageSurface.h"
#include "gfxPlatform.h"
#include "gfxRect.h"
#include "cairo.h"
#include <algorithm>
#ifdef CAIRO_HAS_WIN32_SURFACE
# include "gfxWindowsSurface.h"
#endif
#ifdef MOZ_X11
# include "gfxXlibSurface.h"
#endif
#ifdef CAIRO_HAS_QUARTZ_SURFACE
# include "gfxQuartzSurface.h"
#endif
#include <stdio.h>
#include <limits.h>
#include "nsComponentManagerUtils.h"
#include "nsISupportsUtils.h"
#include "nsCOMPtr.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
using namespace mozilla;
using namespace mozilla::gfx;
static cairo_user_data_key_t gfxasurface_pointer_key;
gfxASurface::gfxASurface()
: mSurface(nullptr),
mFloatingRefs(0),
mBytesRecorded(0),
mSurfaceValid(false) {
MOZ_COUNT_CTOR(gfxASurface);
}
gfxASurface::~gfxASurface() {
RecordMemoryFreed();
MOZ_COUNT_DTOR(gfxASurface);
}
// Surfaces use refcounting that's tied to the cairo surface refcnt, to avoid
// refcount mismatch issues.
nsrefcnt gfxASurface::AddRef(void) {
if (mSurfaceValid) {
if (mFloatingRefs) {
// eat a floating ref
mFloatingRefs--;
} else {
cairo_surface_reference(mSurface);
}
return (nsrefcnt)cairo_surface_get_reference_count(mSurface);
}
// the surface isn't valid, but we still need to refcount
// the gfxASurface
return ++mFloatingRefs;
}
nsrefcnt gfxASurface::Release(void) {
if (mSurfaceValid) {
NS_ASSERTION(
mFloatingRefs == 0,
"gfxASurface::Release with floating refs still hanging around!");
// Note that there is a destructor set on user data for mSurface,
// which will delete this gfxASurface wrapper when the surface's refcount
// goes out of scope.
nsrefcnt refcnt = (nsrefcnt)cairo_surface_get_reference_count(mSurface);
cairo_surface_destroy(mSurface);
// |this| may not be valid any more, don't use it!
return --refcnt;
}
if (--mFloatingRefs == 0) {
delete this;
return 0;
}
return mFloatingRefs;
}
void gfxASurface::SurfaceDestroyFunc(void* data) {
gfxASurface* surf = (gfxASurface*)data;
// fprintf (stderr, "Deleting wrapper for %p (wrapper: %p)\n", surf->mSurface,
// data);
delete surf;
}
gfxASurface* gfxASurface::GetSurfaceWrapper(cairo_surface_t* csurf) {
if (!csurf) return nullptr;
return (gfxASurface*)cairo_surface_get_user_data(csurf,
&gfxasurface_pointer_key);
}
void gfxASurface::SetSurfaceWrapper(cairo_surface_t* csurf,
gfxASurface* asurf) {
if (!csurf) return;
cairo_surface_set_user_data(csurf, &gfxasurface_pointer_key, asurf,
SurfaceDestroyFunc);
}
already_AddRefed<gfxASurface> gfxASurface::Wrap(cairo_surface_t* csurf,
const IntSize& aSize) {
RefPtr<gfxASurface> result;
/* Do we already have a wrapper for this surface? */
result = GetSurfaceWrapper(csurf);
if (result) {
// fprintf(stderr, "Existing wrapper for %p -> %p\n", csurf, result);
return result.forget();
}
/* No wrapper; figure out the surface type and create it */
cairo_surface_type_t stype = cairo_surface_get_type(csurf);
if (stype == CAIRO_SURFACE_TYPE_IMAGE) {
result = new gfxImageSurface(csurf);
}
#ifdef CAIRO_HAS_WIN32_SURFACE
else if (stype == CAIRO_SURFACE_TYPE_WIN32 ||
stype == CAIRO_SURFACE_TYPE_WIN32_PRINTING) {
result = new gfxWindowsSurface(csurf);
}
#endif
#ifdef MOZ_X11
else if (stype == CAIRO_SURFACE_TYPE_XLIB) {
result = new gfxXlibSurface(csurf);
}
#endif
#ifdef CAIRO_HAS_QUARTZ_SURFACE
else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
result = new gfxQuartzSurface(csurf, aSize);
}
#endif
else {
result = new gfxUnknownSurface(csurf, aSize);
}
// fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result);
return result.forget();
}
void gfxASurface::Init(cairo_surface_t* surface, bool existingSurface) {
SetSurfaceWrapper(surface, this);
MOZ_ASSERT(surface, "surface should be a valid pointer");
mSurface = surface;
mSurfaceValid = !cairo_surface_status(surface);
if (!mSurfaceValid) {
gfxWarning() << "ASurface Init failed with Cairo status "
<< cairo_surface_status(surface) << " on " << hexa(surface);
}
if (existingSurface || !mSurfaceValid) {
mFloatingRefs = 0;
} else {
mFloatingRefs = 1;
#ifdef MOZ_TREE_CAIRO
if (cairo_surface_get_content(surface) != CAIRO_CONTENT_COLOR) {
cairo_surface_set_subpixel_antialiasing(
surface, CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
}
#endif
}
}
gfxSurfaceType gfxASurface::GetType() const {
if (!mSurfaceValid) return (gfxSurfaceType)-1;
return (gfxSurfaceType)cairo_surface_get_type(mSurface);
}
gfxContentType gfxASurface::GetContentType() const {
if (!mSurfaceValid) return (gfxContentType)-1;
return (gfxContentType)cairo_surface_get_content(mSurface);
}
void gfxASurface::SetDeviceOffset(const gfxPoint& offset) {
if (!mSurfaceValid) return;
cairo_surface_set_device_offset(mSurface, offset.x, offset.y);
}
gfxPoint gfxASurface::GetDeviceOffset() const {
if (!mSurfaceValid) return gfxPoint(0.0, 0.0);
gfxPoint pt;
cairo_surface_get_device_offset(mSurface, &pt.x, &pt.y);
return pt;
}
void gfxASurface::Flush() const {
if (!mSurfaceValid) return;
cairo_surface_flush(mSurface);
gfxPlatform::ClearSourceSurfaceForSurface(const_cast<gfxASurface*>(this));
}
void gfxASurface::MarkDirty() {
if (!mSurfaceValid) return;
cairo_surface_mark_dirty(mSurface);
gfxPlatform::ClearSourceSurfaceForSurface(this);
}
void gfxASurface::MarkDirty(const gfxRect& r) {
if (!mSurfaceValid) return;
cairo_surface_mark_dirty_rectangle(mSurface, (int)r.X(), (int)r.Y(),
(int)r.Width(), (int)r.Height());
gfxPlatform::ClearSourceSurfaceForSurface(this);
}
void gfxASurface::SetData(const cairo_user_data_key_t* key, void* user_data,
thebes_destroy_func_t destroy) {
if (!mSurfaceValid) return;
cairo_surface_set_user_data(mSurface, key, user_data, destroy);
}
void* gfxASurface::GetData(const cairo_user_data_key_t* key) {
if (!mSurfaceValid) return nullptr;
return cairo_surface_get_user_data(mSurface, key);
}
void gfxASurface::Finish() {
// null surfaces are allowed here
cairo_surface_finish(mSurface);
}
already_AddRefed<gfxASurface> gfxASurface::CreateSimilarSurface(
gfxContentType aContent, const IntSize& aSize) {
if (!mSurface || !mSurfaceValid) {
return nullptr;
}
cairo_surface_t* surface = cairo_surface_create_similar(
mSurface, cairo_content_t(int(aContent)), aSize.width, aSize.height);
if (cairo_surface_status(surface)) {
cairo_surface_destroy(surface);
return nullptr;
}
RefPtr<gfxASurface> result = Wrap(surface, aSize);
cairo_surface_destroy(surface);
return result.forget();
}
already_AddRefed<gfxImageSurface> gfxASurface::CopyToARGB32ImageSurface() {
if (!mSurface || !mSurfaceValid) {
return nullptr;
}
const IntSize size = GetSize();
RefPtr<gfxImageSurface> imgSurface =
new gfxImageSurface(size, SurfaceFormat::A8R8G8B8_UINT32);
RefPtr<DrawTarget> dt = gfxPlatform::CreateDrawTargetForSurface(
imgSurface, IntSize(size.width, size.height));
RefPtr<SourceSurface> source =
gfxPlatform::GetSourceSurfaceForSurface(dt, this);
dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint());
return imgSurface.forget();
}
int gfxASurface::CairoStatus() {
if (!mSurfaceValid) return -1;
return cairo_surface_status(mSurface);
}
nsresult gfxASurface::BeginPrinting(const nsAString& aTitle,
const nsAString& aPrintToFileName) {
return NS_OK;
}
nsresult gfxASurface::EndPrinting() { return NS_OK; }
nsresult gfxASurface::AbortPrinting() { return NS_OK; }
nsresult gfxASurface::BeginPage() { return NS_OK; }
nsresult gfxASurface::EndPage() { return NS_OK; }
gfxContentType gfxASurface::ContentFromFormat(gfxImageFormat format) {
switch (format) {
case SurfaceFormat::A8R8G8B8_UINT32:
return gfxContentType::COLOR_ALPHA;
case SurfaceFormat::X8R8G8B8_UINT32:
case SurfaceFormat::R5G6B5_UINT16:
return gfxContentType::COLOR;
case SurfaceFormat::A8:
return gfxContentType::ALPHA;
case SurfaceFormat::UNKNOWN:
default:
return gfxContentType::COLOR;
}
}
int32_t gfxASurface::BytePerPixelFromFormat(gfxImageFormat format) {
switch (format) {
case SurfaceFormat::A8R8G8B8_UINT32:
case SurfaceFormat::X8R8G8B8_UINT32:
return 4;
case SurfaceFormat::R5G6B5_UINT16:
return 2;
case SurfaceFormat::A8:
return 1;
default:
NS_WARNING("Unknown byte per pixel value for Image format");
}
return 0;
}
/** Memory reporting **/
static const char* sDefaultSurfaceDescription =
"Memory used by gfx surface of the given type.";
struct SurfaceMemoryReporterAttrs {
const char* path;
const char* description;
};
static const SurfaceMemoryReporterAttrs sSurfaceMemoryReporterAttrs[] = {
{"gfx-surface-image", nullptr},
{"gfx-surface-pdf", nullptr},
{"gfx-surface-ps", nullptr},
{"gfx-surface-xlib",
"Memory used by xlib surfaces to store pixmaps. This memory lives in "
"the X server's process rather than in this application, so the bytes "
"accounted for here aren't counted in vsize, resident, explicit, or any "
"of "
"the other measurements on this page."},
{"gfx-surface-xcb", nullptr},
{"gfx-surface-glitz???", nullptr}, // should never be used
{"gfx-surface-quartz", nullptr},
{"gfx-surface-win32", nullptr},
{"gfx-surface-beos", nullptr},
{"gfx-surface-directfb???", nullptr}, // should never be used
{"gfx-surface-svg", nullptr},
{"gfx-surface-os2", nullptr},
{"gfx-surface-win32printing", nullptr},
{"gfx-surface-quartzimage", nullptr},
{"gfx-surface-script", nullptr},
{"gfx-surface-qpainter", nullptr},
{"gfx-surface-recording", nullptr},
{"gfx-surface-vg", nullptr},
{"gfx-surface-gl", nullptr},
{"gfx-surface-drm", nullptr},
{"gfx-surface-tee", nullptr},
{"gfx-surface-xml", nullptr},
{"gfx-surface-skia", nullptr},
{"gfx-surface-subsurface", nullptr},
};
static_assert(MOZ_ARRAY_LENGTH(sSurfaceMemoryReporterAttrs) ==
size_t(gfxSurfaceType::Max),
"sSurfaceMemoryReporterAttrs exceeds max capacity");
static_assert(uint32_t(CAIRO_SURFACE_TYPE_SKIA) ==
uint32_t(gfxSurfaceType::Skia),
"CAIRO_SURFACE_TYPE_SKIA not equal to gfxSurfaceType::Skia");
/* Surface size memory reporting */
class SurfaceMemoryReporter final : public nsIMemoryReporter {
~SurfaceMemoryReporter() = default;
// We can touch this array on several different threads, and we don't
// want to introduce memory barriers when recording the memory used. To
// assure dynamic race checkers like TSan that this is OK, we use
// relaxed memory ordering here.
static Atomic<size_t, Relaxed>
sSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)];
public:
static void AdjustUsedMemory(gfxSurfaceType aType, int32_t aBytes) {
// A read-modify-write operation like += would require a memory barrier
// here, which would defeat the purpose of using relaxed memory
// ordering. So separate out the read and write operations.
sSurfaceMemoryUsed[size_t(aType)] =
sSurfaceMemoryUsed[size_t(aType)] + aBytes;
};
// This memory reporter is sometimes allocated on the compositor thread,
// but always released on the main thread, so its refcounting needs to be
// threadsafe.
NS_DECL_THREADSAFE_ISUPPORTS
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize) override {
const size_t len = ArrayLength(sSurfaceMemoryReporterAttrs);
for (size_t i = 0; i < len; i++) {
int64_t amount = sSurfaceMemoryUsed[i];
if (amount != 0) {
const char* path = sSurfaceMemoryReporterAttrs[i].path;
const char* desc = sSurfaceMemoryReporterAttrs[i].description;
if (!desc) {
desc = sDefaultSurfaceDescription;
}
aHandleReport->Callback(EmptyCString(), nsCString(path), KIND_OTHER,
UNITS_BYTES, amount, nsCString(desc), aData);
}
}
return NS_OK;
}
};
Atomic<size_t, Relaxed>
SurfaceMemoryReporter::sSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)];
NS_IMPL_ISUPPORTS(SurfaceMemoryReporter, nsIMemoryReporter)
void gfxASurface::RecordMemoryUsedForSurfaceType(gfxSurfaceType aType,
int32_t aBytes) {
if (int(aType) < 0 || aType >= gfxSurfaceType::Max) {
NS_WARNING("Invalid type to RecordMemoryUsedForSurfaceType!");
return;
}
static bool registered = false;
if (!registered) {
RegisterStrongMemoryReporter(new SurfaceMemoryReporter());
registered = true;
}
SurfaceMemoryReporter::AdjustUsedMemory(aType, aBytes);
}
void gfxASurface::RecordMemoryUsed(int32_t aBytes) {
RecordMemoryUsedForSurfaceType(GetType(), aBytes);
mBytesRecorded += aBytes;
}
void gfxASurface::RecordMemoryFreed() {
if (mBytesRecorded) {
RecordMemoryUsedForSurfaceType(GetType(), -mBytesRecorded);
mBytesRecorded = 0;
}
}
size_t gfxASurface::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
// We don't measure mSurface because cairo doesn't allow it.
return 0;
}
size_t gfxASurface::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
/* static */
uint8_t gfxASurface::BytesPerPixel(gfxImageFormat aImageFormat) {
switch (aImageFormat) {
case SurfaceFormat::A8R8G8B8_UINT32:
return 4;
case SurfaceFormat::X8R8G8B8_UINT32:
return 4;
case SurfaceFormat::R5G6B5_UINT16:
return 2;
case SurfaceFormat::A8:
return 1;
case SurfaceFormat::UNKNOWN:
default:
MOZ_ASSERT_UNREACHABLE("Not really sure what you want me to say here");
return 0;
}
}
void gfxASurface::SetOpaqueRect(const gfxRect& aRect) {
if (aRect.IsEmpty()) {
mOpaqueRect = nullptr;
} else if (!!mOpaqueRect) {
*mOpaqueRect = aRect;
} else {
mOpaqueRect = MakeUnique<gfxRect>(aRect);
}
}
/* static */ const gfxRect& gfxASurface::GetEmptyOpaqueRect() {
static const gfxRect empty(0, 0, 0, 0);
return empty;
}
const IntSize gfxASurface::GetSize() const { return IntSize(-1, -1); }
SurfaceFormat gfxASurface::GetSurfaceFormat() const {
if (!mSurfaceValid) {
return SurfaceFormat::UNKNOWN;
}
return GfxFormatForCairoSurface(mSurface);
}
already_AddRefed<gfxImageSurface> gfxASurface::GetAsImageSurface() {
return nullptr;
}