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