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
50///////////////////////////////////////////////////////////////////////////////
51
52SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props)
53    : INHERITED(width, height, props)
54{
55    fCachedCanvas = NULL;
56    fCachedImage = NULL;
57}
58
59SkSurface_Base::SkSurface_Base(const SkImageInfo& info, const SkSurfaceProps* props)
60    : INHERITED(info, props)
61{
62    fCachedCanvas = NULL;
63    fCachedImage = NULL;
64}
65
66SkSurface_Base::~SkSurface_Base() {
67    // in case the canvas outsurvives us, we null the callback
68    if (fCachedCanvas) {
69        fCachedCanvas->setSurfaceBase(NULL);
70    }
71
72    SkSafeUnref(fCachedImage);
73    SkSafeUnref(fCachedCanvas);
74}
75
76void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
77    SkImage* image = this->newImageSnapshot();
78    if (image) {
79        canvas->drawImage(image, x, y, paint);
80        image->unref();
81    }
82}
83
84void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
85    this->dirtyGenerationID();
86
87    SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
88
89    if (fCachedImage) {
90        // the surface may need to fork its backend, if its sharing it with
91        // the cached image. Note: we only call if there is an outstanding owner
92        // on the image (besides us).
93        if (!fCachedImage->unique()) {
94            this->onCopyOnWrite(mode);
95        }
96
97        // regardless of copy-on-write, we must drop our cached image now, so
98        // that the next request will get our new contents.
99        fCachedImage->unref();
100        fCachedImage = NULL;
101    } else if (kDiscard_ContentChangeMode == mode) {
102        this->onDiscard();
103    }
104}
105
106uint32_t SkSurface_Base::newGenerationID() {
107    SkASSERT(!fCachedCanvas || fCachedCanvas->getSurfaceBase() == this);
108    static int32_t gID;
109    return sk_atomic_inc(&gID) + 1;
110}
111
112static SkSurface_Base* asSB(SkSurface* surface) {
113    return static_cast<SkSurface_Base*>(surface);
114}
115
116///////////////////////////////////////////////////////////////////////////////
117
118SkSurface::SkSurface(int width, int height, const SkSurfaceProps* props)
119    : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(width), fHeight(height)
120{
121    SkASSERT(fWidth >= 0);
122    SkASSERT(fHeight >= 0);
123    fGenerationID = 0;
124}
125
126SkSurface::SkSurface(const SkImageInfo& info, const SkSurfaceProps* props)
127    : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(info.width()), fHeight(info.height())
128{
129    SkASSERT(fWidth >= 0);
130    SkASSERT(fHeight >= 0);
131    fGenerationID = 0;
132}
133
134uint32_t SkSurface::generationID() {
135    if (0 == fGenerationID) {
136        fGenerationID = asSB(this)->newGenerationID();
137    }
138    return fGenerationID;
139}
140
141void SkSurface::notifyContentWillChange(ContentChangeMode mode) {
142    asSB(this)->aboutToDraw(mode);
143}
144
145SkCanvas* SkSurface::getCanvas() {
146    return asSB(this)->getCachedCanvas();
147}
148
149SkImage* SkSurface::newImageSnapshot() {
150    SkImage* image = asSB(this)->getCachedImage();
151    SkSafeRef(image);   // the caller will call unref() to balance this
152    return image;
153}
154
155SkSurface* SkSurface::newSurface(const SkImageInfo& info) {
156    return asSB(this)->onNewSurface(info);
157}
158
159void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
160                     const SkPaint* paint) {
161    return asSB(this)->onDraw(canvas, x, y, paint);
162}
163
164const void* SkSurface::peekPixels(SkImageInfo* info, size_t* rowBytes) {
165    return this->getCanvas()->peekPixels(info, rowBytes);
166}
167
168//////////////////////////////////////////////////////////////////////////////////////
169#ifdef SK_SUPPORT_LEGACY_TEXTRENDERMODE
170
171static SkSurfaceProps make_props(SkSurface::TextRenderMode trm) {
172    uint32_t propsFlags = 0;
173    if (SkSurface::kDistanceField_TextRenderMode == trm) {
174        propsFlags |= SkSurfaceProps::kUseDistanceFieldFonts_Flag;
175    }
176    return SkSurfaceProps(propsFlags, SkSurfaceProps::kLegacyFontHost_InitType);
177}
178
179SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget* target, TextRenderMode trm) {
180    SkSurfaceProps props = make_props(trm);
181    return NewRenderTargetDirect(target, &props);
182}
183
184SkSurface* SkSurface::NewRenderTarget(GrContext* gr, const SkImageInfo& info, int sampleCount,
185                                      TextRenderMode trm) {
186    SkSurfaceProps props = make_props(trm);
187    return NewRenderTarget(gr, info, sampleCount, &props);
188}
189
190SkSurface* SkSurface::NewScratchRenderTarget(GrContext* gr, const SkImageInfo& info, int sampleCount,
191                                             TextRenderMode trm) {
192    SkSurfaceProps props = make_props(trm);
193    return NewScratchRenderTarget(gr, info, sampleCount, &props);
194}
195
196#endif
197
198#if !SK_SUPPORT_GPU
199
200SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget*, const SkSurfaceProps*) {
201    return NULL;
202}
203
204SkSurface* SkSurface::NewRenderTarget(GrContext*, const SkImageInfo&, int, const SkSurfaceProps*) {
205    return NULL;
206}
207
208SkSurface* SkSurface::NewScratchRenderTarget(GrContext*, const SkImageInfo&, int sampleCount,
209                                             const SkSurfaceProps*) {
210    return NULL;
211}
212
213#endif
214