From d10d8777fa0790fd589df1eedaf0643d26260404 Mon Sep 17 00:00:00 2001 From: Cary Clark Date: Wed, 5 Jul 2017 16:41:51 -0400 Subject: support m_bGlyph_Adjust MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skia has no direct match for a different 2x3 matrix per glyph -- if the 2x3 is a square scale with rotation, we can do that with RSX transforms. The bug used the 2x3 to do a condensed face, which we can do with SkPaint::setTextScaleX. Otherwise, we draw a character at a time. R=dsinclair@chromium.org,npm@chromium.org Bug: 736703 Change-Id: I8f14fd63ffdaee886b63d1154b771f9de092a83f Reviewed-on: https://pdfium-review.googlesource.com/7272 Commit-Queue: Cary Clark Reviewed-by: dsinclair Reviewed-by: Nicolás Peña --- core/fxge/skia/fx_skia_device.cpp | 145 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 5 deletions(-) diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp index 40b1ccb665..ad3b85c1fb 100644 --- a/core/fxge/skia/fx_skia_device.cpp +++ b/core/fxge/skia/fx_skia_device.cpp @@ -32,6 +32,7 @@ #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkRSXform.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkStream.h" #include "third_party/skia/include/core/SkTypeface.h" @@ -664,6 +665,7 @@ class SkiaState { : m_pDriver(pDriver), m_pTypeFace(nullptr), m_fontSize(0), + m_scaleX(0), m_fillColor(0), m_strokeColor(0), m_blendType(0), @@ -772,6 +774,38 @@ class SkiaState { m_type = Accumulator::kNone; } + bool HasRSX(int nChars, + const FXTEXT_CHARPOS* pCharPos, + float* scaleXPtr, + bool* oneAtATimePtr) { + bool useRSXform = false; + bool oneAtATime = false; + float scaleX = 1; + for (int index = 0; index < nChars; ++index) { + const FXTEXT_CHARPOS& cp = pCharPos[index]; + if (!cp.m_bGlyphAdjust) + continue; + bool upright = 0 == cp.m_AdjustMatrix[1] && 0 == cp.m_AdjustMatrix[2]; + if (cp.m_AdjustMatrix[0] != cp.m_AdjustMatrix[3]) { + if (upright && 1 == cp.m_AdjustMatrix[3]) { + if (1 == scaleX) + scaleX = cp.m_AdjustMatrix[0]; + else if (scaleX != cp.m_AdjustMatrix[0]) + oneAtATime = true; + } else { + oneAtATime = true; + } + } else if (cp.m_AdjustMatrix[1] != -cp.m_AdjustMatrix[2]) { + oneAtATime = true; + } else { + useRSXform = true; + } + } + *oneAtATimePtr = oneAtATime; + *scaleXPtr = oneAtATime ? 1 : scaleX; + return oneAtATime ? false : useRSXform; + } + bool DrawText(int nChars, const FXTEXT_CHARPOS* pCharPos, CFX_Font* pFont, @@ -781,10 +815,18 @@ class SkiaState { if (m_debugDisable) return false; Dump(__func__); + float scaleX = 1; + bool oneAtATime = false; + bool hasRSX = HasRSX(nChars, pCharPos, &scaleX, &oneAtATime); + if (oneAtATime) { + Flush(); + return false; + } 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))) { + (FontChanged(pFont, pMatrix, font_size, scaleX, color) || + hasRSX == !m_rsxform.count()))) { Flush(); } if (Accumulator::kText != m_type) { @@ -792,6 +834,7 @@ class SkiaState { m_glyphs.setCount(0); m_pTypeFace = pFont->GetFace() ? pFont->GetDeviceCache() : nullptr; m_fontSize = font_size; + m_scaleX = scaleX; m_fillColor = color; m_drawMatrix = *pMatrix; m_drawIndex = m_commandIndex; @@ -800,6 +843,9 @@ class SkiaState { int count = m_positions.count(); m_positions.setCount(nChars + count); m_glyphs.setCount(nChars + count); + if (hasRSX) { + m_rsxform.setCount(nChars + count); + } SkScalar flip = m_fontSize < 0 ? -1 : 1; SkScalar vFlip = flip; if (pFont->IsVertical()) @@ -815,6 +861,23 @@ class SkiaState { for (int index = 0; index < nChars; ++index) m_positions[index + count].offset(delta.fX * flip, -delta.fY * flip); } + if (hasRSX) { + for (int index = 0; index < nChars; ++index) { + const FXTEXT_CHARPOS& cp = pCharPos[index]; + SkRSXform* rsxform = &m_rsxform[index + count]; + if (cp.m_bGlyphAdjust) { + rsxform->fSCos = cp.m_AdjustMatrix[0]; + rsxform->fSSin = cp.m_AdjustMatrix[1]; + rsxform->fTx = cp.m_AdjustMatrix[0] * m_positions[index].fX; + rsxform->fTy = cp.m_AdjustMatrix[1] * m_positions[index].fY; + } else { + rsxform->fSCos = 1; + rsxform->fSSin = 0; + rsxform->fTx = m_positions[index].fX; + rsxform->fTy = m_positions[index].fY; + } + } + } return true; } @@ -829,6 +892,7 @@ class SkiaState { } skPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); skPaint.setHinting(SkPaint::kNo_Hinting); + skPaint.setTextScaleX(m_scaleX); skPaint.setTextSize(SkTAbs(m_fontSize)); skPaint.setSubpixelText(true); SkCanvas* skCanvas = m_pDriver->SkiaCanvas(); @@ -847,8 +911,13 @@ class SkiaState { printf("%lc", m_glyphs[i]); printf("\n"); #endif - skCanvas->drawPosText(m_glyphs.begin(), m_glyphs.count() * 2, - m_positions.begin(), skPaint); + if (m_rsxform.count()) { + skCanvas->drawTextRSXform(m_glyphs.begin(), m_glyphs.count() * 2, + m_rsxform.begin(), nullptr, skPaint); + } else { + skCanvas->drawPosText(m_glyphs.begin(), m_glyphs.count() * 2, + m_positions.begin(), skPaint); + } skCanvas->restore(); m_drawIndex = INT_MAX; m_type = Accumulator::kNone; @@ -1006,11 +1075,13 @@ class SkiaState { bool FontChanged(CFX_Font* pFont, const CFX_Matrix* pMatrix, float font_size, + float scaleX, uint32_t color) const { CFX_TypeFace* typeface = pFont->GetFace() ? pFont->GetDeviceCache() : nullptr; return typeface != m_pTypeFace || MatrixChanged(pMatrix, m_drawMatrix) || - font_size != m_fontSize || color != m_fillColor; + font_size != m_fontSize || scaleX != m_scaleX || + color != m_fillColor; } bool MatrixChanged(const CFX_Matrix* pMatrix, @@ -1301,6 +1372,7 @@ class SkiaState { SkTArray m_clips; // stack of clips that may be reused SkTDArray m_commands; // stack of clip-related commands SkTDArray m_positions; // accumulator for text positions + SkTDArray m_rsxform; // accumulator for txt rotate/scale/translate SkTDArray m_glyphs; // accumulator for text glyphs SkPath m_skPath; // accumulator for path contours SkPath m_skEmptyPath; // used as placehold in the clips array @@ -1311,6 +1383,7 @@ class SkiaState { CFX_UnownedPtr m_pDriver; CFX_UnownedPtr m_pTypeFace; float m_fontSize; + float m_scaleX; uint32_t m_fillColor; uint32_t m_strokeColor; int m_blendType; @@ -1487,11 +1560,22 @@ bool CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, positions.setCount(nChars); SkTDArray glyphs; glyphs.setCount(nChars); + bool useRSXform = false; + bool oneAtATime = false; for (int index = 0; index < nChars; ++index) { const FXTEXT_CHARPOS& cp = pCharPos[index]; positions[index] = {cp.m_Origin.x * flip, cp.m_Origin.y * vFlip}; + if (cp.m_bGlyphAdjust) { + useRSXform = true; + if (cp.m_AdjustMatrix[0] != cp.m_AdjustMatrix[3] || + cp.m_AdjustMatrix[1] != -cp.m_AdjustMatrix[2]) { + oneAtATime = true; + } + } glyphs[index] = static_cast(cp.m_GlyphIndex); } + if (oneAtATime) + useRSXform = false; #if SHOW_TEXT_GLYPHS SkTDArray text; text.setCount(glyphs.count()); @@ -1503,7 +1587,58 @@ bool CFX_SkiaDeviceDriver::DrawDeviceText(int nChars, #ifdef _SKIA_SUPPORT_PATHS_ m_pBitmap->PreMultiply(); #endif // _SKIA_SUPPORT_PATHS_ - m_pCanvas->drawPosText(glyphs.begin(), nChars * 2, positions.begin(), paint); + if (useRSXform) { + SkTDArray xforms; + xforms.setCount(nChars); + for (int index = 0; index < nChars; ++index) { + const FXTEXT_CHARPOS& cp = pCharPos[index]; + SkRSXform* rsxform = &xforms[index]; + if (cp.m_bGlyphAdjust) { + rsxform->fSCos = cp.m_AdjustMatrix[0]; + rsxform->fSSin = cp.m_AdjustMatrix[1]; + rsxform->fTx = cp.m_AdjustMatrix[0] * positions[index].fX; + rsxform->fTy = cp.m_AdjustMatrix[1] * positions[index].fY; + } else { + rsxform->fSCos = 1; + rsxform->fSSin = 0; + rsxform->fTx = positions[index].fX; + rsxform->fTy = positions[index].fY; + } + } + m_pCanvas->drawTextRSXform(glyphs.begin(), nChars * 2, xforms.begin(), + nullptr, paint); + } else if (oneAtATime) { + for (int index = 0; index < nChars; ++index) { + const FXTEXT_CHARPOS& cp = pCharPos[index]; + if (cp.m_bGlyphAdjust) { + if (0 == cp.m_AdjustMatrix[1] && 0 == cp.m_AdjustMatrix[2] && + 1 == cp.m_AdjustMatrix[3]) { + paint.setTextScaleX(cp.m_AdjustMatrix[0]); + m_pCanvas->drawText(&glyphs[index], 1, positions[index].fX, + positions[index].fY, paint); + paint.setTextScaleX(1); + } else { + m_pCanvas->save(); + SkMatrix adjust; + adjust.reset(); + adjust.setScaleX(cp.m_AdjustMatrix[0]); + adjust.setSkewX(cp.m_AdjustMatrix[1]); + adjust.setSkewY(cp.m_AdjustMatrix[2]); + adjust.setScaleY(cp.m_AdjustMatrix[3]); + adjust.preTranslate(positions[index].fX, positions[index].fY); + m_pCanvas->concat(adjust); + m_pCanvas->drawText(&glyphs[index], 1, 0, 0, paint); + m_pCanvas->restore(); + } + } else { + m_pCanvas->drawText(&glyphs[index], 1, positions[index].fX, + positions[index].fY, paint); + } + } + } else { + m_pCanvas->drawPosText(glyphs.begin(), nChars * 2, positions.begin(), + paint); + } m_pCanvas->restore(); return true; -- cgit v1.2.3