Line data Source code
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 :
7 : #include "Logging.h"
8 : #include "SourceSurfaceSkia.h"
9 : #include "HelpersSkia.h"
10 : #include "DrawTargetSkia.h"
11 : #include "DataSurfaceHelpers.h"
12 : #include "skia/include/core/SkData.h"
13 : #include "mozilla/CheckedInt.h"
14 :
15 : namespace mozilla {
16 : namespace gfx {
17 :
18 37 : SourceSurfaceSkia::SourceSurfaceSkia()
19 37 : : mDrawTarget(nullptr)
20 : {
21 37 : }
22 :
23 54 : SourceSurfaceSkia::~SourceSurfaceSkia()
24 : {
25 18 : if (mDrawTarget) {
26 18 : mDrawTarget->SnapshotDestroyed();
27 18 : mDrawTarget = nullptr;
28 : }
29 54 : }
30 :
31 : IntSize
32 146 : SourceSurfaceSkia::GetSize() const
33 : {
34 146 : return mSize;
35 : }
36 :
37 : SurfaceFormat
38 145 : SourceSurfaceSkia::GetFormat() const
39 : {
40 145 : return mFormat;
41 : }
42 :
43 : static sk_sp<SkData>
44 0 : MakeSkData(void* aData, int32_t aHeight, size_t aStride)
45 : {
46 0 : CheckedInt<size_t> size = aStride;
47 0 : size *= aHeight;
48 0 : if (size.isValid()) {
49 0 : void* mem = sk_malloc_flags(size.value(), 0);
50 0 : if (mem) {
51 0 : if (aData) {
52 0 : memcpy(mem, aData, size.value());
53 : }
54 0 : return SkData::MakeFromMalloc(mem, size.value());
55 : }
56 : }
57 0 : return nullptr;
58 : }
59 :
60 : static sk_sp<SkImage>
61 0 : ReadSkImage(const sk_sp<SkImage>& aImage, const SkImageInfo& aInfo, size_t aStride)
62 : {
63 0 : if (sk_sp<SkData> data = MakeSkData(nullptr, aInfo.height(), aStride)) {
64 0 : if (aImage->readPixels(aInfo, data->writable_data(), aStride, 0, 0, SkImage::kDisallow_CachingHint)) {
65 0 : return SkImage::MakeRasterData(aInfo, data, aStride);
66 : }
67 : }
68 0 : return nullptr;
69 : }
70 :
71 : bool
72 0 : SourceSurfaceSkia::InitFromData(unsigned char* aData,
73 : const IntSize &aSize,
74 : int32_t aStride,
75 : SurfaceFormat aFormat)
76 : {
77 0 : sk_sp<SkData> data = MakeSkData(aData, aSize.height, aStride);
78 0 : if (!data) {
79 0 : return false;
80 : }
81 :
82 0 : SkImageInfo info = MakeSkiaImageInfo(aSize, aFormat);
83 0 : mImage = SkImage::MakeRasterData(info, data, aStride);
84 0 : if (!mImage) {
85 0 : return false;
86 : }
87 :
88 0 : mSize = aSize;
89 0 : mFormat = aFormat;
90 0 : mStride = aStride;
91 0 : return true;
92 : }
93 :
94 : bool
95 37 : SourceSurfaceSkia::InitFromImage(const sk_sp<SkImage>& aImage,
96 : SurfaceFormat aFormat,
97 : DrawTargetSkia* aOwner)
98 : {
99 37 : if (!aImage) {
100 0 : return false;
101 : }
102 :
103 37 : mSize = IntSize(aImage->width(), aImage->height());
104 :
105 : // For the raster image case, we want to use the format and stride
106 : // information that the underlying raster image is using, which is
107 : // reliable.
108 : // For the GPU case (for which peekPixels is false), we can't easily
109 : // figure this information out. It is better to report the originally
110 : // intended format and stride that we will convert to if this GPU
111 : // image is ever read back into a raster image.
112 74 : SkPixmap pixmap;
113 37 : if (aImage->peekPixels(&pixmap)) {
114 37 : mFormat =
115 37 : aFormat != SurfaceFormat::UNKNOWN ?
116 : aFormat :
117 0 : SkiaColorTypeToGfxFormat(pixmap.colorType(), pixmap.alphaType());
118 37 : mStride = pixmap.rowBytes();
119 0 : } else if (aFormat != SurfaceFormat::UNKNOWN) {
120 0 : mFormat = aFormat;
121 0 : SkImageInfo info = MakeSkiaImageInfo(mSize, mFormat);
122 0 : mStride = SkAlign4(info.minRowBytes());
123 : } else {
124 0 : return false;
125 : }
126 :
127 37 : mImage = aImage;
128 :
129 37 : if (aOwner) {
130 37 : mDrawTarget = aOwner;
131 : }
132 :
133 37 : return true;
134 : }
135 :
136 : uint8_t*
137 0 : SourceSurfaceSkia::GetData()
138 : {
139 0 : if (!mImage) {
140 0 : return nullptr;
141 : }
142 : #ifdef USE_SKIA_GPU
143 0 : if (mImage->isTextureBacked()) {
144 0 : if (sk_sp<SkImage> raster = ReadSkImage(mImage, MakeSkiaImageInfo(mSize, mFormat), mStride)) {
145 0 : mImage = raster;
146 : } else {
147 0 : gfxCriticalError() << "Failed making Skia raster image for GPU surface";
148 : }
149 : }
150 : #endif
151 0 : SkPixmap pixmap;
152 0 : if (!mImage->peekPixels(&pixmap)) {
153 0 : gfxCriticalError() << "Failed accessing pixels for Skia raster image";
154 : }
155 0 : return reinterpret_cast<uint8_t*>(pixmap.writable_addr());
156 : }
157 :
158 : void
159 0 : SourceSurfaceSkia::DrawTargetWillChange()
160 : {
161 0 : if (mDrawTarget) {
162 : // Raster snapshots do not use Skia's internal copy-on-write mechanism,
163 : // so we need to do an explicit copy here.
164 : // GPU snapshots, for which peekPixels is false, will already be dealt
165 : // with automatically via the internal copy-on-write mechanism, so we
166 : // don't need to do anything for them here.
167 0 : SkPixmap pixmap;
168 0 : if (mImage->peekPixels(&pixmap)) {
169 0 : mImage = ReadSkImage(mImage, pixmap.info(), pixmap.rowBytes());
170 0 : if (!mImage) {
171 0 : gfxCriticalError() << "Failed copying Skia raster snapshot";
172 : }
173 : }
174 0 : mDrawTarget = nullptr;
175 : }
176 0 : }
177 :
178 : } // namespace gfx
179 : } // namespace mozilla
|