1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkSurface_Base.h"
9#include "SkImagePriv.h"
10#include "SkCanvas.h"
11
12#include "SkFontLCDConfig.h"
13static SkPixelGeometry compute_default_geometry() {
14    SkFontLCDConfig::LCDOrder order = SkFontLCDConfig::GetSubpixelOrder();
15    if (SkFontLCDConfig::kNONE_LCDOrder == order) {
16        return kUnknown_SkPixelGeometry;
17    } else {
18        // Bit0 is RGB(0), BGR(1)
19        // Bit1 is H(0), V(1)
20        const SkPixelGeometry gGeo[] = {
21            kRGB_H_SkPixelGeometry,
22            kBGR_H_SkPixelGeometry,
23            kRGB_V_SkPixelGeometry,
24            kBGR_V_SkPixelGeometry,
25        };
26        int index = 0;
27        if (SkFontLCDConfig::kBGR_LCDOrder == order) {
28            index |= 1;
29        }
30        if (SkFontLCDConfig::kVertical_LCDOrientation == SkFontLCDConfig::GetSubpixelOrientation()){
31            index |= 2;
32        }
33        return gGeo[index];
34    }
35}
36
37SkSurfaceProps::SkSurfaceProps() : fFlags(0), fPixelGeometry(kUnknown_SkPixelGeometry) {}
38
39SkSurfaceProps::SkSurfaceProps(InitType) : fFlags(0), fPixelGeometry(compute_default_geometry()) {}
40
41SkSurfaceProps::SkSurfaceProps(uint32_t flags, InitType)
42    : fFlags(flags)
43    , fPixelGeometry(compute_default_geometry())
44{}
45
46SkSurfaceProps::SkSurfaceProps(uint32_t flags, SkPixelGeometry pg)
47    : fFlags(flags), fPixelGeometry(pg)
48{}
49
50SkSurfaceProps::SkSurfaceProps(const SkSurfaceProps& other)
51    : fFlags(other.fFlags)
52    , fPixelGeometry(other.fPixelGeometry)
53{}
54
55///////////////////////////////////////////////////////////////////////////////
56
57SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props)
58    : INHERITED(width, height, props)
59{
60    fCachedCanvas = nullptr;
61    fCachedImage = nullptr;
62}
63
64SkSurface_Base::SkSurface_Base(const SkImageInfo& info, const SkSurfaceProps* props)
65    : INHERITED(info, props)
66{
67    fCachedCanvas = nullptr;
68    fCachedImage = nullptr;
69}
70
71SkSurface_Base::~SkSurface_Base() {
72    // in case the canvas outsurvives us, we null the callback
73    if (fCachedCanvas) {
74        fCachedCanvas->setSurfaceBase(nullptr);
75    }
76
77    SkSafeUnref(fCachedImage);
78    SkSafeUnref(fCachedCanvas);
79}
80
81void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
82    SkImage* image = this->newImageSnapshot(SkBudgeted::kYes);
83    if (image) {
84        canvas->drawImage(image, x, y, paint);
85        image->unref();
86    }
87}
88
89bool SkSurface_Base::outstandingImageSnapshot() const {
90    return fCachedImage && !fCachedImage->unique();
91}
92
93void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
94    this->dirtyGenerationID();
95
96    SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
97
98    if (fCachedImage) {
99        // the surface may need to fork its backend, if its sharing it with
100        // the cached image. Note: we only call if there is an outstanding owner
101        // on the image (besides us).
102        bool unique = fCachedImage->unique();
103        if (!unique) {
104            this->onCopyOnWrite(mode);
105        }
106
107        // regardless of copy-on-write, we must drop our cached image now, so
108        // that the next request will get our new contents.
109        fCachedImage->unref();
110        fCachedImage = nullptr;
111
112        if (unique) {
113            // Our content isn't held by any image now, so we can consider that content mutable.
114            // Raster surfaces need to be told it's safe to consider its pixels mutable again.
115            // We make this call after the ->unref() so the subclass can assert there are no images.
116            this->onRestoreBackingMutability();
117        }
118    } else if (kDiscard_ContentChangeMode == mode) {
119        this->onDiscard();
120    }
121}
122
123uint32_t SkSurface_Base::newGenerationID() {
124    SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
125    static int32_t gID;
126    return sk_atomic_inc(&gID) + 1;
127}
128
129static SkSurface_Base* asSB(SkSurface* surface) {
130    return static_cast<SkSurface_Base*>(surface);
131}
132
133///////////////////////////////////////////////////////////////////////////////
134
135SkSurface::SkSurface(int width, int height, const SkSurfaceProps* props)
136    : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(width), fHeight(height)
137{
138    SkASSERT(fWidth > 0);
139    SkASSERT(fHeight > 0);
140    fGenerationID = 0;
141}
142
143SkSurface::SkSurface(const SkImageInfo& info, const SkSurfaceProps* props)
144    : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(info.width()), fHeight(info.height())
145{
146    SkASSERT(fWidth > 0);
147    SkASSERT(fHeight > 0);
148    fGenerationID = 0;
149}
150
151uint32_t SkSurface::generationID() {
152    if (0 == fGenerationID) {
153        fGenerationID = asSB(this)->newGenerationID();
154    }
155    return fGenerationID;
156}
157
158void SkSurface::notifyContentWillChange(ContentChangeMode mode) {
159    asSB(this)->aboutToDraw(mode);
160}
161
162SkCanvas* SkSurface::getCanvas() {
163    return asSB(this)->getCachedCanvas();
164}
165
166SkImage* SkSurface::newImageSnapshot(SkBudgeted budgeted) {
167    // the caller will call unref() to balance this
168    return asSB(this)->refCachedImage(budgeted, kNo_ForceUnique);
169}
170
171SkImage* SkSurface::newImageSnapshot(SkBudgeted budgeted, ForceUnique unique) {
172    // the caller will call unref() to balance this
173    return asSB(this)->refCachedImage(budgeted, unique);
174}
175
176SkSurface* SkSurface::newSurface(const SkImageInfo& info) {
177    return asSB(this)->onNewSurface(info);
178}
179
180void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
181                     const SkPaint* paint) {
182    return asSB(this)->onDraw(canvas, x, y, paint);
183}
184
185const void* SkSurface::peekPixels(SkImageInfo* info, size_t* rowBytes) {
186    return this->getCanvas()->peekPixels(info, rowBytes);
187}
188
189bool SkSurface::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
190                           int srcX, int srcY) {
191    return this->getCanvas()->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
192}
193
194GrBackendObject SkSurface::getTextureHandle(BackendHandleAccess access) {
195    return asSB(this)->onGetTextureHandle(access);
196}
197
198bool SkSurface::getRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
199    return asSB(this)->onGetRenderTargetHandle(obj, access);
200}
201
202void SkSurface::prepareForExternalIO() {
203  asSB(this)->onPrepareForExternalIO();
204}
205
206//////////////////////////////////////////////////////////////////////////////////////
207
208#if !SK_SUPPORT_GPU
209
210SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget*, const SkSurfaceProps*) {
211    return nullptr;
212}
213
214SkSurface* SkSurface::NewRenderTarget(GrContext*, SkBudgeted, const SkImageInfo&, int,
215                                      const SkSurfaceProps*, GrTextureStorageAllocator) {
216    return nullptr;
217}
218
219SkSurface* SkSurface::NewFromBackendTexture(GrContext*, const GrBackendTextureDesc&,
220                                             const SkSurfaceProps*) {
221    return nullptr;
222}
223
224SkSurface* SkSurface::NewFromBackendRenderTarget(GrContext*, const GrBackendRenderTargetDesc&,
225                                                 const SkSurfaceProps*) {
226    return nullptr;
227}
228
229SkSurface* NewFromBackendTextureAsRenderTarget(GrContext*, const GrBackendTextureDesc&,
230                                               const SkSurfaceProps*) {
231    return nullptr;
232}
233
234#endif
235