1c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com/*
2c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com * Copyright 2012 Google Inc.
3c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com *
4c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com * Use of this source code is governed by a BSD-style license that can be
5c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com * found in the LICENSE file.
6c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com */
7c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
8c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com#include "SkSurface_Base.h"
9c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com#include "SkImagePriv.h"
10c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com#include "SkCanvas.h"
1197af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com#include "SkDevice.h"
12c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com#include "SkMallocPixelRef.h"
13c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
14c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.comstatic const size_t kIgnoreRowBytesValue = (size_t)~0;
15c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
16c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.comclass SkSurface_Raster : public SkSurface_Base {
17c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.compublic:
182bd8b8100529c96c81c30f749f672f4caf775b04reed@google.com    static bool Valid(const SkImageInfo&, size_t rb = kIgnoreRowBytesValue);
19c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
20982542dce8acbd2f3e7642268b21e76b93230dafreed    SkSurface_Raster(const SkImageInfo&, void*, size_t rb,
214a8126e7f81384526629b1e21bf89b632ea13cd9reed                     void (*releaseProc)(void* pixels, void* context), void* context,
224a8126e7f81384526629b1e21bf89b632ea13cd9reed                     const SkSurfaceProps*);
234a8126e7f81384526629b1e21bf89b632ea13cd9reed    SkSurface_Raster(SkPixelRef*, const SkSurfaceProps*);
24c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
2536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkCanvas* onNewCanvas() override;
2636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkSurface* onNewSurface(const SkImageInfo&) override;
275ec26ae9bfca635ccc98283aad5deda11519d826bsalomon    SkImage* onNewImageSnapshot(SkBudgeted, ForceCopyMode) override;
287831a4bbb46a919316efc7c70808dcaaf8ee629atfarina    void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override;
2936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onCopyOnWrite(ContentChangeMode) override;
3026e0e587f76f2a9338652c100f835c2377c908d3reed    void onRestoreBackingMutability() override;
31c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
32c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.comprivate:
33c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    SkBitmap    fBitmap;
349cd016e9b63f3827580d5b19a187dbf26b8e1436reed    size_t      fRowBytes;
35c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    bool        fWeOwnThePixels;
36c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
37c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    typedef SkSurface_Base INHERITED;
38c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com};
39c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
40c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com///////////////////////////////////////////////////////////////////////////////
41c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
422bd8b8100529c96c81c30f749f672f4caf775b04reed@google.combool SkSurface_Raster::Valid(const SkImageInfo& info, size_t rowBytes) {
43b2497c2d945c0a5d770865b026e2d5947bf37c91reed    if (info.isEmpty()) {
44b2497c2d945c0a5d770865b026e2d5947bf37c91reed        return false;
45b2497c2d945c0a5d770865b026e2d5947bf37c91reed    }
46b2497c2d945c0a5d770865b026e2d5947bf37c91reed
47c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    static const size_t kMaxTotalSize = SK_MaxS32;
48c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
49c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    int shift = 0;
50e5ea500d4714a7d84de2bf913e81be3b65d2de68reed    switch (info.colorType()) {
511360c52b10dad45d7a6850370eab40c6253d7988reed@google.com        case kAlpha_8_SkColorType:
52c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com            shift = 0;
53c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com            break;
541360c52b10dad45d7a6850370eab40c6253d7988reed@google.com        case kRGB_565_SkColorType:
55c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com            shift = 1;
56c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com            break;
5728fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org        case kN32_SkColorType:
58c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com            shift = 2;
59c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com            break;
60a34be68a7eff0ae475b194f8a29975460cf3e456reed        case kRGBA_F16_SkColorType:
61a34be68a7eff0ae475b194f8a29975460cf3e456reed            shift = 3;
62a34be68a7eff0ae475b194f8a29975460cf3e456reed            break;
63c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com        default:
64c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com            return false;
65c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
66c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
67c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    if (kIgnoreRowBytesValue == rowBytes) {
68c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com        return true;
69c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
70c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
71e5ea500d4714a7d84de2bf913e81be3b65d2de68reed    uint64_t minRB = (uint64_t)info.width() << shift;
72c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    if (minRB > rowBytes) {
73c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com        return false;
74c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
75c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
76c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    size_t alignedRowBytes = rowBytes >> shift << shift;
77c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    if (alignedRowBytes != rowBytes) {
78c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com        return false;
79c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
80c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
81e5ea500d4714a7d84de2bf913e81be3b65d2de68reed    uint64_t size = sk_64_mul(info.height(), rowBytes);
82c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    if (size > kMaxTotalSize) {
83c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com        return false;
84c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
85fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
86c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    return true;
87c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com}
88c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
89982542dce8acbd2f3e7642268b21e76b93230dafreedSkSurface_Raster::SkSurface_Raster(const SkImageInfo& info, void* pixels, size_t rb,
904a8126e7f81384526629b1e21bf89b632ea13cd9reed                                   void (*releaseProc)(void* pixels, void* context), void* context,
914a8126e7f81384526629b1e21bf89b632ea13cd9reed                                   const SkSurfaceProps* props)
924a8126e7f81384526629b1e21bf89b632ea13cd9reed    : INHERITED(info, props)
931360c52b10dad45d7a6850370eab40c6253d7988reed@google.com{
9496fcdcc219d2a0d3579719b84b28bede76efba64halcanary    fBitmap.installPixels(info, pixels, rb, nullptr, releaseProc, context);
959cd016e9b63f3827580d5b19a187dbf26b8e1436reed    fRowBytes = 0;              // don't need to track the rowbytes
9697af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com    fWeOwnThePixels = false;    // We are "Direct"
97c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com}
98c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
994a8126e7f81384526629b1e21bf89b632ea13cd9reedSkSurface_Raster::SkSurface_Raster(SkPixelRef* pr, const SkSurfaceProps* props)
1004a8126e7f81384526629b1e21bf89b632ea13cd9reed    : INHERITED(pr->info().width(), pr->info().height(), props)
1011360c52b10dad45d7a6850370eab40c6253d7988reed@google.com{
102e13af711d4ff9031c9ed3054a4c33a56a0c62e1fcommit-bot@chromium.org    const SkImageInfo& info = pr->info();
103e13af711d4ff9031c9ed3054a4c33a56a0c62e1fcommit-bot@chromium.org
1049cd016e9b63f3827580d5b19a187dbf26b8e1436reed    fBitmap.setInfo(info, pr->rowBytes());
105e13af711d4ff9031c9ed3054a4c33a56a0c62e1fcommit-bot@chromium.org    fBitmap.setPixelRef(pr);
1069cd016e9b63f3827580d5b19a187dbf26b8e1436reed    fRowBytes = pr->rowBytes(); // we track this, so that subsequent re-allocs will match
107c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    fWeOwnThePixels = true;
108c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com}
109c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
110385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanarySkCanvas* SkSurface_Raster::onNewCanvas() { return new SkCanvas(fBitmap, this->props()); }
111c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
1122bd8b8100529c96c81c30f749f672f4caf775b04reed@google.comSkSurface* SkSurface_Raster::onNewSurface(const SkImageInfo& info) {
113702edbd4bc41230902b5fe69d14d15763c27faferobertphillips    return SkSurface::NewRaster(info, &this->props());
114c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com}
115c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
116c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.comvoid SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
117c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com                              const SkPaint* paint) {
118c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    canvas->drawBitmap(fBitmap, x, y, paint);
119c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com}
120c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
1215ec26ae9bfca635ccc98283aad5deda11519d826bsalomonSkImage* SkSurface_Raster::onNewImageSnapshot(SkBudgeted, ForceCopyMode forceCopyMode) {
12226e0e587f76f2a9338652c100f835c2377c908d3reed    if (fWeOwnThePixels) {
12326e0e587f76f2a9338652c100f835c2377c908d3reed        // SkImage_raster requires these pixels are immutable for its full lifetime.
12426e0e587f76f2a9338652c100f835c2377c908d3reed        // We'll undo this via onRestoreBackingMutability() if we can avoid the COW.
12526e0e587f76f2a9338652c100f835c2377c908d3reed        if (SkPixelRef* pr = fBitmap.pixelRef()) {
12626e0e587f76f2a9338652c100f835c2377c908d3reed            pr->setTemporarilyImmutable();
12726e0e587f76f2a9338652c100f835c2377c908d3reed        }
128f47b9a3b88a037a481eb70f01a4cf9f5be34dc28bsalomon    } else {
129f47b9a3b88a037a481eb70f01a4cf9f5be34dc28bsalomon        forceCopyMode = kYes_ForceCopyMode;
13026e0e587f76f2a9338652c100f835c2377c908d3reed    }
131f47b9a3b88a037a481eb70f01a4cf9f5be34dc28bsalomon
1329a5d1ab54d52a912bb3ac9f74ee01bba079639e5fmalita    // Our pixels are in memory, so read access on the snapshot SkImage could be cheap.
1339a5d1ab54d52a912bb3ac9f74ee01bba079639e5fmalita    // Lock the shared pixel ref to ensure peekPixels() is usable.
134f47b9a3b88a037a481eb70f01a4cf9f5be34dc28bsalomon    return SkNewImageFromRasterBitmap(fBitmap, forceCopyMode);
13526e0e587f76f2a9338652c100f835c2377c908d3reed}
13626e0e587f76f2a9338652c100f835c2377c908d3reed
13726e0e587f76f2a9338652c100f835c2377c908d3reedvoid SkSurface_Raster::onRestoreBackingMutability() {
13826e0e587f76f2a9338652c100f835c2377c908d3reed    SkASSERT(!this->hasCachedImage());  // Shouldn't be any snapshots out there.
13926e0e587f76f2a9338652c100f835c2377c908d3reed    if (SkPixelRef* pr = fBitmap.pixelRef()) {
14026e0e587f76f2a9338652c100f835c2377c908d3reed        pr->restoreMutability();
14126e0e587f76f2a9338652c100f835c2377c908d3reed    }
14297af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com}
14397af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com
144c4c9870953037be94da00ac9db887d171f6e479ccommit-bot@chromium.orgvoid SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
14597af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com    // are we sharing pixelrefs with the image?
1465ec26ae9bfca635ccc98283aad5deda11519d826bsalomon    SkAutoTUnref<SkImage> cached(this->refCachedImage(SkBudgeted::kNo, kNo_ForceUnique));
147f47b9a3b88a037a481eb70f01a4cf9f5be34dc28bsalomon    SkASSERT(cached);
148f47b9a3b88a037a481eb70f01a4cf9f5be34dc28bsalomon    if (SkBitmapImageGetPixelRef(cached) == fBitmap.pixelRef()) {
14997af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com        SkASSERT(fWeOwnThePixels);
150c4c9870953037be94da00ac9db887d171f6e479ccommit-bot@chromium.org        if (kDiscard_ContentChangeMode == mode) {
151c4c9870953037be94da00ac9db887d171f6e479ccommit-bot@chromium.org            fBitmap.allocPixels();
152c4c9870953037be94da00ac9db887d171f6e479ccommit-bot@chromium.org        } else {
153c4c9870953037be94da00ac9db887d171f6e479ccommit-bot@chromium.org            SkBitmap prev(fBitmap);
1549cd016e9b63f3827580d5b19a187dbf26b8e1436reed            fBitmap.allocPixels();
1559cd016e9b63f3827580d5b19a187dbf26b8e1436reed            prev.lockPixels();
1569cd016e9b63f3827580d5b19a187dbf26b8e1436reed            SkASSERT(prev.info() == fBitmap.info());
1579cd016e9b63f3827580d5b19a187dbf26b8e1436reed            SkASSERT(prev.rowBytes() == fBitmap.rowBytes());
1589cd016e9b63f3827580d5b19a187dbf26b8e1436reed            memcpy(fBitmap.getPixels(), prev.getPixels(), fBitmap.getSafeSize());
159c4c9870953037be94da00ac9db887d171f6e479ccommit-bot@chromium.org        }
1609cd016e9b63f3827580d5b19a187dbf26b8e1436reed        SkASSERT(fBitmap.rowBytes() == fRowBytes);  // be sure we always use the same value
1619cd016e9b63f3827580d5b19a187dbf26b8e1436reed
16297af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com        // Now fBitmap is a deep copy of itself (and therefore different from
16397af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com        // what is being used by the image. Next we update the canvas to use
16497af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com        // this as its backend, so we can't modify the image's pixels anymore.
16549f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(this->getCachedCanvas());
166acea3ef448c9903de3aa6a013c839dce577e6ce3junov@chromium.org        this->getCachedCanvas()->getDevice()->replaceBitmapBackendForRasterSurface(fBitmap);
16797af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com    }
16897af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com}
16997af1a64ae6bdddd346d8babfd9f188279dd6644reed@google.com
170c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com///////////////////////////////////////////////////////////////////////////////
171c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
172982542dce8acbd2f3e7642268b21e76b93230dafreedSkSurface* SkSurface::NewRasterDirectReleaseProc(const SkImageInfo& info, void* pixels, size_t rb,
173982542dce8acbd2f3e7642268b21e76b93230dafreed                                                 void (*releaseProc)(void* pixels, void* context),
1744a8126e7f81384526629b1e21bf89b632ea13cd9reed                                                 void* context, const SkSurfaceProps* props) {
17596fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == releaseProc) {
17696fcdcc219d2a0d3579719b84b28bede76efba64halcanary        context = nullptr;
177982542dce8acbd2f3e7642268b21e76b93230dafreed    }
178982542dce8acbd2f3e7642268b21e76b93230dafreed    if (!SkSurface_Raster::Valid(info, rb)) {
17996fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
180c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
18196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == pixels) {
18296fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
183c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
18426e0e587f76f2a9338652c100f835c2377c908d3reed
185385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    return new SkSurface_Raster(info, pixels, rb, releaseProc, context, props);
186982542dce8acbd2f3e7642268b21e76b93230dafreed}
187fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1884a8126e7f81384526629b1e21bf89b632ea13cd9reedSkSurface* SkSurface::NewRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes,
1894a8126e7f81384526629b1e21bf89b632ea13cd9reed                                      const SkSurfaceProps* props) {
19096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    return NewRasterDirectReleaseProc(info, pixels, rowBytes, nullptr, nullptr, props);
191c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com}
192c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com
1939cd016e9b63f3827580d5b19a187dbf26b8e1436reedSkSurface* SkSurface::NewRaster(const SkImageInfo& info, size_t rowBytes,
1949cd016e9b63f3827580d5b19a187dbf26b8e1436reed                                const SkSurfaceProps* props) {
195b947625800a26194fcf63d7b57dadb1a63677f6amike@reedtribe.org    if (!SkSurface_Raster::Valid(info)) {
19696fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
197c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
198fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1999cd016e9b63f3827580d5b19a187dbf26b8e1436reed    SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewZeroed(info, rowBytes, nullptr));
20096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == pr.get()) {
20196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        return nullptr;
202c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com    }
2039cd016e9b63f3827580d5b19a187dbf26b8e1436reed    if (rowBytes) {
2049cd016e9b63f3827580d5b19a187dbf26b8e1436reed        SkASSERT(pr->rowBytes() == rowBytes);
2059cd016e9b63f3827580d5b19a187dbf26b8e1436reed    }
206385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    return new SkSurface_Raster(pr, props);
207c9062047cea66575868270b4dcaeb1dab113c8a7reed@google.com}
2089cd016e9b63f3827580d5b19a187dbf26b8e1436reed
2099cd016e9b63f3827580d5b19a187dbf26b8e1436reedSkSurface* SkSurface::NewRaster(const SkImageInfo& info, const SkSurfaceProps* props) {
2109cd016e9b63f3827580d5b19a187dbf26b8e1436reed    return NewRaster(info, 0, props);
2119cd016e9b63f3827580d5b19a187dbf26b8e1436reed}
212