michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkDevice.h" michael@0: #include "SkMetaData.h" michael@0: michael@0: #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) michael@0: const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias = SkCanvas::kBGRA_Premul_Config8888; michael@0: #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) michael@0: const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias = SkCanvas::kRGBA_Premul_Config8888; michael@0: #else michael@0: const SkCanvas::Config8888 SkBaseDevice::kPMColorAlias = (SkCanvas::Config8888) -1; michael@0: #endif michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkBaseDevice::SkBaseDevice() michael@0: : fLeakyProperties(SkDeviceProperties::MakeDefault()) michael@0: #ifdef SK_DEBUG michael@0: , fAttachedToCanvas(false) michael@0: #endif michael@0: { michael@0: fOrigin.setZero(); michael@0: fMetaData = NULL; michael@0: } michael@0: michael@0: SkBaseDevice::SkBaseDevice(const SkDeviceProperties& deviceProperties) michael@0: : fLeakyProperties(deviceProperties) michael@0: #ifdef SK_DEBUG michael@0: , fAttachedToCanvas(false) michael@0: #endif michael@0: { michael@0: fOrigin.setZero(); michael@0: fMetaData = NULL; michael@0: } michael@0: michael@0: SkBaseDevice::~SkBaseDevice() { michael@0: delete fMetaData; michael@0: } michael@0: michael@0: SkBaseDevice* SkBaseDevice::createCompatibleDevice(const SkImageInfo& info) { michael@0: #ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG michael@0: // We call the old method to support older subclasses. michael@0: // If they have, we return their device, else we use the new impl. michael@0: SkBitmap::Config config = SkColorTypeToBitmapConfig(info.colorType()); michael@0: SkBaseDevice* dev = this->onCreateCompatibleDevice(config, michael@0: info.width(), michael@0: info.height(), michael@0: info.isOpaque(), michael@0: kGeneral_Usage); michael@0: if (dev) { michael@0: return dev; michael@0: } michael@0: // fall through to new impl michael@0: #endif michael@0: return this->onCreateDevice(info, kGeneral_Usage); michael@0: } michael@0: michael@0: SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(const SkImageInfo& info) { michael@0: #ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG michael@0: // We call the old method to support older subclasses. michael@0: // If they have, we return their device, else we use the new impl. michael@0: SkBitmap::Config config = SkColorTypeToBitmapConfig(info.colorType()); michael@0: SkBaseDevice* dev = this->onCreateCompatibleDevice(config, michael@0: info.width(), michael@0: info.height(), michael@0: info.isOpaque(), michael@0: kSaveLayer_Usage); michael@0: if (dev) { michael@0: return dev; michael@0: } michael@0: // fall through to new impl michael@0: #endif michael@0: return this->onCreateDevice(info, kSaveLayer_Usage); michael@0: } michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG michael@0: SkBaseDevice* SkBaseDevice::createCompatibleDevice(SkBitmap::Config config, michael@0: int width, int height, michael@0: bool isOpaque) { michael@0: SkImageInfo info = SkImageInfo::Make(width, height, michael@0: SkBitmapConfigToColorType(config), michael@0: isOpaque ? kOpaque_SkAlphaType michael@0: : kPremul_SkAlphaType); michael@0: return this->createCompatibleDevice(info); michael@0: } michael@0: #endif michael@0: michael@0: SkMetaData& SkBaseDevice::getMetaData() { michael@0: // metadata users are rare, so we lazily allocate it. If that changes we michael@0: // can decide to just make it a field in the device (rather than a ptr) michael@0: if (NULL == fMetaData) { michael@0: fMetaData = new SkMetaData; michael@0: } michael@0: return *fMetaData; michael@0: } michael@0: michael@0: // TODO: should make this guy pure-virtual. michael@0: SkImageInfo SkBaseDevice::imageInfo() const { michael@0: return SkImageInfo::MakeUnknown(this->width(), this->height()); michael@0: } michael@0: michael@0: const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) { michael@0: const SkBitmap& bitmap = this->onAccessBitmap(); michael@0: if (changePixels) { michael@0: bitmap.notifyPixelsChanged(); michael@0: } michael@0: return bitmap; michael@0: } michael@0: michael@0: bool SkBaseDevice::readPixels(SkBitmap* bitmap, int x, int y, michael@0: SkCanvas::Config8888 config8888) { michael@0: if (SkBitmap::kARGB_8888_Config != bitmap->config() || michael@0: NULL != bitmap->getTexture()) { michael@0: return false; michael@0: } michael@0: michael@0: const SkBitmap& src = this->accessBitmap(false); michael@0: michael@0: SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(), michael@0: bitmap->height()); michael@0: SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height()); michael@0: if (!srcRect.intersect(devbounds)) { michael@0: return false; michael@0: } michael@0: michael@0: SkBitmap tmp; michael@0: SkBitmap* bmp; michael@0: if (bitmap->isNull()) { michael@0: if (!tmp.allocPixels(SkImageInfo::MakeN32Premul(bitmap->width(), michael@0: bitmap->height()))) { michael@0: return false; michael@0: } michael@0: bmp = &tmp; michael@0: } else { michael@0: bmp = bitmap; michael@0: } michael@0: michael@0: SkIRect subrect = srcRect; michael@0: subrect.offset(-x, -y); michael@0: SkBitmap bmpSubset; michael@0: bmp->extractSubset(&bmpSubset, subrect); michael@0: michael@0: bool result = this->onReadPixels(bmpSubset, michael@0: srcRect.fLeft, michael@0: srcRect.fTop, michael@0: config8888); michael@0: if (result && bmp == &tmp) { michael@0: tmp.swap(*bitmap); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: SkSurface* SkBaseDevice::newSurface(const SkImageInfo&) { return NULL; } michael@0: michael@0: const void* SkBaseDevice::peekPixels(SkImageInfo*, size_t*) { return NULL; } michael@0: michael@0: void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, michael@0: const SkRRect& inner, const SkPaint& paint) { michael@0: SkPath path; michael@0: path.addRRect(outer); michael@0: path.addRRect(inner); michael@0: path.setFillType(SkPath::kEvenOdd_FillType); michael@0: michael@0: const SkMatrix* preMatrix = NULL; michael@0: const bool pathIsMutable = true; michael@0: this->drawPath(draw, path, paint, preMatrix, pathIsMutable); michael@0: } michael@0: michael@0: bool SkBaseDevice::writePixelsDirect(const SkImageInfo& info, const void* pixels, size_t rowBytes, michael@0: int x, int y) { michael@0: #ifdef SK_DEBUG michael@0: SkASSERT(info.width() > 0 && info.height() > 0); michael@0: SkASSERT(pixels); michael@0: SkASSERT(rowBytes >= info.minRowBytes()); michael@0: SkASSERT(x >= 0 && y >= 0); michael@0: michael@0: const SkImageInfo& dstInfo = this->imageInfo(); michael@0: SkASSERT(x + info.width() <= dstInfo.width()); michael@0: SkASSERT(y + info.height() <= dstInfo.height()); michael@0: #endif michael@0: return this->onWritePixels(info, pixels, rowBytes, x, y); michael@0: } michael@0: michael@0: bool SkBaseDevice::onWritePixels(const SkImageInfo&, const void*, size_t, int, int) { michael@0: return false; michael@0: } michael@0: michael@0: bool SkBaseDevice::onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) { michael@0: return false; michael@0: } michael@0: michael@0: void* SkBaseDevice::accessPixels(SkImageInfo* info, size_t* rowBytes) { michael@0: SkImageInfo tmpInfo; michael@0: size_t tmpRowBytes; michael@0: if (NULL == info) { michael@0: info = &tmpInfo; michael@0: } michael@0: if (NULL == rowBytes) { michael@0: rowBytes = &tmpRowBytes; michael@0: } michael@0: return this->onAccessPixels(info, rowBytes); michael@0: } michael@0: michael@0: void* SkBaseDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) { michael@0: return NULL; michael@0: } michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG michael@0: void SkBaseDevice::writePixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) {} michael@0: #endif michael@0: michael@0: void SkBaseDevice::EXPERIMENTAL_optimize(SkPicture* picture) { michael@0: // The base class doesn't perform any analysis but derived classes may michael@0: } michael@0: michael@0: bool SkBaseDevice::EXPERIMENTAL_drawPicture(const SkPicture& picture) { michael@0: // The base class doesn't perform any accelerated picture rendering michael@0: return false; michael@0: }