From 8f875507a986d10335e40a5f7c1679aff9770d0a Mon Sep 17 00:00:00 2001 From: caryclark Date: Tue, 6 Dec 2016 13:49:34 -0800 Subject: re-enable skia caching This permits consecutive path drawing or text drawing to combine if their graphics state matches. This speeds up rendering considerably when PDFium draws in many small parts. It also allows discarding changes to the clip state that have no effect from draw to draw. All corpus tests draw equivalently with caching enabled or disabled. Change the member order in CPDF_PageRenderContext so the device is flushed before the referencing annotation is deleted. Add more printf style debugging for test draws. R=dsinclair@chromium.org Review-Url: https://codereview.chromium.org/2546803003 --- core/fpdfapi/cpdf_pagerendercontext.h | 2 +- core/fpdfapi/render/cpdf_renderstatus.cpp | 2 + core/fxge/cfx_renderdevice.h | 2 + core/fxge/ge/cfx_renderdevice.cpp | 11 +- core/fxge/ifx_renderdevicedriver.cpp | 4 + core/fxge/ifx_renderdevicedriver.h | 3 + core/fxge/skia/fx_skia_device.cpp | 452 ++++++++++++++++++------------ core/fxge/skia/fx_skia_device.h | 7 +- fpdfsdk/fpdfformfill.cpp | 5 +- fpdfsdk/fpdfview.cpp | 1 + 10 files changed, 298 insertions(+), 191 deletions(-) diff --git a/core/fpdfapi/cpdf_pagerendercontext.h b/core/fpdfapi/cpdf_pagerendercontext.h index 9ddd075778..27244e7fc3 100644 --- a/core/fpdfapi/cpdf_pagerendercontext.h +++ b/core/fpdfapi/cpdf_pagerendercontext.h @@ -21,10 +21,10 @@ class CPDF_PageRenderContext { CPDF_PageRenderContext(); ~CPDF_PageRenderContext(); + std::unique_ptr m_pAnnots; std::unique_ptr m_pDevice; std::unique_ptr m_pContext; std::unique_ptr m_pRenderer; - std::unique_ptr m_pAnnots; std::unique_ptr m_pOptions; }; diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp index 88dbb030ce..b23b98cdb1 100644 --- a/core/fpdfapi/render/cpdf_renderstatus.cpp +++ b/core/fpdfapi/render/cpdf_renderstatus.cpp @@ -898,6 +898,7 @@ std::unique_ptr DrawPatternBitmap( context.AppendLayer(pPattern->form(), &mtPattern2Bitmap); context.Render(&bitmap_device, &options, nullptr); #if defined _SKIA_SUPPORT_PATHS_ + bitmap_device.Flush(); pBitmap->UnPreMultiply(); #endif return pBitmap; @@ -1553,6 +1554,7 @@ bool CPDF_RenderStatus::ProcessTransparency(CPDF_PageObject* pPageObj, pFormResource, true); bitmap_render.ProcessObjectNoClip(pPageObj, &new_matrix); #if defined _SKIA_SUPPORT_PATHS_ + bitmap_device.Flush(); bitmap->UnPreMultiply(); #endif m_bStopped = bitmap_render.m_bStopped; diff --git a/core/fxge/cfx_renderdevice.h b/core/fxge/cfx_renderdevice.h index d38b2981ba..800d0c7c52 100644 --- a/core/fxge/cfx_renderdevice.h +++ b/core/fxge/cfx_renderdevice.h @@ -227,6 +227,8 @@ class CFX_RenderDevice { int top, int bitmap_alpha, int blend_type); +#endif +#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ void Flush(); #endif diff --git a/core/fxge/ge/cfx_renderdevice.cpp b/core/fxge/ge/cfx_renderdevice.cpp index 64fa6ff452..9c67a7d1e7 100644 --- a/core/fxge/ge/cfx_renderdevice.cpp +++ b/core/fxge/ge/cfx_renderdevice.cpp @@ -354,9 +354,13 @@ CFX_RenderDevice::CFX_RenderDevice() m_RenderCaps(0), m_DeviceClass(0) {} -CFX_RenderDevice::~CFX_RenderDevice() {} +CFX_RenderDevice::~CFX_RenderDevice() { +#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ + Flush(); +#endif +} -#ifdef _SKIA_SUPPORT_ +#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ void CFX_RenderDevice::Flush() { m_pDeviceDriver.reset(); } @@ -615,6 +619,9 @@ bool CFX_RenderDevice::DrawFillStrokePath(const CFX_PathData* pPathData, blend_type)) { return false; } +#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ + bitmap_device.GetDeviceDriver()->Flush(); +#endif FX_RECT src_rect(0, 0, FXSYS_round(rect.Width() * fScaleX), FXSYS_round(rect.Height() * fScaleY)); return m_pDeviceDriver->SetDIBits(&bitmap, 0, &src_rect, rect.left, rect.top, diff --git a/core/fxge/ifx_renderdevicedriver.cpp b/core/fxge/ifx_renderdevicedriver.cpp index 07a4c27277..77af00f430 100644 --- a/core/fxge/ifx_renderdevicedriver.cpp +++ b/core/fxge/ifx_renderdevicedriver.cpp @@ -99,3 +99,7 @@ bool IFX_RenderDeviceDriver::SetBitsWithMask(const CFX_DIBSource* pBitmap, int blend_type) { return false; } + +#if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_ +void IFX_RenderDeviceDriver::Flush() {} +#endif diff --git a/core/fxge/ifx_renderdevicedriver.h b/core/fxge/ifx_renderdevicedriver.h index 6a99276eba..6a5b63ba32 100644 --- a/core/fxge/ifx_renderdevicedriver.h +++ b/core/fxge/ifx_renderdevicedriver.h @@ -103,6 +103,9 @@ class IFX_RenderDeviceDriver { int top, int bitmap_alpha, int blend_type); +#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ + virtual void Flush(); +#endif }; #endif // CORE_FXGE_IFX_RENDERDEVICEDRIVER_H_ diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp index 84db838807..9c0ea07b3c 100644 --- a/core/fxge/skia/fx_skia_device.cpp +++ b/core/fxge/skia/fx_skia_device.cpp @@ -155,28 +155,37 @@ void RgbByteOrderTransferBitmap(CFX_DIBitmap* pBitmap, #define SHOW_SKIA_PATH 0 // set to 1 to print the path contents #define DRAW_SKIA_CLIP 0 // set to 1 to draw a green rectangle around the clip -void DebugShowSkiaPath(const SkPath& path) { #if SHOW_SKIA_PATH - char buffer[4096]; - sk_bzero(buffer, sizeof(buffer)); - SkMemoryWStream stream(buffer, sizeof(buffer)); - path.dump(&stream, false, false); - printf("%s", buffer); -#endif // SHOW_SKIA_PATH +void DebugShowSkiaPaint(const SkPaint& paint) { + if (SkPaint::kFill_Style == paint.getStyle()) { + printf("fill 0x%08x\n", paint.getColor()); + } else { + printf("stroke 0x%08x width %g\n", paint.getColor(), + paint.getStrokeWidth()); + } } void DebugShowCanvasMatrix(const SkCanvas* canvas) { -#if SHOW_SKIA_PATH SkMatrix matrix = canvas->getTotalMatrix(); SkScalar m[9]; matrix.get9(m); printf("matrix (%g,%g,%g) (%g,%g,%g) (%g,%g,%g)\n", m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); -#endif // SHOW_SKIA_PATH } +#endif // SHOW_SKIA_PATH +void DebugShowSkiaPath(const SkPath& path) { #if SHOW_SKIA_PATH + char buffer[4096]; + sk_bzero(buffer, sizeof(buffer)); + SkMemoryWStream stream(buffer, sizeof(buffer)); + path.dump(&stream, false, false); + printf("%s", buffer); +#endif // SHOW_SKIA_PATH +} + void DebugShowCanvasClip(const SkCanvas* canvas) { +#if SHOW_SKIA_PATH SkRect local; SkIRect device; canvas->getClipBounds(&local); @@ -187,8 +196,10 @@ void DebugShowCanvasClip(const SkCanvas* canvas) { device.fRight, device.fBottom); const SkClipStack* clipStack = canvas->getClipStack(); clipStack->dump(); +#endif // SHOW_SKIA_PATH } +#if SHOW_SKIA_PATH void DebugShowSkiaPaint(const SkPaint& paint) { if (SkPaint::kFill_Style == paint.getStyle()) { printf("fill 0x%08x\n", paint.getColor()); @@ -634,7 +645,6 @@ bool Upsample(const CFX_DIBSource* pSource, } // namespace -#ifdef _SKIA_SUPPORT_ // Encapsulate the state used for successive text and path draws so that // they can be combined. class SkiaState { @@ -644,19 +654,35 @@ class SkiaState { kPath, }; + enum class Accumulator { + kNone, + kPath, + kText, + kOther, + }; + // mark all cached state as uninitialized - SkiaState() - : m_pFont(nullptr), + explicit SkiaState(CFX_SkiaDeviceDriver* pDriver) + : m_pDriver(pDriver), + m_pFont(nullptr), m_fontSize(0), m_fillColor(0), m_strokeColor(0), m_blendType(0), m_commandIndex(0), - m_drawText(false), - m_drawPath(false), + m_drawIndex(INT_MAX), + m_clipIndex(0), + m_type(Accumulator::kNone), + m_fillFullCover(false), m_fillPath(false), m_groupKnockout(false), - m_debugDisable(false) {} + m_debugDisable(false) +#if SHOW_SKIA_PATH + , + m_debugSaveCounter(0) +#endif + { + } bool DrawPath(const CFX_PathData* pPathData, const CFX_Matrix* pMatrix, @@ -664,21 +690,20 @@ class SkiaState { uint32_t fill_color, uint32_t stroke_color, int fill_mode, - int blend_type, - CFX_SkiaDeviceDriver* pDriver) { + int blend_type) { if (m_debugDisable) return false; - if (m_commandIndex < m_commands.count()) - FlushCommands(pDriver); - if (m_drawText) - FlushText(pDriver); - if (m_drawPath && - DrawChanged(pMatrix, pDrawState, fill_color, stroke_color, fill_mode, - blend_type, pDriver->m_bGroupKnockout)) { - FlushPath(pDriver); - } - if (!m_drawPath) { + Dump(__func__); + int drawIndex = SkTMin(m_drawIndex, m_commands.count()); + if (Accumulator::kText == m_type || drawIndex != m_commandIndex || + (Accumulator::kPath == m_type && + DrawChanged(pMatrix, pDrawState, fill_color, stroke_color, fill_mode, + blend_type, m_pDriver->m_bGroupKnockout))) { + Flush(); + } + if (Accumulator::kPath != m_type) { m_skPath.reset(); + m_fillFullCover = !!(fill_mode & FXFILL_FULLCOVER); m_fillPath = (fill_mode & 3) && fill_color; m_skPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE ? SkPath::kEvenOdd_FillType @@ -688,27 +713,31 @@ class SkiaState { m_fillColor = fill_color; m_strokeColor = stroke_color; m_blendType = blend_type; - m_groupKnockout = pDriver->m_bGroupKnockout; + m_groupKnockout = m_pDriver->m_bGroupKnockout; if (pMatrix) m_drawMatrix = *pMatrix; + m_drawIndex = m_commandIndex; + m_type = Accumulator::kPath; } SkPath skPath = BuildPath(pPathData); SkPoint delta; if (MatrixOffset(pMatrix, &delta)) skPath.offset(delta.fX, delta.fY); m_skPath.addPath(skPath); - m_drawPath = true; return true; } - void FlushPath(CFX_SkiaDeviceDriver* pDriver) { + void FlushPath() { + Dump(__func__); SkMatrix skMatrix = ToSkMatrix(m_drawMatrix); SkPaint skPaint; skPaint.setAntiAlias(true); + if (m_fillFullCover) + skPaint.setBlendMode(SkBlendMode::kPlus); int stroke_alpha = FXARGB_A(m_strokeColor); if (stroke_alpha) - pDriver->PaintStroke(&skPaint, &m_drawState, skMatrix); - SkCanvas* skCanvas = pDriver->SkiaCanvas(); + m_pDriver->PaintStroke(&skPaint, &m_drawState, skMatrix); + SkCanvas* skCanvas = m_pDriver->SkiaCanvas(); skCanvas->save(); skCanvas->concat(skMatrix); if (m_fillPath) { @@ -725,17 +754,24 @@ class SkiaState { } skPaint.setStyle(SkPaint::kFill_Style); skPaint.setColor(m_fillColor); +#ifdef _SKIA_SUPPORT_PATHS_ + m_pDriver->PreMultiply(); +#endif // _SKIA_SUPPORT_PATHS_ + DebugShowSkiaDrawPath(skCanvas, skPaint, *fillPath); skCanvas->drawPath(*fillPath, skPaint); } if (stroke_alpha) { - DebugShowSkiaPath(m_skPath); - DebugShowCanvasMatrix(skCanvas); skPaint.setStyle(SkPaint::kStroke_Style); skPaint.setColor(m_strokeColor); +#ifdef _SKIA_SUPPORT_PATHS_ + m_pDriver->PreMultiply(); +#endif // _SKIA_SUPPORT_PATHS_ + DebugShowSkiaDrawPath(skCanvas, skPaint, m_skPath); skCanvas->drawPath(m_skPath, skPaint); } skCanvas->restore(); - m_drawPath = false; + m_drawIndex = INT_MAX; + m_type = Accumulator::kNone; } bool DrawText(int nChars, @@ -743,31 +779,36 @@ class SkiaState { CFX_Font* pFont, const CFX_Matrix* pMatrix, FX_FLOAT font_size, - uint32_t color, - CFX_SkiaDeviceDriver* pDriver) { + uint32_t color) { if (m_debugDisable) return false; - if (m_commandIndex < m_commands.count()) - FlushCommands(pDriver); - if (m_drawPath) - FlushPath(pDriver); - if (m_drawText && FontChanged(pFont, pMatrix, font_size, color)) - FlushText(pDriver); - if (!m_drawText) { + Dump(__func__); + int drawIndex = SkTMin(m_drawIndex, m_commands.count()); + if (Accumulator::kPath == m_type || drawIndex != m_commandIndex || + (Accumulator::kText == m_type && + FontChanged(pFont, pMatrix, font_size, color))) { + Flush(); + } + if (Accumulator::kText != m_type) { m_positions.setCount(0); m_glyphs.setCount(0); m_pFont = pFont; m_fontSize = font_size; m_fillColor = color; m_drawMatrix = *pMatrix; + m_drawIndex = m_commandIndex; + m_type = Accumulator::kText; } int count = m_positions.count(); m_positions.setCount(nChars + count); m_glyphs.setCount(nChars + count); SkScalar flip = m_fontSize < 0 ? -1 : 1; + SkScalar vFlip = flip; + if (pFont->IsVertical()) + vFlip *= -1; for (int index = 0; index < nChars; ++index) { const FXTEXT_CHARPOS& cp = pCharPos[index]; - m_positions[index + count] = {cp.m_OriginX * flip, cp.m_OriginY * flip}; + m_positions[index + count] = {cp.m_OriginX * flip, cp.m_OriginY * vFlip}; m_glyphs[index + count] = (uint16_t)cp.m_GlyphIndex; } SkPoint delta; @@ -775,13 +816,11 @@ class SkiaState { for (int index = 0; index < nChars; ++index) m_positions[index + count].offset(delta.fX * flip, -delta.fY * flip); } - m_drawText = true; return true; } - void FlushText(CFX_SkiaDeviceDriver* pDriver) { - SkScalar flip = m_fontSize < 0 ? -1 : 1; - SkMatrix skMatrix = ToFlippedSkMatrix(m_drawMatrix, flip); + void FlushText() { + Dump(__func__); SkPaint skPaint; skPaint.setAntiAlias(true); skPaint.setColor(m_fillColor); @@ -793,60 +832,78 @@ class SkiaState { skPaint.setHinting(SkPaint::kNo_Hinting); skPaint.setTextSize(SkTAbs(m_fontSize)); skPaint.setSubpixelText(true); - SkCanvas* skCanvas = pDriver->SkiaCanvas(); + SkCanvas* skCanvas = m_pDriver->SkiaCanvas(); skCanvas->save(); + SkScalar flip = m_fontSize < 0 ? -1 : 1; + SkMatrix skMatrix = ToFlippedSkMatrix(m_drawMatrix, flip); skCanvas->concat(skMatrix); +#ifdef _SKIA_SUPPORT_PATHS_ + m_pDriver->PreMultiply(); +#endif // _SKIA_SUPPORT_PATHS_ skCanvas->drawPosText(m_glyphs.begin(), m_glyphs.count() * 2, m_positions.begin(), skPaint); skCanvas->restore(); - m_drawText = false; + m_drawIndex = INT_MAX; + m_type = Accumulator::kNone; } bool SetClipFill(const CFX_PathData* pPathData, const CFX_Matrix* pMatrix, - int fill_mode, - CFX_SkiaDeviceDriver* pDriver) { + int fill_mode) { if (m_debugDisable) return false; + Dump(__func__); SkPath skClipPath = BuildPath(pPathData); skClipPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); SkMatrix skMatrix = ToSkMatrix(*pMatrix); skClipPath.transform(skMatrix); - return SetClip(skClipPath, pDriver); + return SetClip(skClipPath); } - bool SetClip(const SkPath& skClipPath, CFX_SkiaDeviceDriver* pDriver) { + bool SetClip(const SkPath& skClipPath) { + // if a pending draw depends on clip state that is cached, flush it and draw if (m_commandIndex < m_commands.count()) { if (m_commands[m_commandIndex] == Clip::kPath && m_clips[m_commandIndex] == skClipPath) { ++m_commandIndex; return true; } - FlushCommands(pDriver); + Flush(); + } + while (m_clipIndex > m_commandIndex) { + do { + --m_clipIndex; + SkASSERT(m_clipIndex >= 0); + } while (m_commands[m_clipIndex] != Clip::kSave); + m_pDriver->SkiaCanvas()->restore(); + } + if (m_commandIndex < m_commands.count()) { + m_commands[m_commandIndex] = Clip::kPath; + m_clips[m_commandIndex] = skClipPath; + } else { + m_commands.push(Clip::kPath); + m_clips.push_back(skClipPath); } - Flush(pDriver); - m_commands.push(Clip::kPath); ++m_commandIndex; - m_clips.push_back(skClipPath); - return false; + return true; } bool SetClipStroke(const CFX_PathData* pPathData, const CFX_Matrix* pMatrix, - const CFX_GraphStateData* pGraphState, - CFX_SkiaDeviceDriver* pDriver) { + const CFX_GraphStateData* pGraphState) { if (m_debugDisable) return false; + Dump(__func__); SkPath skPath = BuildPath(pPathData); SkMatrix skMatrix = ToSkMatrix(*pMatrix); SkPaint skPaint; - pDriver->PaintStroke(&skPaint, pGraphState, skMatrix); + m_pDriver->PaintStroke(&skPaint, pGraphState, skMatrix); SkPath dst_path; skPaint.getFillPath(skPath, &dst_path); dst_path.transform(skMatrix); - return SetClip(dst_path, pDriver); + return SetClip(dst_path); } bool MatrixOffset(const CFX_Matrix* pMatrix, SkPoint* delta) { @@ -871,60 +928,38 @@ class SkiaState { return true; } - void FlushCommands(CFX_SkiaDeviceDriver* pDriver) { - if (m_commandIndex == m_commands.count()) - return; - if (m_commandIndex < m_commands.count()) - pDriver->SkiaCanvas()->restore(); - int index = m_commands.count() - 1; - if (m_commandIndex == index && m_commands[index] == Clip::kSave) - return; - for (; index > m_commandIndex; --index) { - if (m_commands[index] == Clip::kSave) - pDriver->SkiaCanvas()->restore(); - } - - if (m_commandIndex > 0) - pDriver->SkiaCanvas()->save(); - while (index > 0 && m_commands[index] != Clip::kSave) - --index; - while (++index < m_commandIndex) { - SkASSERT(m_commands[index] == Clip::kPath); - pDriver->SkiaCanvas()->clipPath(m_clips[index], SkCanvas::kIntersect_Op, - true); - } - m_commands.setCount(m_commandIndex); - m_clips.resize_back(m_commandIndex); - } - // returns true if caller should apply command to skia canvas - bool ClipSave(CFX_SkiaDeviceDriver* pDriver) { + bool ClipSave() { if (m_debugDisable) return false; + Dump(__func__); int count = m_commands.count(); - if (m_commandIndex < count) { - if (m_commands[m_commandIndex] == Clip::kSave) { + if (m_commandIndex < count - 1) { + if (Clip::kSave == m_commands[m_commandIndex + 1]) { ++m_commandIndex; return true; } - FlushCommands(pDriver); + Flush(); + AdjustClip(m_commandIndex); + m_commands[++m_commandIndex] = Clip::kSave; + m_clips[m_commandIndex] = m_skEmptyPath; + } else { + AdjustClip(m_commandIndex); + m_commands.push(Clip::kSave); + m_clips.push_back(m_skEmptyPath); + ++m_commandIndex; } - Flush(pDriver); - m_commands.push(Clip::kSave); - ++m_commandIndex; - m_clips.push_back(m_skEmptyPath); - return false; + return true; } - bool ClipRestore(CFX_SkiaDeviceDriver* pDriver) { + bool ClipRestore() { if (m_debugDisable) return false; - while (m_commandIndex > 0) { - if (m_commands[--m_commandIndex] == Clip::kSave) - return true; + Dump(__func__); + while (Clip::kSave != m_commands[--m_commandIndex]) { + SkASSERT(m_commandIndex > 0); } - Flush(pDriver); - return false; + return true; } bool DrawChanged(const CFX_Matrix* pMatrix, @@ -933,7 +968,7 @@ class SkiaState { uint32_t stroke_color, int fill_mode, int blend_type, - bool group_knockout) { + bool group_knockout) const { return MatrixChanged(pMatrix, m_drawMatrix) || StateChanged(pState, m_drawState) || fill_color != m_fillColor || stroke_color != m_strokeColor || @@ -945,12 +980,13 @@ class SkiaState { bool FontChanged(CFX_Font* pFont, const CFX_Matrix* pMatrix, FX_FLOAT font_size, - uint32_t color) { + uint32_t color) const { return pFont != m_pFont || MatrixChanged(pMatrix, m_drawMatrix) || font_size != m_fontSize || color != m_fillColor; } - bool MatrixChanged(const CFX_Matrix* pMatrix, const CFX_Matrix& refMatrix) { + bool MatrixChanged(const CFX_Matrix* pMatrix, + const CFX_Matrix& refMatrix) const { CFX_Matrix identityMatrix; if (!pMatrix) pMatrix = &identityMatrix; @@ -959,7 +995,7 @@ class SkiaState { } bool StateChanged(const CFX_GraphStateData* pState, - const CFX_GraphStateData& refState) { + const CFX_GraphStateData& refState) const { CFX_GraphStateData identityState; if (!pState) pState = &identityState; @@ -971,7 +1007,7 @@ class SkiaState { } bool DashChanged(const CFX_GraphStateData* pState, - const CFX_GraphStateData& refState) { + const CFX_GraphStateData& refState) const { bool dashArray = pState && pState->m_DashArray; if (!dashArray && !refState.m_DashArray) return false; @@ -983,39 +1019,97 @@ class SkiaState { } for (int index = 0; index < pState->m_DashCount; ++index) { if (pState->m_DashArray[index] != refState.m_DashArray[index]) - return false; + return true; } return true; } - void Flush(CFX_SkiaDeviceDriver* pDriver) { - if (m_drawPath) - FlushPath(pDriver); - if (m_drawText) - FlushText(pDriver); + void AdjustClip(int limit) { + while (m_clipIndex > limit) { + do { + --m_clipIndex; + SkASSERT(m_clipIndex >= 0); + } while (m_commands[m_clipIndex] != Clip::kSave); + m_pDriver->SkiaCanvas()->restore(); + } + while (m_clipIndex < limit) { + if (Clip::kSave == m_commands[m_clipIndex]) { + m_pDriver->SkiaCanvas()->save(); + } else { + SkASSERT(Clip::kPath == m_commands[m_clipIndex]); + m_pDriver->SkiaCanvas()->clipPath(m_clips[m_clipIndex], + SkCanvas::kIntersect_Op, true); + } + ++m_clipIndex; + } + } + + void Flush() { + if (m_debugDisable) + return; + Dump(__func__); + if (Accumulator::kPath == m_type || Accumulator::kText == m_type) { + AdjustClip(SkTMin(m_drawIndex, m_commands.count())); + Accumulator::kPath == m_type ? FlushPath() : FlushText(); + } } - void Dump(const CFX_SkiaDeviceDriver* pDriver) const { + void FlushForDraw() { + if (m_debugDisable) + return; + Flush(); // draw any pending text or path + AdjustClip(m_commandIndex); // set up clip stack with any pending state + } + +#if SHOW_SKIA_PATH + void DumpPrefix(int index) const { + if (index != m_commandIndex && index != m_drawIndex && + index != m_clipIndex) { + printf(" "); + return; + } + printf("%c%c%c> ", index == m_commandIndex ? 'x' : '-', + index == m_drawIndex ? 'd' : '-', index == m_clipIndex ? 'c' : '-'); + } + + void DumpEndPrefix() const { + int index = m_commands.count(); + if (index != m_commandIndex && index > m_drawIndex && index != m_clipIndex) + return; + printf("%c%c%c>\n", index == m_commandIndex ? 'x' : '-', + index <= m_drawIndex ? 'd' : '-', index == m_clipIndex ? 'c' : '-'); + } +#endif // SHOW_SKIA_PATH + + void Dump(const char* where) const { #if SHOW_SKIA_PATH - SkDebugf("\n\nSkia Save Count %d:\n", pDriver->m_pCanvas->getSaveCount()); - pDriver->m_pCanvas->getClipStack()->dump(); - SkDebugf("Cache:\n"); + printf("\n%s\nSkia Save Count %d:\n", where, + m_pDriver->m_pCanvas->getSaveCount()); + m_pDriver->m_pCanvas->getClipStack()->dump(); + printf("Cache:\n"); for (int index = 0; index < m_commands.count(); ++index) { - SkDebugf("%s ", m_commandIndex == index ? "-->" : " "); + DumpPrefix(index); switch (m_commands[index]) { case Clip::kSave: - SkDebugf("Save\n"); + printf("Save %d\n", ++m_debugSaveCounter); break; case Clip::kPath: m_clips[index].dump(); break; default: - SkDebugf("unknown\n"); + printf("unknown\n"); } } - if (m_commandIndex == m_commands.count()) - SkDebugf("-->\n"); + DumpEndPrefix(); #endif // SHOW_SKIA_PATH +#ifdef SK_DEBUG + int skCanvasSaveCount = m_pDriver->m_pCanvas->getSaveCount(); + int cacheSaveCount = 1; + SkASSERT(m_clipIndex <= m_commands.count()); + for (int index = 0; index < m_clipIndex; ++index) + cacheSaveCount += Clip::kSave == m_commands[index]; + SkASSERT(skCanvasSaveCount == cacheSaveCount); +#endif } private: @@ -1029,19 +1123,24 @@ class SkiaState { CFX_GraphStateData m_clipState; CFX_GraphStateData m_drawState; CFX_Matrix m_clipMatrix; + CFX_SkiaDeviceDriver* m_pDriver; CFX_Font* m_pFont; FX_FLOAT m_fontSize; uint32_t m_fillColor; uint32_t m_strokeColor; int m_blendType; int m_commandIndex; // active position in clip command stack - bool m_drawText; - bool m_drawPath; + int m_drawIndex; // position of the pending path or text draw + int m_clipIndex; // position reflecting depth of canvas clip stacck + Accumulator m_type; // type of pending draw + bool m_fillFullCover; bool m_fillPath; bool m_groupKnockout; bool m_debugDisable; // turn off cache for debugging +#if SHOW_SKIA_PATH + mutable int m_debugSaveCounter; +#endif }; -#endif // _SKIA_SUPPORT_ // convert a stroking path to scanlines void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint, @@ -1115,9 +1214,7 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap, : m_pBitmap(pBitmap), m_pOriDevice(pOriDevice), m_pRecorder(nullptr), -#ifdef _SKIA_SUPPORT_ - m_pCache(new SkiaState), -#endif + m_pCache(new SkiaState(this)), #ifdef _SKIA_SUPPORT_PATHS_ m_pClipRgn(nullptr), m_FillFlags(0), @@ -1141,7 +1238,7 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(int size_x, int size_y) : m_pBitmap(nullptr), m_pOriDevice(nullptr), m_pRecorder(new SkPictureRecorder), - m_pCache(new SkiaState), + m_pCache(new SkiaState(this)), m_bGroupKnockout(false) { m_pRecorder->beginRecording(SkIntToScalar(size_x), SkIntToScalar(size_y)); m_pCanvas = m_pRecorder->getRecordingCanvas(); @@ -1151,7 +1248,7 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder) : m_pBitmap(nullptr), m_pOriDevice(nullptr), m_pRecorder(recorder), - m_pCache(new SkiaState), + m_pCache(new SkiaState(this)), m_bGroupKnockout(false) { m_pCanvas = m_pRecorder->getRecordingCanvas(); } @@ -1164,10 +1261,7 @@ CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() { } void CFX_SkiaDeviceDriver::Flush() { -#ifdef _SKIA_SUPPORT_ - m_pCache->Flush(this); - m_pCache->FlushCommands(this); -#endif + m_pCache->Flush(); } bool CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, @@ -1176,12 +1270,10 @@ bool CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, const CFX_Matrix* pObject2Device, FX_FLOAT font_size, uint32_t color) { -#ifdef _SKIA_SUPPORT_ if (m_pCache->DrawText(nChars, pCharPos, pFont, pObject2Device, font_size, - color, this)) { + color)) { return true; } -#endif sk_sp typeface(SkSafeRef(pFont->GetDeviceCache())); SkPaint paint; paint.setAntiAlias(true); @@ -1269,9 +1361,7 @@ int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) const { } void CFX_SkiaDeviceDriver::SaveState() { -#ifdef _SKIA_SUPPORT_ - if (!m_pCache->ClipSave(this)) -#endif + if (!m_pCache->ClipSave()) m_pCanvas->save(); #ifdef _SKIA_SUPPORT_PATHS_ @@ -1283,17 +1373,10 @@ void CFX_SkiaDeviceDriver::SaveState() { } void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) { -#ifdef _SKIA_SUPPORT_ - if (!m_pCache->ClipRestore(this)) -#endif + if (!m_pCache->ClipRestore()) m_pCanvas->restore(); - if (bKeepSaved -#ifdef _SKIA_SUPPORT_ - && !m_pCache->ClipSave(this) -#endif - ) { + if (bKeepSaved && !m_pCache->ClipSave()) m_pCanvas->save(); - } #ifdef _SKIA_SUPPORT_PATHS_ m_pClipRgn.reset(); @@ -1346,10 +1429,7 @@ bool CFX_SkiaDeviceDriver::SetClip_PathFill( ) { CFX_Matrix identity; const CFX_Matrix* deviceMatrix = pObject2Device ? pObject2Device : &identity; -#ifdef _SKIA_SUPPORT_ - if (m_pCache->SetClipFill(pPathData, deviceMatrix, fill_mode, this)) - return true; -#endif // _SKIA_SUPPORT_ + bool cached = m_pCache->SetClipFill(pPathData, deviceMatrix, fill_mode); #ifdef _SKIA_SUPPORT_PATHS_ m_FillFlags = fill_mode; @@ -1365,15 +1445,18 @@ bool CFX_SkiaDeviceDriver::SetClip_PathFill( CFX_FloatRect(0, 0, (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_WIDTH), (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_HEIGHT))); // note that PDF's y-axis goes up; Skia's y-axis goes down - SkRect skClipRect = - SkRect::MakeLTRB(rectf.left, rectf.bottom, rectf.right, rectf.top); - DebugDrawSkiaClipRect(m_pCanvas, skClipRect); - m_pCanvas->clipRect(skClipRect, SkCanvas::kIntersect_Op, true); + if (!cached) { + SkRect skClipRect = + SkRect::MakeLTRB(rectf.left, rectf.bottom, rectf.right, rectf.top); + DebugDrawSkiaClipRect(m_pCanvas, skClipRect); + m_pCanvas->clipRect(skClipRect, SkCanvas::kIntersect_Op, true); + } #ifdef _SKIA_SUPPORT_PATHS_ FX_RECT rect = rectf.GetOuterRect(); m_pClipRgn->IntersectRect(rect); #endif // _SKIA_SUPPORT_PATHS_ + DebugShowCanvasClip(m_pCanvas); return true; } } @@ -1384,13 +1467,16 @@ bool CFX_SkiaDeviceDriver::SetClip_PathFill( SkMatrix skMatrix = ToSkMatrix(*deviceMatrix); skClipPath.transform(skMatrix); DebugShowSkiaPath(skClipPath); - DebugDrawSkiaClipPath(m_pCanvas, skClipPath); - m_pCanvas->clipPath(skClipPath, SkCanvas::kIntersect_Op, true); + if (!cached) { + DebugDrawSkiaClipPath(m_pCanvas, skClipPath); + m_pCanvas->clipPath(skClipPath, SkCanvas::kIntersect_Op, true); + } #ifdef _SKIA_SUPPORT_PATHS_ FX_RECT clipBox(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); SetClipMask(clipBox, skClipPath); #endif // _SKIA_SUPPORT_PATHS_ + DebugShowCanvasClip(m_pCanvas); return true; } @@ -1399,10 +1485,7 @@ bool CFX_SkiaDeviceDriver::SetClip_PathStroke( const CFX_Matrix* pObject2Device, // optional transformation const CFX_GraphStateData* pGraphState // graphic state, for pen attributes ) { -#ifdef _SKIA_SUPPORT_ - if (m_pCache->SetClipStroke(pPathData, pObject2Device, pGraphState, this)) - return true; -#endif // _SKIA_SUPPORT_ + bool cached = m_pCache->SetClipStroke(pPathData, pObject2Device, pGraphState); #ifdef _SKIA_SUPPORT_PATHS_ if (!m_pClipRgn) { @@ -1418,16 +1501,16 @@ bool CFX_SkiaDeviceDriver::SetClip_PathStroke( SkPath dst_path; skPaint.getFillPath(skPath, &dst_path); dst_path.transform(skMatrix); - DebugDrawSkiaClipPath(m_pCanvas, dst_path); -#ifdef _SKIA_SUPPORT_ - m_pCanvas->clipPath(dst_path, SkCanvas::kIntersect_Op, true); -#endif // _SKIA_SUPPORT_ - + if (!cached) { + DebugDrawSkiaClipPath(m_pCanvas, dst_path); + m_pCanvas->clipPath(dst_path, SkCanvas::kIntersect_Op, true); + } #ifdef _SKIA_SUPPORT_PATHS_ FX_RECT clipBox(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT)); SetClipMask(clipBox, dst_path); #endif // _SKIA_SUPPORT_PATHS_ + DebugShowCanvasClip(m_pCanvas); return true; } @@ -1441,15 +1524,10 @@ bool CFX_SkiaDeviceDriver::DrawPath( int blend_type) { if (fill_mode & FX_ZEROAREA_FILL) return true; -#ifdef _SKIA_SUPPORT_ if (m_pCache->DrawPath(pPathData, pObject2Device, pGraphState, fill_color, - stroke_color, fill_mode, blend_type, this)) { + stroke_color, fill_mode, blend_type)) { return true; } -#endif - SkIRect rect; - rect.set(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH), - GetDeviceCaps(FXDC_PIXEL_HEIGHT)); SkMatrix skMatrix; if (pObject2Device) skMatrix = ToSkMatrix(*pObject2Device); @@ -1513,6 +1591,7 @@ bool CFX_SkiaDeviceDriver::DrawCosmeticLine(FX_FLOAT x1, bool CFX_SkiaDeviceDriver::FillRectWithBlend(const FX_RECT* pRect, uint32_t fill_color, int blend_type) { + m_pCache->FlushForDraw(); SkPaint spaint; spaint.setAntiAlias(true); spaint.setColor(fill_color); @@ -1530,6 +1609,7 @@ bool CFX_SkiaDeviceDriver::DrawShading(const CPDF_ShadingPattern* pPattern, const FX_RECT& clip_rect, int alpha, bool bAlphaMode) { + m_pCache->FlushForDraw(); ShadingType shadingType = pPattern->GetShadingType(); if (kAxialShading != shadingType && kRadialShading != shadingType && kCoonsPatchMeshShading != shadingType) { @@ -1724,6 +1804,7 @@ bool CFX_SkiaDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap, int left, int top) { if (!srcBuffer) return true; #ifdef _SKIA_SUPPORT_ + m_pCache->FlushForDraw(); int srcWidth = m_pBitmap->GetWidth(); int srcHeight = m_pBitmap->GetHeight(); int srcRowBytes = srcWidth * sizeof(uint32_t); @@ -1749,10 +1830,11 @@ bool CFX_SkiaDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap, int left, int top) { #endif // _SKIA_SUPPORT_ #ifdef _SKIA_SUPPORT_PATHS_ + Flush(); m_pBitmap->UnPreMultiply(); FX_RECT rect(left, top, left + pBitmap->GetWidth(), top + pBitmap->GetHeight()); - CFX_DIBitmap* pBack = nullptr; + std::unique_ptr pBack; if (m_pOriDevice) { pBack = m_pOriDevice->Clone(&rect); if (!pBack) @@ -1771,12 +1853,11 @@ bool CFX_SkiaDeviceDriver::GetDIBits(CFX_DIBitmap* pBitmap, int left, int top) { top = std::min(top, 0); if (m_bRgbByteOrder) { RgbByteOrderTransferBitmap(pBitmap, 0, 0, rect.Width(), rect.Height(), - pBack, left, top); + pBack.get(), left, top); } else { - bRet = pBitmap->TransferBitmap(0, 0, rect.Width(), rect.Height(), pBack, - left, top); + bRet = pBitmap->TransferBitmap(0, 0, rect.Width(), rect.Height(), + pBack.get(), left, top); } - delete pBack; return bRet; #endif // _SKIA_SUPPORT_PATHS_ } @@ -1802,6 +1883,7 @@ bool CFX_SkiaDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap, #endif // _SKIA_SUPPORT_ #ifdef _SKIA_SUPPORT_PATHS_ + Flush(); if (pBitmap->IsAlphaMask()) { return m_pBitmap->CompositeMask( left, top, pSrcRect->Width(), pSrcRect->Height(), pBitmap, argb, @@ -1824,6 +1906,7 @@ bool CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource, uint32_t flags, int blend_type) { #ifdef _SKIA_SUPPORT_ + m_pCache->FlushForDraw(); if (!m_pBitmap->GetBuffer()) return true; CFX_Matrix m(dest_width, 0, 0, -dest_height, dest_left, @@ -1846,6 +1929,7 @@ bool CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource, FX_RECT rect(0, 0, dest_width, dest_height); return SetDIBits(pSource, argb, &rect, dest_left, dest_top, blend_type); } + Flush(); FX_RECT dest_rect(dest_left, dest_top, dest_left + dest_width, dest_top + dest_height); dest_rect.Normalize(); @@ -1871,6 +1955,7 @@ bool CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, void*& handle, int blend_type) { #ifdef _SKIA_SUPPORT_ + m_pCache->FlushForDraw(); DebugValidate(m_pBitmap, m_pOriDevice); SkColorTable* ct = nullptr; std::unique_ptr dst8Storage; @@ -1912,6 +1997,7 @@ bool CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, #endif // _SKIA_SUPPORT_ #ifdef _SKIA_SUPPORT_PATHS_ + Flush(); if (!m_pBitmap->GetBuffer()) return true; m_pBitmap->UnPreMultiply(); @@ -1925,10 +2011,12 @@ bool CFX_SkiaDeviceDriver::StartDIBits(const CFX_DIBSource* pSource, bool CFX_SkiaDeviceDriver::ContinueDIBits(void* handle, IFX_Pause* pPause) { #ifdef _SKIA_SUPPORT_ + m_pCache->FlushForDraw(); return false; #endif // _SKIA_SUPPORT_ #ifdef _SKIA_SUPPORT_PATHS_ + Flush(); if (!m_pBitmap->GetBuffer()) { return true; } diff --git a/core/fxge/skia/fx_skia_device.h b/core/fxge/skia/fx_skia_device.h index 06b7be3d82..c83f9919e0 100644 --- a/core/fxge/skia/fx_skia_device.h +++ b/core/fxge/skia/fx_skia_device.h @@ -152,8 +152,9 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { const CFX_GraphStateData* pGraphState, const SkMatrix& matrix); void Clear(uint32_t color); - void Flush(); + void Flush() override; SkPictureRecorder* GetRecorder() const { return m_pRecorder; } + void PreMultiply() { m_pBitmap->PreMultiply(); } static void PreMultiply(CFX_DIBitmap* pDIBitmap); SkCanvas* SkiaCanvas() { return m_pCanvas; } void DebugVerifyBitmapIsPreMultiplied() const; @@ -166,9 +167,7 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { CFX_DIBitmap* m_pOriDevice; SkCanvas* m_pCanvas; SkPictureRecorder* const m_pRecorder; -#ifdef _SKIA_SUPPORT_ std::unique_ptr m_pCache; -#endif #ifdef _SKIA_SUPPORT_PATHS_ std::unique_ptr m_pClipRgn; std::vector> m_StateStack; @@ -177,6 +176,6 @@ class CFX_SkiaDeviceDriver : public IFX_RenderDeviceDriver { #endif bool m_bGroupKnockout; }; -#endif // defined(_SKIA_SUPPORT_) +#endif // defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ #endif // CORE_FXGE_SKIA_FX_SKIA_DEVICE_H_ diff --git a/fpdfsdk/fpdfformfill.cpp b/fpdfsdk/fpdfformfill.cpp index 44204b766a..6b8cbaa59d 100644 --- a/fpdfsdk/fpdfformfill.cpp +++ b/fpdfsdk/fpdfformfill.cpp @@ -137,10 +137,11 @@ void FFLCommon(FPDF_FORMHANDLE hHandle, pPageView->PageView_OnDraw(pDevice.get(), &matrix, &options); #endif // PDF_ENABLE_XFA -#ifdef _SKIA_SUPPORT_PATHS + pDevice->RestoreState(false); +#ifdef _SKIA_SUPPORT_PATHS_ + pDevice->Flush(); CFXBitmapFromFPDFBitmap(bitmap)->UnPreMultiply(); #endif - pDevice->RestoreState(false); delete options.m_pOCContext; options.m_pOCContext = nullptr; } diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index f0c269a312..fb87c838d4 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -720,6 +720,7 @@ DLLEXPORT void STDCALL FPDF_RenderPageBitmap(FPDF_BITMAP bitmap, rotate, flags, true, nullptr); #ifdef _SKIA_SUPPORT_PATHS_ + pDevice->Flush(); pBitmap->UnPreMultiply(); #endif pPage->SetRenderContext(nullptr); -- cgit v1.2.3