summaryrefslogtreecommitdiff
path: root/core/fxge/skia
diff options
context:
space:
mode:
authorcaryclark <caryclark@google.com>2016-06-02 08:59:20 -0700
committerCommit bot <commit-bot@chromium.org>2016-06-02 08:59:20 -0700
commit36e258b475702bdb1a95a88fcebd78b51069c532 (patch)
tree6752f85aa4944cbc59b7e05decfd1e891ad22ed1 /core/fxge/skia
parent2235b7b52e2cedea9b5d4822de9548994362ca96 (diff)
downloadpdfium-36e258b475702bdb1a95a88fcebd78b51069c532.tar.xz
The PDFium source in core/fxge/dib implements a bit-blitting backend.
This code has several disadvantages over a more modern graphics engine: - no SIMD support - no GPU support - limited quality Further, calling this code locks in the perceived resolution, so that the output cannot be scaled without additional loss. By directing all bitmap drawing through CFX_SkiaDeviceDriver::StartDIBits, Skia can handle all appropriate bitmap optimizations. To that end, SetDIBits and StretchDIBits now call StartDIBits. Other changes: Skia's bitmaps are premultiplied. PDF contains bitmaps that are unpremultiplied. PDFium appears to use premultiplied bitmaps sometimes, and unpremultiplied bitmaps elsewhere. Add a debug check for unpremultiplied bits in Skia's driver, and add a utility to premultiply PDFium's bitmaps' bits. PDFium supports a 24 bit RGB bitmap padded to a 32 bit word. Set the high byte so that Skia can treat this as an ARGB bitmap. Defer the application of the alpha value to the draw call rather than calling MultiplyAlpha where possible. Allow the destination bitmap to be alpha 8 or argb 32. Review-Url: https://codereview.chromium.org/2025043002
Diffstat (limited to 'core/fxge/skia')
-rw-r--r--core/fxge/skia/fx_skia_device.cpp144
-rw-r--r--core/fxge/skia/fx_skia_device.h9
2 files changed, 104 insertions, 49 deletions
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index 452472e40c..86a8269b79 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -81,6 +81,45 @@ void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) {}
#undef SHOW_SKIA_PATH
#undef DRAW_SKIA_CLIP
+static void DebugVerifyBitmapIsPreMultiplied(void* buffer,
+ int width,
+ int height) {
+#ifdef SK_DEBUG
+ // verify that input is really premultiplied
+ for (int y = 0; y < height; ++y) {
+ const uint32_t* srcRow = static_cast<const uint32_t*>(buffer) + y * width;
+ for (int x = 0; x < width; ++x) {
+ uint8_t a = SkGetPackedA32(srcRow[x]);
+ uint8_t r = SkGetPackedR32(srcRow[x]);
+ uint8_t g = SkGetPackedG32(srcRow[x]);
+ uint8_t b = SkGetPackedB32(srcRow[x]);
+ SkA32Assert(a);
+ SkASSERT(r <= a);
+ SkASSERT(g <= a);
+ SkASSERT(b <= a);
+ }
+ }
+#endif
+}
+
+static void DebugValidate(const CFX_DIBitmap* bitmap,
+ const CFX_DIBitmap* device) {
+ if (bitmap) {
+ SkASSERT(bitmap->GetBPP() == 8 || bitmap->GetBPP() == 32);
+ if (bitmap->GetBPP() == 32) {
+ DebugVerifyBitmapIsPreMultiplied(bitmap->GetBuffer(), bitmap->GetWidth(),
+ bitmap->GetHeight());
+ }
+ }
+ if (device) {
+ SkASSERT(device->GetBPP() == 8 || device->GetBPP() == 32);
+ if (device->GetBPP() == 32) {
+ DebugVerifyBitmapIsPreMultiplied(device->GetBuffer(), device->GetWidth(),
+ device->GetHeight());
+ }
+ }
+}
+
SkPath BuildPath(const CFX_PathData* pPathData) {
SkPath skPath;
const CFX_PathData* pFPath = pPathData;
@@ -509,9 +548,11 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap,
m_bRgbByteOrder(bRgbByteOrder),
m_bGroupKnockout(bGroupKnockout) {
SkBitmap skBitmap;
- SkImageInfo imageInfo =
- SkImageInfo::Make(pBitmap->GetWidth(), pBitmap->GetHeight(),
- kN32_SkColorType, kOpaque_SkAlphaType);
+ SkASSERT(pBitmap->GetBPP() == 8 || pBitmap->GetBPP() == 32);
+ SkImageInfo imageInfo = SkImageInfo::Make(
+ pBitmap->GetWidth(), pBitmap->GetHeight(),
+ pBitmap->GetBPP() == 8 ? kAlpha_8_SkColorType : kN32_SkColorType,
+ kOpaque_SkAlphaType);
skBitmap.installPixels(imageInfo, pBitmap->GetBuffer(), pBitmap->GetPitch(),
nullptr, /* to do : set color table */
nullptr, nullptr);
@@ -553,7 +594,7 @@ FX_BOOL CFX_SkiaDeviceDriver::DrawDeviceText(int nChars,
uint32_t color,
int alpha_flag,
void* pIccTransform) {
- CFX_TypeFace* typeface = pCache->GetDeviceCache(pFont);
+ sk_sp<SkTypeface> typeface(SkSafeRef(pCache->GetDeviceCache(pFont)));
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(color);
@@ -932,15 +973,12 @@ FX_BOOL CFX_SkiaDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap,
void* pIccTransform) {
if (!m_pBitmap || !m_pBitmap->GetBuffer())
return TRUE;
- if (pBitmap->IsAlphaMask()) {
- return m_pBitmap->CompositeMask(
- left, top, pSrcRect->Width(), pSrcRect->Height(), pBitmap, argb,
- pSrcRect->left, pSrcRect->top, blend_type, nullptr, m_bRgbByteOrder,
- alpha_flag, pIccTransform);
- }
- return m_pBitmap->CompositeBitmap(
- left, top, pSrcRect->Width(), pSrcRect->Height(), pBitmap, pSrcRect->left,
- pSrcRect->top, blend_type, nullptr, m_bRgbByteOrder, pIccTransform);
+
+ CFX_Matrix m(pBitmap->GetWidth(), 0, 0, -pBitmap->GetHeight(), left,
+ top + pBitmap->GetHeight());
+ void* dummy;
+ return this->StartDIBits(pBitmap, 0xFF, argb, &m, 0, dummy, alpha_flag,
+ pIccTransform, blend_type);
}
FX_BOOL CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource,
@@ -956,27 +994,19 @@ FX_BOOL CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource,
int blend_type) {
if (!m_pBitmap->GetBuffer())
return TRUE;
- if (dest_width == pSource->GetWidth() &&
- dest_height == pSource->GetHeight()) {
- FX_RECT rect(0, 0, dest_width, dest_height);
- return SetDIBits(pSource, argb, &rect, dest_left, dest_top, blend_type,
- alpha_flag, pIccTransform);
- }
- FX_RECT dest_rect(dest_left, dest_top, dest_left + dest_width,
- dest_top + dest_height);
- dest_rect.Normalize();
- FX_RECT dest_clip = dest_rect;
- dest_clip.Intersect(*pClipRect);
- CFX_BitmapComposer composer;
- composer.Compose(m_pBitmap, nullptr, 255, argb, dest_clip, FALSE, FALSE,
- FALSE, m_bRgbByteOrder, alpha_flag, pIccTransform,
- blend_type);
- dest_clip.Offset(-dest_rect.left, -dest_rect.top);
- CFX_ImageStretcher stretcher(&composer, pSource, dest_width, dest_height,
- dest_clip, flags);
- if (stretcher.Start())
- stretcher.Continue(nullptr);
- return TRUE;
+ CFX_Matrix m(dest_width, 0, 0, -dest_height, dest_left,
+ dest_top + dest_height);
+
+ m_pCanvas->save();
+ SkRect skClipRect = SkRect::MakeLTRB(pClipRect->left, pClipRect->bottom,
+ pClipRect->right, pClipRect->top);
+ m_pCanvas->clipRect(skClipRect);
+ void* dummy;
+ FX_BOOL result = this->StartDIBits(pSource, 0xFF, argb, &m, 0, dummy,
+ alpha_flag, pIccTransform, blend_type);
+ m_pCanvas->restore();
+
+ return result;
}
FX_BOOL CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource,
@@ -988,9 +1018,12 @@ FX_BOOL CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource,
int alpha_flag,
void* pIccTransform,
int blend_type) {
+ DebugValidate(m_pBitmap, m_pOriDevice);
SkColorType colorType = pSource->IsAlphaMask()
? SkColorType::kAlpha_8_SkColorType
: SkColorType::kGray_8_SkColorType;
+ SkAlphaType alphaType =
+ pSource->IsAlphaMask() ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
SkColorTable* ct = nullptr;
void* buffer = pSource->GetBuffer();
std::unique_ptr<uint8_t, FxFreeDeleter> dst8Storage;
@@ -1025,23 +1058,27 @@ FX_BOOL CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource,
const uint8_t* srcRow =
static_cast<const uint8_t*>(buffer) + y * rowBytes;
uint32_t* dstRow = dst32Pixels + y * width;
- for (int x = 0; x < width; ++x)
+ for (int x = 0; x < width; ++x) {
dstRow[x] = SkPackARGB32(0xFF, srcRow[x * 3 + 2], srcRow[x * 3 + 1],
srcRow[x * 3 + 0]);
+ }
}
buffer = dst32Storage.get();
rowBytes = width * sizeof(uint32_t);
colorType = SkColorType::kN32_SkColorType;
+ alphaType = kOpaque_SkAlphaType;
} break;
case 32:
colorType = SkColorType::kN32_SkColorType;
+ alphaType = kPremul_SkAlphaType;
+ DebugVerifyBitmapIsPreMultiplied(buffer, width, height);
break;
default:
+ SkASSERT(0); // TODO(caryclark) ensure that all cases are covered
colorType = SkColorType::kUnknown_SkColorType;
}
- SkImageInfo imageInfo = SkImageInfo::Make(
- width, height, colorType,
- pSource->IsAlphaMask() ? kPremul_SkAlphaType : kOpaque_SkAlphaType);
+ SkImageInfo imageInfo =
+ SkImageInfo::Make(width, height, colorType, alphaType);
SkBitmap skBitmap;
skBitmap.installPixels(imageInfo, buffer, rowBytes, ct, nullptr, nullptr);
m_pCanvas->save();
@@ -1063,19 +1100,28 @@ FX_BOOL CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource,
m_pCanvas->restore();
if (ct)
ct->unref();
+ DebugValidate(m_pBitmap, m_pOriDevice);
return TRUE;
}
-FX_BOOL CFX_SkiaDeviceDriver::ContinueDIBits(void* pHandle, IFX_Pause* pPause) {
- if (!m_pBitmap->GetBuffer())
- return TRUE;
- return ((CFX_ImageRenderer*)pHandle)->Continue(pPause);
-}
-
-void CFX_SkiaDeviceDriver::CancelDIBits(void* pHandle) {
- if (!m_pBitmap->GetBuffer())
+void CFX_SkiaDeviceDriver::PreMultiply() {
+ void* buffer = m_pBitmap->GetBuffer();
+ if (!buffer)
return;
- delete (CFX_ImageRenderer*)pHandle;
+ if (m_pBitmap->GetBPP() != 32) {
+ return;
+ }
+ int height = m_pBitmap->GetHeight();
+ int width = m_pBitmap->GetWidth();
+ int rowBytes = m_pBitmap->GetPitch();
+ SkImageInfo unpremultipliedInfo =
+ SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType);
+ SkPixmap unpremultiplied(unpremultipliedInfo, buffer, rowBytes);
+ SkImageInfo premultipliedInfo =
+ SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
+ SkPixmap premultiplied(premultipliedInfo, buffer, rowBytes);
+ unpremultiplied.readPixels(premultiplied);
+ DebugVerifyBitmapIsPreMultiplied(buffer, width, height);
}
CFX_FxgeDevice::CFX_FxgeDevice() {
@@ -1129,4 +1175,8 @@ CFX_FxgeDevice::~CFX_FxgeDevice() {
delete GetBitmap();
}
+void CFX_FxgeDevice::PreMultiply() {
+ (static_cast<CFX_SkiaDeviceDriver*>(this->GetDeviceDriver()))->PreMultiply();
+}
+
#endif
diff --git a/core/fxge/skia/fx_skia_device.h b/core/fxge/skia/fx_skia_device.h
index dd3ba420e8..085977b66e 100644
--- a/core/fxge/skia/fx_skia_device.h
+++ b/core/fxge/skia/fx_skia_device.h
@@ -114,8 +114,12 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver {
int alpha_flag = 0,
void* pIccTransform = NULL,
int blend_type = FXDIB_BLEND_NORMAL) override;
- FX_BOOL ContinueDIBits(void* handle, IFX_Pause* pPause) override;
- void CancelDIBits(void* handle) override;
+
+ FX_BOOL ContinueDIBits(void* handle, IFX_Pause* pPause) override {
+ return FALSE;
+ }
+
+ void CancelDIBits(void* handle) override {}
FX_BOOL DrawDeviceText(int nChars,
const FXTEXT_CHARPOS* pCharPos,
@@ -138,6 +142,7 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver {
const CFX_GraphStateData* pGraphState,
const SkMatrix& matrix);
SkPictureRecorder* GetRecorder() const { return m_pRecorder; }
+ void PreMultiply();
private:
CFX_DIBitmap* m_pBitmap;