Chromium Code Reviews| Index: core/fxge/skia/fx_skia_device.cpp |
| diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp |
| index 4b69d2fee6b938703eb4fbb888f7e467b438255f..d434e52f142b2b1d9c2c905c87a57ec20e800137 100644 |
| --- a/core/fxge/skia/fx_skia_device.cpp |
| +++ b/core/fxge/skia/fx_skia_device.cpp |
| @@ -2,8 +2,6 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "core/fxge/include/fx_ge.h" |
| - |
| #if defined(_SKIA_SUPPORT_) |
| #include <algorithm> |
| #include <vector> |
| @@ -29,6 +27,10 @@ |
| #include "third_party/skia/include/effects/SkGradientShader.h" |
| #include "third_party/skia/include/pathops/SkPathOps.h" |
| +#ifdef SK_DEBUG |
| +#include "third_party/skia/include/core/SkClipStack.h" |
| +#endif |
| + |
| namespace { |
| #define SHOW_SKIA_PATH 0 // set to 1 to print the path contents |
| @@ -476,6 +478,404 @@ void ClipAngledGradient(const SkPoint pts[2], |
| } // namespace |
| +// Encapsulate the state used for successive text and path draws so that |
| +// they can be combined |
|
dsinclair
2016/06/29 13:22:28
nit: . at end of sentence.
caryclark
2016/06/29 13:55:10
Done.
|
| +class SkiaState { |
| + public: |
| + enum class Clip { |
| + kSave, |
| + kPath, |
| + }; |
| + |
| + // mark all cached state as uninitialized |
| + SkiaState() { |
|
dsinclair
2016/06/29 13:22:28
Initializer list?
SkiaState() : m_pFont(nullptr),
caryclark
2016/06/29 13:55:10
Done.
|
| + m_pFont = nullptr; |
| + m_pCache = nullptr; |
| + m_fontSize = 0; |
| + m_fillColor = 0; |
| + m_strokeColor = 0; |
| + m_blendType = 0; |
| + m_commandIndex = 0; |
| + m_drawText = false; |
| + m_drawPath = false; |
| + m_fillPath = false; |
| + m_debugDisable = false; |
| + } |
| + |
| + bool DrawPath(const CFX_PathData* pPathData, |
| + const CFX_Matrix* pMatrix, |
| + const CFX_GraphStateData* pDrawState, |
| + uint32_t fill_color, |
| + uint32_t stroke_color, |
| + int fill_mode, |
| + int blend_type, |
| + CFX_SkiaDeviceDriver* pDriver) { |
| + 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)) { |
| + FlushPath(pDriver); |
| + } |
| + if (!m_drawPath) { |
| + m_skPath.reset(); |
| + m_fillPath = (fill_mode & 3) && fill_color; |
| + m_skPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE |
| + ? SkPath::kEvenOdd_FillType |
| + : SkPath::kWinding_FillType); |
| + m_drawState = *pDrawState; |
| + m_fillColor = fill_color; |
| + m_strokeColor = stroke_color; |
| + m_blendType = blend_type; |
| + m_drawMatrix = *pMatrix; |
| + } |
| + 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) { |
| + SkMatrix skMatrix = ToSkMatrix(m_drawMatrix); |
| + SkPaint skPaint; |
| + skPaint.setAntiAlias(true); |
| + int stroke_alpha = FXARGB_A(m_strokeColor); |
| + if (stroke_alpha) |
| + pDriver->PaintStroke(&skPaint, &m_drawState, skMatrix); |
| + SkCanvas* skCanvas = pDriver->SkiaCanvas(); |
| + skCanvas->save(); |
| + skCanvas->concat(skMatrix); |
| + if (m_fillPath) { |
| + SkPath strokePath; |
| + const SkPath* fillPath = &m_skPath; |
| + if (stroke_alpha) { |
| + SkAlpha fillA = SkColorGetA(m_fillColor); |
| + SkAlpha strokeA = SkColorGetA(m_strokeColor); |
| + if (fillA && fillA < 0xFF && strokeA && strokeA < 0xFF) { |
| + skPaint.getFillPath(m_skPath, &strokePath); |
| + if (Op(m_skPath, strokePath, SkPathOp::kDifference_SkPathOp, |
| + &strokePath)) { |
| + fillPath = &strokePath; |
| + } |
| + } |
| + } |
| + skPaint.setStyle(SkPaint::kFill_Style); |
| + skPaint.setColor(m_fillColor); |
| + skCanvas->drawPath(*fillPath, skPaint); |
| + } |
| + if (stroke_alpha) { |
| + DebugShowSkiaPath(m_skPath); |
| + DebugShowCanvasMatrix(skCanvas); |
| + skPaint.setStyle(SkPaint::kStroke_Style); |
| + skPaint.setColor(m_strokeColor); |
| + skCanvas->drawPath(m_skPath, skPaint); |
| + } |
| + skCanvas->restore(); |
| + m_drawPath = false; |
| + } |
| + |
| + bool DrawText(int nChars, |
| + const FXTEXT_CHARPOS* pCharPos, |
| + CFX_Font* pFont, |
| + CFX_FontCache* pCache, |
| + const CFX_Matrix* pMatrix, |
| + FX_FLOAT font_size, |
| + uint32_t color, |
| + CFX_SkiaDeviceDriver* pDriver) { |
| + if (m_debugDisable) |
| + return false; |
| + if (m_commandIndex < m_commands.count()) |
| + FlushCommands(pDriver); |
| + if (m_drawPath) |
| + FlushPath(pDriver); |
| + if (m_drawText && FontChanged(pFont, pCache, pMatrix, font_size, color)) |
| + FlushText(pDriver); |
| + if (!m_drawText) { |
| + m_positions.setCount(0); |
| + m_glyphs.setCount(0); |
| + m_pFont = pFont; |
| + m_pCache = pCache; |
| + m_fontSize = font_size; |
| + m_fillColor = color; |
| + m_drawMatrix = *pMatrix; |
| + } |
| + int count = m_positions.count(); |
| + m_positions.setCount(nChars + count); |
| + m_glyphs.setCount(nChars + count); |
| + for (int index = 0; index < nChars; ++index) { |
| + const FXTEXT_CHARPOS& cp = pCharPos[index]; |
| + m_positions[index + count] = {cp.m_OriginX, cp.m_OriginY}; |
| + m_glyphs[index + count] = (uint16_t)cp.m_GlyphIndex; |
| + } |
| + SkPoint delta; |
| + if (MatrixOffset(pMatrix, &delta)) { |
| + for (int index = 0; index < nChars; ++index) |
| + m_positions[index + count].offset(delta.fX, -delta.fY); |
| + } |
| + m_drawText = true; |
| + return true; |
| + } |
| + |
| + void FlushText(CFX_SkiaDeviceDriver* pDriver) { |
| + SkMatrix skMatrix = ToFlippedSkMatrix(m_drawMatrix); |
| + SkPaint skPaint; |
| + skPaint.setAntiAlias(true); |
| + skPaint.setColor(m_fillColor); |
| + if (m_pFont->GetFace()) { // exclude placeholder test fonts |
| + sk_sp<SkTypeface> typeface(SkSafeRef(m_pCache->GetDeviceCache(m_pFont))); |
| + skPaint.setTypeface(typeface); |
| + } |
| + skPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| + skPaint.setTextSize(m_fontSize); |
| + skPaint.setSubpixelText(true); |
| + SkCanvas* skCanvas = pDriver->SkiaCanvas(); |
| + skCanvas->save(); |
| + skCanvas->concat(skMatrix); |
| + skCanvas->drawPosText(m_glyphs.begin(), m_glyphs.count() * 2, |
| + m_positions.begin(), skPaint); |
| + skCanvas->restore(); |
| + m_drawText = false; |
| + } |
| + |
| + bool SetClipFill(const CFX_PathData* pPathData, |
| + const CFX_Matrix* pMatrix, |
| + int fill_mode, |
| + CFX_SkiaDeviceDriver* pDriver) { |
| + if (m_debugDisable) |
| + return false; |
| + 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); |
| + } |
| + |
| + bool SetClip(const SkPath& skClipPath, CFX_SkiaDeviceDriver* pDriver) { |
| + 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(pDriver); |
| + m_commands.push(Clip::kPath); |
| + ++m_commandIndex; |
| + m_clips.push_back(skClipPath); |
| + return false; |
| + } |
| + |
| + bool SetClipStroke(const CFX_PathData* pPathData, |
| + const CFX_Matrix* pMatrix, |
| + const CFX_GraphStateData* pGraphState, |
| + CFX_SkiaDeviceDriver* pDriver) { |
| + if (m_debugDisable) |
| + return false; |
| + SkPath skPath = BuildPath(pPathData); |
| + SkMatrix skMatrix = ToSkMatrix(*pMatrix); |
| + SkPaint skPaint; |
| + pDriver->PaintStroke(&skPaint, pGraphState, skMatrix); |
| + SkPath dst_path; |
| + skPaint.getFillPath(skPath, &dst_path); |
| + dst_path.transform(skMatrix); |
| + return SetClip(dst_path, pDriver); |
| + } |
| + |
| + bool MatrixOffset(const CFX_Matrix* pMatrix, SkPoint* delta) { |
| + delta->set(pMatrix->e - m_drawMatrix.e, pMatrix->f - m_drawMatrix.f); |
| + if (!delta->fX && !delta->fY) |
| + return true; |
| + SkMatrix drawMatrix = ToSkMatrix(m_drawMatrix); |
| + if (!(drawMatrix.getType() & ~SkMatrix::kTranslate_Mask)) |
| + return true; |
| + SkMatrix invDrawMatrix; |
| + if (!drawMatrix.invert(&invDrawMatrix)) |
| + return false; |
| + SkMatrix invNewMatrix; |
| + SkMatrix newMatrix = ToSkMatrix(*pMatrix); |
| + if (!newMatrix.invert(&invNewMatrix)) |
| + return false; |
| + delta->set(invDrawMatrix.getTranslateX() - invNewMatrix.getTranslateX(), |
| + invDrawMatrix.getTranslateY() - invNewMatrix.getTranslateY()); |
| + return true; |
| + } |
| + |
| + // start here; more work to do thinking through flushing |
|
dsinclair
2016/06/29 13:22:28
Is this still relevant? If so, can you add a TODO(
caryclark
2016/06/29 13:55:10
Removed (Done).
|
| + |
| + 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(); |
|
dsinclair
2016/06/29 13:22:28
There is a save() but no restore below()?
caryclark
2016/06/29 13:55:10
That's correct. The save here is balanced by a sub
|
| + 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], SkRegion::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) { |
| + if (m_debugDisable) |
| + return false; |
| + int count = m_commands.count(); |
| + if (m_commandIndex < count) { |
| + if (m_commands[m_commandIndex] == Clip::kSave) { |
| + ++m_commandIndex; |
| + return true; |
| + } |
| + FlushCommands(pDriver); |
| + } |
| + Flush(pDriver); |
| + m_commands.push(Clip::kSave); |
| + ++m_commandIndex; |
| + m_clips.push_back(m_skEmptyPath); |
| + return false; |
| + } |
| + |
| + bool ClipRestore(CFX_SkiaDeviceDriver* pDriver) { |
| + if (m_debugDisable) |
| + return false; |
| + while (m_commandIndex > 0) { |
| + if (m_commands[--m_commandIndex] == Clip::kSave) |
| + return true; |
| + } |
| + Flush(pDriver); |
| + return false; |
| + } |
| + |
| + bool DrawChanged(const CFX_Matrix* pMatrix, |
| + const CFX_GraphStateData* pState, |
| + uint32_t fill_color, |
| + uint32_t stroke_color, |
| + int fill_mode, |
| + int blend_type) { |
| + return MatrixChanged(pMatrix, m_drawMatrix) || |
| + StateChanged(pState, m_drawState) || fill_color != m_fillColor || |
| + stroke_color != m_strokeColor || |
| + ((fill_mode & 3) == FXFILL_ALTERNATE) != |
| + (m_skPath.getFillType() == SkPath::kEvenOdd_FillType) || |
| + blend_type != m_blendType; |
| + } |
| + |
| + bool FontChanged(CFX_Font* pFont, |
| + CFX_FontCache* pCache, |
| + const CFX_Matrix* pMatrix, |
| + FX_FLOAT font_size, |
| + uint32_t color) { |
| + return pFont != m_pFont || pCache != m_pCache || |
| + MatrixChanged(pMatrix, m_drawMatrix) || font_size != m_fontSize || |
| + color != m_fillColor; |
| + } |
| + |
| + bool MatrixChanged(const CFX_Matrix* pMatrix, const CFX_Matrix& refMatrix) { |
| + return pMatrix->a != refMatrix.a || pMatrix->b != refMatrix.b || |
| + pMatrix->c != refMatrix.c || pMatrix->d != refMatrix.d; |
| + } |
| + |
| + bool StateChanged(const CFX_GraphStateData* pState, |
| + const CFX_GraphStateData& refState) { |
| + return pState->m_LineWidth != refState.m_LineWidth || |
| + pState->m_LineCap != refState.m_LineCap || |
| + pState->m_LineJoin != refState.m_LineJoin || |
| + pState->m_MiterLimit != refState.m_MiterLimit || |
| + DashChanged(pState, refState); |
| + } |
| + |
| + bool DashChanged(const CFX_GraphStateData* pState, |
| + const CFX_GraphStateData& refState) { |
| + if (!pState->m_DashArray && !refState.m_DashArray) |
|
dsinclair
2016/06/29 13:22:28
Can't this just be removed in favour of the check
caryclark
2016/06/29 13:55:10
The first condition returns false when both items
dsinclair
2016/06/29 13:58:34
I can't read, I mis-read the second statement as r
|
| + return false; |
| + if (!pState->m_DashArray || !refState.m_DashArray) |
| + return true; |
| + if (pState->m_DashPhase != refState.m_DashPhase || |
| + pState->m_DashCount != refState.m_DashCount) { |
| + return true; |
| + } |
| + for (int index = 0; index < pState->m_DashCount; ++index) { |
| + if (pState->m_DashArray[index] != refState.m_DashArray[index]) |
| + return false; |
| + } |
| + return true; |
| + } |
| + |
| + void Flush(CFX_SkiaDeviceDriver* pDriver) { |
| + if (m_drawPath) |
| + FlushPath(pDriver); |
| + if (m_drawText) |
| + FlushText(pDriver); |
| + } |
| + |
| +#ifdef SK_DEBUG |
| + void Dump(CFX_SkiaDeviceDriver* pDriver) { |
| + SkDebugf("\n\nSkia Save Count %d:\n", pDriver->m_pCanvas->getSaveCount()); |
| + pDriver->m_pCanvas->getClipStack()->dump(); |
| + SkDebugf("Cache:\n"); |
| + for (int index = 0; index < m_commands.count(); ++index) { |
| + SkDebugf("%s ", m_commandIndex == index ? "-->" : " "); |
| + switch (m_commands[index]) { |
| + case Clip::kSave: |
| + SkDebugf("Save\n"); |
| + break; |
| + case Clip::kPath: |
| + m_clips[index].dump(); |
| + break; |
| + default: |
| + SkDebugf("unknown\n"); |
| + } |
| + } |
| + if (m_commandIndex == m_commands.count()) |
| + SkDebugf("-->\n"); |
| + } |
| +#endif |
| + |
| + private: |
| + SkTArray<SkPath> m_clips; // stack of clips that may be reused |
| + SkTDArray<Clip> m_commands; // stack of clip-related commands |
| + SkTDArray<SkPoint> m_positions; // accumulator for text positions |
| + SkTDArray<uint16_t> m_glyphs; // accumulator for text glyphs |
| + SkPath m_skPath; // accumulator for path contours |
| + SkPath m_skEmptyPath; // used as placehold in the clips array |
| + CFX_Matrix m_drawMatrix; |
| + CFX_GraphStateData m_clipState; |
| + CFX_GraphStateData m_drawState; |
| + CFX_Matrix m_clipMatrix; |
| + CFX_Font* m_pFont; |
| + CFX_FontCache* m_pCache; |
| + 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; |
| + bool m_fillPath; |
| + bool m_debugDisable; // turn off cache for debugging |
| +}; |
| + |
| // convert a stroking path to scanlines |
| void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint, |
| const CFX_GraphStateData* pGraphState, |
| @@ -548,6 +948,7 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(CFX_DIBitmap* pBitmap, |
| : m_pBitmap(pBitmap), |
| m_pOriDevice(pOriDevice), |
| m_pRecorder(nullptr), |
| + m_pCache(new SkiaState), |
| m_bRgbByteOrder(bRgbByteOrder), |
| m_bGroupKnockout(bGroupKnockout) { |
| SkBitmap skBitmap; |
| @@ -568,6 +969,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_bRgbByteOrder(FALSE), |
| m_bGroupKnockout(FALSE) { |
| m_pRecorder->beginRecording(SkIntToScalar(size_x), SkIntToScalar(size_y)); |
| @@ -578,14 +980,22 @@ CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder) |
| : m_pBitmap(nullptr), |
| m_pOriDevice(nullptr), |
| m_pRecorder(recorder), |
| + m_pCache(new SkiaState), |
| m_bRgbByteOrder(FALSE), |
| m_bGroupKnockout(FALSE) { |
| m_pCanvas = m_pRecorder->getRecordingCanvas(); |
| } |
| CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() { |
| + Flush(); |
| if (!m_pRecorder) |
| delete m_pCanvas; |
| + delete m_pCache; |
|
dsinclair
2016/06/29 13:22:28
Not needed with unique_ptr
caryclark
2016/06/29 13:55:10
Done.
|
| +} |
| + |
| +void CFX_SkiaDeviceDriver::Flush() { |
| + m_pCache->Flush(this); |
| + m_pCache->FlushCommands(this); |
| } |
| FX_BOOL CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, |
| @@ -595,6 +1005,10 @@ FX_BOOL CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, |
| const CFX_Matrix* pObject2Device, |
| FX_FLOAT font_size, |
| uint32_t color) { |
| + if (m_pCache->DrawText(nChars, pCharPos, pFont, pCache, pObject2Device, |
| + font_size, color, this)) { |
| + return TRUE; |
| + } |
| sk_sp<SkTypeface> typeface(SkSafeRef(pCache->GetDeviceCache(pFont))); |
| SkPaint paint; |
| paint.setAntiAlias(true); |
| @@ -642,13 +1056,15 @@ int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) const { |
| } |
| void CFX_SkiaDeviceDriver::SaveState() { |
| - m_pCanvas->save(); |
| + if (!m_pCache->ClipSave(this)) |
| + m_pCanvas->save(); |
| } |
| void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) { |
| - m_pCanvas->restore(); |
| + if (!m_pCache->ClipRestore(this)) |
| + m_pCanvas->restore(); |
| if (bKeepSaved) |
| - m_pCanvas->save(); |
| + SaveState(); |
| } |
| FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathFill( |
| @@ -656,9 +1072,13 @@ FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathFill( |
| const CFX_Matrix* pObject2Device, // flips object's y-axis |
| int fill_mode // fill mode, WINDING or ALTERNATE |
| ) { |
| + CFX_Matrix identity; |
| + const CFX_Matrix* deviceMatrix = pObject2Device ? pObject2Device : &identity; |
| + if (m_pCache->SetClipFill(pPathData, deviceMatrix, fill_mode, this)) |
| + return TRUE; |
| if (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) { |
| CFX_FloatRect rectf; |
| - if (pPathData->IsRect(pObject2Device, &rectf)) { |
| + if (pPathData->IsRect(deviceMatrix, &rectf)) { |
| rectf.Intersect( |
| CFX_FloatRect(0, 0, (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_WIDTH), |
| (FX_FLOAT)GetDeviceCaps(FXDC_PIXEL_HEIGHT))); |
| @@ -666,19 +1086,19 @@ FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathFill( |
| SkRect skClipRect = |
| SkRect::MakeLTRB(rectf.left, rectf.bottom, rectf.right, rectf.top); |
| DebugDrawSkiaClipRect(m_pCanvas, skClipRect); |
| - m_pCanvas->clipRect(skClipRect); |
| + m_pCanvas->clipRect(skClipRect, SkRegion::kIntersect_Op, true); |
| return TRUE; |
| } |
| } |
| SkPath skClipPath = BuildPath(pPathData); |
| - skClipPath.setFillType((fill_mode & 3) == FXFILL_WINDING |
| - ? SkPath::kWinding_FillType |
| - : SkPath::kEvenOdd_FillType); |
| - SkMatrix skMatrix = ToSkMatrix(*pObject2Device); |
| + skClipPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE |
| + ? SkPath::kEvenOdd_FillType |
| + : SkPath::kWinding_FillType); |
| + SkMatrix skMatrix = ToSkMatrix(*deviceMatrix); |
| skClipPath.transform(skMatrix); |
| DebugShowSkiaPath(skClipPath); |
| DebugDrawSkiaClipPath(m_pCanvas, skClipPath); |
| - m_pCanvas->clipPath(skClipPath); |
| + m_pCanvas->clipPath(skClipPath, SkRegion::kIntersect_Op, true); |
| return TRUE; |
| } |
| @@ -688,18 +1108,18 @@ FX_BOOL CFX_SkiaDeviceDriver::SetClip_PathStroke( |
| const CFX_Matrix* pObject2Device, // optional transformation |
| const CFX_GraphStateData* pGraphState // graphic state, for pen attributes |
| ) { |
| + if (m_pCache->SetClipStroke(pPathData, pObject2Device, pGraphState, this)) |
| + return TRUE; |
| // build path data |
| SkPath skPath = BuildPath(pPathData); |
| - skPath.setFillType(SkPath::kWinding_FillType); |
| - |
| SkMatrix skMatrix = ToSkMatrix(*pObject2Device); |
| - SkPaint spaint; |
| - PaintStroke(&spaint, pGraphState, skMatrix); |
| + SkPaint skPaint; |
| + PaintStroke(&skPaint, pGraphState, skMatrix); |
| SkPath dst_path; |
| - spaint.getFillPath(skPath, &dst_path); |
| + skPaint.getFillPath(skPath, &dst_path); |
| dst_path.transform(skMatrix); |
| DebugDrawSkiaClipPath(m_pCanvas, dst_path); |
| - m_pCanvas->clipPath(dst_path); |
| + m_pCanvas->clipPath(dst_path, SkRegion::kIntersect_Op, true); |
| return TRUE; |
| } |
| @@ -711,6 +1131,10 @@ FX_BOOL CFX_SkiaDeviceDriver::DrawPath( |
| uint32_t stroke_color, // stroke color |
| int fill_mode, // fill mode, WINDING or ALTERNATE. 0 for not filled |
| int blend_type) { |
| + if (m_pCache->DrawPath(pPathData, pObject2Device, pGraphState, fill_color, |
| + stroke_color, fill_mode, blend_type, this)) { |
| + return TRUE; |
| + } |
| SkIRect rect; |
| rect.set(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH), |
| GetDeviceCaps(FXDC_PIXEL_HEIGHT)); |
| @@ -728,9 +1152,9 @@ FX_BOOL CFX_SkiaDeviceDriver::DrawPath( |
| m_pCanvas->save(); |
| m_pCanvas->concat(skMatrix); |
| if ((fill_mode & 3) && fill_color) { |
| - skPath.setFillType((fill_mode & 3) == FXFILL_WINDING |
| - ? SkPath::kWinding_FillType |
| - : SkPath::kEvenOdd_FillType); |
| + skPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE |
| + ? SkPath::kEvenOdd_FillType |
| + : SkPath::kWinding_FillType); |
| SkPath strokePath; |
| const SkPath* fillPath = &skPath; |
| if (pGraphState && stroke_alpha) { |
| @@ -909,7 +1333,7 @@ FX_BOOL CFX_SkiaDeviceDriver::DrawShading(const CPDF_ShadingPattern* pPattern, |
| } |
| m_pCanvas->save(); |
| if (!skClip.isEmpty()) |
| - m_pCanvas->clipPath(skClip); |
| + m_pCanvas->clipPath(skClip, SkRegion::kIntersect_Op, true); |
| m_pCanvas->concat(skMatrix); |
| m_pCanvas->drawPath(skPath, paint); |
| m_pCanvas->restore(); |
| @@ -1000,7 +1424,7 @@ FX_BOOL CFX_SkiaDeviceDriver::StretchDIBits(const CFX_DIBSource* pSource, |
| m_pCanvas->save(); |
| SkRect skClipRect = SkRect::MakeLTRB(pClipRect->left, pClipRect->bottom, |
| pClipRect->right, pClipRect->top); |
| - m_pCanvas->clipRect(skClipRect); |
| + m_pCanvas->clipRect(skClipRect, SkRegion::kIntersect_Op, true); |
| void* dummy; |
| FX_BOOL result = StartDIBits(pSource, 0xFF, argb, &m, 0, dummy, blend_type); |
| m_pCanvas->restore(); |
| @@ -1125,6 +1549,13 @@ void CFX_SkiaDeviceDriver::PreMultiply() { |
| DebugVerifyBitmapIsPreMultiplied(buffer, width, height); |
| } |
| +void CFX_SkiaDeviceDriver::Dump() { |
| +#ifdef SK_DEBUG |
| + if (m_pCache) |
| + m_pCache->Dump(this); |
| +#endif |
| +} |
| + |
| CFX_FxgeDevice::CFX_FxgeDevice() { |
| m_bOwnedBitmap = FALSE; |
| } |