summaryrefslogtreecommitdiffstats
path: root/gfx/2d/SourceSurfaceSkia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/SourceSurfaceSkia.cpp')
-rw-r--r--gfx/2d/SourceSurfaceSkia.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/gfx/2d/SourceSurfaceSkia.cpp b/gfx/2d/SourceSurfaceSkia.cpp
new file mode 100644
index 000000000..14cbf6a84
--- /dev/null
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -0,0 +1,172 @@
+/* -*- 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 "Logging.h"
+#include "SourceSurfaceSkia.h"
+#include "HelpersSkia.h"
+#include "DrawTargetSkia.h"
+#include "DataSurfaceHelpers.h"
+#include "skia/include/core/SkData.h"
+#include "mozilla/CheckedInt.h"
+
+namespace mozilla {
+namespace gfx {
+
+SourceSurfaceSkia::SourceSurfaceSkia()
+ : mDrawTarget(nullptr)
+{
+}
+
+SourceSurfaceSkia::~SourceSurfaceSkia()
+{
+ if (mDrawTarget) {
+ mDrawTarget->SnapshotDestroyed();
+ mDrawTarget = nullptr;
+ }
+}
+
+IntSize
+SourceSurfaceSkia::GetSize() const
+{
+ return mSize;
+}
+
+SurfaceFormat
+SourceSurfaceSkia::GetFormat() const
+{
+ return mFormat;
+}
+
+static sk_sp<SkData>
+MakeSkData(unsigned char* aData, const IntSize& aSize, int32_t aStride)
+{
+ CheckedInt<size_t> size = aStride;
+ size *= aSize.height;
+ if (size.isValid()) {
+ void* mem = sk_malloc_flags(size.value(), 0);
+ if (mem) {
+ if (aData) {
+ memcpy(mem, aData, size.value());
+ }
+ return SkData::MakeFromMalloc(mem, size.value());
+ }
+ }
+ return nullptr;
+}
+
+bool
+SourceSurfaceSkia::InitFromData(unsigned char* aData,
+ const IntSize &aSize,
+ int32_t aStride,
+ SurfaceFormat aFormat)
+{
+ sk_sp<SkData> data = MakeSkData(aData, aSize, aStride);
+ if (!data) {
+ return false;
+ }
+
+ SkImageInfo info = MakeSkiaImageInfo(aSize, aFormat);
+ mImage = SkImage::MakeRasterData(info, data, aStride);
+ if (!mImage) {
+ return false;
+ }
+
+ mSize = aSize;
+ mFormat = aFormat;
+ mStride = aStride;
+ return true;
+}
+
+bool
+SourceSurfaceSkia::InitFromImage(sk_sp<SkImage> aImage,
+ SurfaceFormat aFormat,
+ DrawTargetSkia* aOwner)
+{
+ if (!aImage) {
+ return false;
+ }
+
+ mSize = IntSize(aImage->width(), aImage->height());
+
+ // For the raster image case, we want to use the format and stride
+ // information that the underlying raster image is using, which is
+ // reliable.
+ // For the GPU case (for which peekPixels is false), we can't easily
+ // figure this information out. It is better to report the originally
+ // intended format and stride that we will convert to if this GPU
+ // image is ever read back into a raster image.
+ SkPixmap pixmap;
+ if (aImage->peekPixels(&pixmap)) {
+ mFormat =
+ aFormat != SurfaceFormat::UNKNOWN ?
+ aFormat :
+ SkiaColorTypeToGfxFormat(pixmap.colorType(), pixmap.alphaType());
+ mStride = pixmap.rowBytes();
+ } else if (aFormat != SurfaceFormat::UNKNOWN) {
+ mFormat = aFormat;
+ SkImageInfo info = MakeSkiaImageInfo(mSize, mFormat);
+ mStride = SkAlign4(info.minRowBytes());
+ } else {
+ return false;
+ }
+
+ mImage = aImage;
+
+ if (aOwner) {
+ mDrawTarget = aOwner;
+ }
+
+ return true;
+}
+
+uint8_t*
+SourceSurfaceSkia::GetData()
+{
+#ifdef USE_SKIA_GPU
+ if (mImage->isTextureBacked()) {
+ sk_sp<SkImage> raster;
+ if (sk_sp<SkData> data = MakeSkData(nullptr, mSize, mStride)) {
+ SkImageInfo info = MakeSkiaImageInfo(mSize, mFormat);
+ if (mImage->readPixels(info, data->writable_data(), mStride, 0, 0, SkImage::kDisallow_CachingHint)) {
+ raster = SkImage::MakeRasterData(info, data, mStride);
+ }
+ }
+ if (raster) {
+ mImage = raster;
+ } else {
+ gfxCriticalError() << "Failed making Skia raster image for GPU surface";
+ }
+ }
+#endif
+ SkPixmap pixmap;
+ if (!mImage->peekPixels(&pixmap)) {
+ gfxCriticalError() << "Failed accessing pixels for Skia raster image";
+ }
+ return reinterpret_cast<uint8_t*>(pixmap.writable_addr());
+}
+
+void
+SourceSurfaceSkia::DrawTargetWillChange()
+{
+ if (mDrawTarget) {
+ // Raster snapshots do not use Skia's internal copy-on-write mechanism,
+ // so we need to do an explicit copy here.
+ // GPU snapshots, for which peekPixels is false, will already be dealt
+ // with automatically via the internal copy-on-write mechanism, so we
+ // don't need to do anything for them here.
+ SkPixmap pixmap;
+ if (mImage->peekPixels(&pixmap)) {
+ mImage = SkImage::MakeRasterCopy(pixmap);
+ if (!mImage) {
+ gfxCriticalError() << "Failed copying Skia raster snapshot";
+ }
+ }
+ mDrawTarget = nullptr;
+ }
+}
+
+} // namespace gfx
+} // namespace mozilla