summaryrefslogtreecommitdiff
path: root/core/fxge/skia
diff options
context:
space:
mode:
Diffstat (limited to 'core/fxge/skia')
-rw-r--r--core/fxge/skia/fx_skia_device.cpp145
1 files 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<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<SkRSXform> m_rsxform; // accumulator for txt rotate/scale/translate
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
@@ -1311,6 +1383,7 @@ class SkiaState {
CFX_UnownedPtr<CFX_SkiaDeviceDriver> m_pDriver;
CFX_UnownedPtr<CFX_TypeFace> 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<uint16_t> 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<uint16_t>(cp.m_GlyphIndex);
}
+ if (oneAtATime)
+ useRSXform = false;
#if SHOW_TEXT_GLYPHS
SkTDArray<SkUnichar> 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<SkRSXform> 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;