#include "config.h"
#include "SkiaFontWin.h"
#include "AffineTransform.h"
#include "Gradient.h"
#include "Pattern.h"
#include "PlatformContextSkia.h"
#include "PlatformSupport.h"
#include "SimpleFontData.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkShader.h"
#include "SkTemplates.h"
namespace WebCore {
#if !USE(SKIA_TEXT)
bool windowsCanHandleDrawTextShadow(GraphicsContext* context)
{
FloatSize shadowOffset;
float shadowBlur;
Color shadowColor;
ColorSpace shadowColorSpace;
bool hasShadow = context->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
return !hasShadow || (!shadowBlur && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255));
}
bool windowsCanHandleTextDrawing(GraphicsContext* context)
{
if (!windowsCanHandleTextDrawingWithoutShadow(context))
return false;
if (!windowsCanHandleDrawTextShadow(context))
return false;
return true;
}
bool windowsCanHandleTextDrawingWithoutShadow(GraphicsContext* context)
{
const AffineTransform& matrix = context->getCTM();
if (matrix.b() || matrix.c()) return false;
if (context->platformContext()->getTextDrawingMode() != TextModeFill)
return false;
if (context->fillGradient() || context->strokeGradient())
return false;
if (context->fillPattern() || context->strokePattern())
return false;
if (!context->platformContext()->isNativeFontRenderingAllowed())
return false;
return true;
}
#endif
static void skiaDrawText(SkCanvas* canvas,
const SkPoint& point,
SkPaint* paint,
const WORD* glyphs,
const int* advances,
const GOFFSET* offsets,
int numGlyphs)
{
static const size_t kLocalGlyphMax = 64;
SkScalar x = point.fX;
SkScalar y = point.fY;
if (offsets) {
SkAutoSTArray<kLocalGlyphMax, SkPoint> storage(numGlyphs);
SkPoint* pos = storage.get();
for (int i = 0; i < numGlyphs; i++) {
pos[i].set(x + SkIntToScalar(offsets[i].du),
y + -SkIntToScalar(offsets[i].dv));
x += SkIntToScalar(advances[i]);
}
canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, *paint);
} else {
SkAutoSTArray<kLocalGlyphMax * 2, SkScalar> storage(numGlyphs);
SkScalar* xpos = storage.get();
for (int i = 0; i < numGlyphs; i++) {
xpos[i] = x;
x += SkIntToScalar(advances[i]);
}
canvas->drawPosTextH(glyphs, numGlyphs * sizeof(uint16_t),
xpos, y, *paint);
}
}
static uint32_t getDefaultGDITextFlags()
{
static bool gInited;
static uint32_t gFlags;
if (!gInited) {
BOOL enabled;
gFlags = 0;
if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) {
gFlags |= SkPaint::kAntiAlias_Flag;
UINT smoothType;
if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) {
if (FE_FONTSMOOTHINGCLEARTYPE == smoothType)
gFlags |= SkPaint::kLCDRenderText_Flag;
}
}
gInited = true;
}
return gFlags;
}
static void setupPaintForFont(SkPaint* paint, PlatformContextSkia* pcs,
SkTypeface* face, float size, int quality)
{
paint->setTextSize(SkFloatToScalar(size));
paint->setTypeface(face);
uint32_t textFlags;
switch (quality) {
case NONANTIALIASED_QUALITY:
textFlags = 0;
break;
case ANTIALIASED_QUALITY:
textFlags = SkPaint::kAntiAlias_Flag;
break;
case CLEARTYPE_QUALITY:
textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag);
break;
default:
textFlags = getDefaultGDITextFlags();
break;
}
textFlags &= getDefaultGDITextFlags();
if (!pcs->couldUseLCDRenderedText()) {
textFlags &= ~SkPaint::kLCDRenderText_Flag;
textFlags |= SkPaint::kGenA8FromLCD_Flag;
}
static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag |
SkPaint::kLCDRenderText_Flag |
SkPaint::kGenA8FromLCD_Flag;
SkASSERT(!(textFlags & ~textFlagsMask));
uint32_t flags = paint->getFlags();
flags &= ~textFlagsMask;
flags |= textFlags;
paint->setFlags(flags);
}
static void paintSkiaText(GraphicsContext* context, HFONT hfont,
SkTypeface* face, float size, int quality,
int numGlyphs,
const WORD* glyphs,
const int* advances,
const GOFFSET* offsets,
const SkPoint* origin)
{
PlatformContextSkia* platformContext = context->platformContext();
SkCanvas* canvas = platformContext->canvas();
TextDrawingModeFlags textMode = platformContext->getTextDrawingMode();
if (canvas->getTopDevice()->getDeviceCapabilities() & SkDevice::kVector_Capability)
PlatformSupport::ensureFontLoaded(hfont);
SkPaint paint;
platformContext->setupPaintForFilling(&paint);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
setupPaintForFont(&paint, platformContext, face, size, quality);
bool didFill = false;
if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) {
skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs);
didFill = true;
}
if ((textMode & TextModeStroke)
&& platformContext->getStrokeStyle() != NoStroke
&& platformContext->getStrokeThickness() > 0) {
paint.reset();
platformContext->setupPaintForStroking(&paint, 0, 0);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
setupPaintForFont(&paint, platformContext, face, size, quality);
if (didFill) {
paint.setLooper(0);
}
skiaDrawText(canvas, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs);
}
}
void paintSkiaText(GraphicsContext* context,
const FontPlatformData& data,
int numGlyphs,
const WORD* glyphs,
const int* advances,
const GOFFSET* offsets,
const SkPoint* origin)
{
paintSkiaText(context, data.hfont(), data.typeface(), data.size(), data.lfQuality(),
numGlyphs, glyphs, advances, offsets, origin);
}
void paintSkiaText(GraphicsContext* context,
HFONT hfont,
int numGlyphs,
const WORD* glyphs,
const int* advances,
const GOFFSET* offsets,
const SkPoint* origin)
{
int size;
int quality;
SkTypeface* face = CreateTypefaceFromHFont(hfont, &size, &quality);
SkAutoUnref aur(face);
paintSkiaText(context, hfont, face, size, quality, numGlyphs, glyphs, advances, offsets, origin);
}
}