summaryrefslogtreecommitdiff
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
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
-rw-r--r--core/fpdfapi/fpdf_render/fpdf_render.cpp9
-rw-r--r--core/fpdfapi/fpdf_render/fpdf_render_image.cpp11
-rw-r--r--core/fxge/dib/fx_dib_main.cpp5
-rw-r--r--core/fxge/include/fx_ge.h1
-rw-r--r--core/fxge/skia/fx_skia_device.cpp144
-rw-r--r--core/fxge/skia/fx_skia_device.h9
6 files changed, 128 insertions, 51 deletions
diff --git a/core/fpdfapi/fpdf_render/fpdf_render.cpp b/core/fpdfapi/fpdf_render/fpdf_render.cpp
index a3dbbdb3f2..6ac78ecd43 100644
--- a/core/fpdfapi/fpdf_render/fpdf_render.cpp
+++ b/core/fpdfapi/fpdf_render/fpdf_render.cpp
@@ -815,14 +815,19 @@ FX_BOOL CPDF_RenderStatus::ProcessTransparency(const CPDF_PageObject* pPageObj,
bitmap->MultiplyAlpha(pTextMask.get());
pTextMask.reset();
}
+ int32_t blitAlpha = 255;
if (Transparency & PDFTRANS_GROUP && group_alpha != 1.0f) {
- bitmap->MultiplyAlpha((int32_t)(group_alpha * 255));
+ blitAlpha = (int32_t)(group_alpha * 255);
+#ifndef _SKIA_SUPPORT_
+ bitmap->MultiplyAlpha(blitAlpha);
+ blitAlpha = 255;
+#endif
}
Transparency = m_Transparency;
if (pPageObj->IsForm()) {
Transparency |= PDFTRANS_GROUP;
}
- CompositeDIBitmap(bitmap, rect.left, rect.top, 0, 255, blend_type,
+ CompositeDIBitmap(bitmap, rect.left, rect.top, 0, blitAlpha, blend_type,
Transparency);
return TRUE;
}
diff --git a/core/fpdfapi/fpdf_render/fpdf_render_image.cpp b/core/fpdfapi/fpdf_render/fpdf_render_image.cpp
index d3fbb7990c..acfb20314a 100644
--- a/core/fpdfapi/fpdf_render/fpdf_render_image.cpp
+++ b/core/fpdfapi/fpdf_render/fpdf_render_image.cpp
@@ -48,7 +48,15 @@ void CPDF_RenderStatus::CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
if (blend_mode == FXDIB_BLEND_NORMAL) {
if (!pDIBitmap->IsAlphaMask()) {
if (bitmap_alpha < 255) {
+#ifdef _SKIA_SUPPORT_
+ void* dummy;
+ CFX_Matrix m(pDIBitmap->GetWidth(), 0, 0, -pDIBitmap->GetHeight(), left,
+ top + pDIBitmap->GetHeight());
+ m_pDevice->StartDIBits(pDIBitmap, bitmap_alpha, 0, &m, 0, dummy);
+ return;
+#else
pDIBitmap->MultiplyAlpha(bitmap_alpha);
+#endif
}
if (m_pDevice->SetDIBits(pDIBitmap, left, top)) {
return;
@@ -693,6 +701,9 @@ FX_BOOL CPDF_ImageRenderer::DrawMaskedImage() {
}
bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask);
bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
+#ifdef _SKIA_SUPPORT_
+ bitmap_device1.PreMultiply(); // convert unpremultiplied to premultiplied
+#endif
if (m_BitmapAlpha < 255) {
bitmap_device1.GetBitmap()->MultiplyAlpha(m_BitmapAlpha);
}
diff --git a/core/fxge/dib/fx_dib_main.cpp b/core/fxge/dib/fx_dib_main.cpp
index 85df71e11d..896551401a 100644
--- a/core/fxge/dib/fx_dib_main.cpp
+++ b/core/fxge/dib/fx_dib_main.cpp
@@ -344,6 +344,11 @@ void CFX_DIBitmap::Clear(uint32_t color) {
case FXDIB_Rgb32:
case FXDIB_Argb: {
color = IsCmykImage() ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
+#ifdef _SKIA_SUPPORT_
+ if (FXDIB_Rgb32 == GetFormat() && !IsCmykImage()) {
+ color |= 0xFF000000;
+ }
+#endif
for (int i = 0; i < m_Width; i++) {
((uint32_t*)m_pBuffer)[i] = color;
}
diff --git a/core/fxge/include/fx_ge.h b/core/fxge/include/fx_ge.h
index 6a3113d070..8111e46d13 100644
--- a/core/fxge/include/fx_ge.h
+++ b/core/fxge/include/fx_ge.h
@@ -412,6 +412,7 @@ class CFX_FxgeDevice : public CFX_RenderDevice {
#ifdef _SKIA_SUPPORT_
bool AttachRecorder(SkPictureRecorder* recorder);
SkPictureRecorder* CreateRecorder(int size_x, int size_y);
+ void PreMultiply();
#endif
protected:
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;