FontChromiumWin.cpp [plain text]
#include "config.h"
#include "Font.h"
#include "TransformationMatrix.h"
#include "ChromiumBridge.h"
#include "FontFallbackList.h"
#include "GlyphBuffer.h"
#include "PlatformContextSkia.h"
#include "SimpleFontData.h"
#include "SkiaFontWin.h"
#include "SkiaUtils.h"
#include "UniscribeHelperTextRun.h"
#include "skia/ext/platform_canvas_win.h"
#include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency.
#include <windows.h>
namespace WebCore {
static bool windowsCanHandleTextDrawing(GraphicsContext* context)
{
const TransformationMatrix& matrix = context->getCTM();
if (matrix.b() != 0 || matrix.c() != 0) return false;
if (context->platformContext()->getTextDrawingMode() != cTextFill)
return false;
if (context->platformContext()->getDrawLooper())
return false;
return true;
}
static bool skiaDrawText(HFONT hfont,
SkCanvas* canvas,
const SkPoint& point,
SkPaint* paint,
const WORD* glyphs,
const int* advances,
int numGlyphs)
{
HDC dc = GetDC(0);
HGDIOBJ oldFont = SelectObject(dc, hfont);
canvas->save();
canvas->translate(point.fX, point.fY);
for (int i = 0; i < numGlyphs; i++) {
const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);
if (!path)
return false;
canvas->drawPath(*path, *paint);
canvas->translate(advances[i], 0);
}
canvas->restore();
SelectObject(dc, oldFont);
ReleaseDC(0, dc);
return true;
}
static bool paintSkiaText(PlatformContextSkia* platformContext,
HFONT hfont,
int numGlyphs,
const WORD* glyphs,
const int* advances,
const SkPoint& origin)
{
int textMode = platformContext->getTextDrawingMode();
SkPaint paint;
platformContext->setupPaintForFilling(&paint);
paint.setFlags(SkPaint::kAntiAlias_Flag);
bool didFill = false;
if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) {
if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs))
return false;
didFill = true;
}
if ((textMode & WebCore::cTextStroke)
&& platformContext->getStrokeStyle() != NoStroke
&& platformContext->getStrokeThickness() > 0) {
paint.reset();
platformContext->setupPaintForStroking(&paint, 0, 0);
paint.setFlags(SkPaint::kAntiAlias_Flag);
if (didFill) {
paint.setLooper(0)->safeUnref();
}
if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs))
return false;
}
return true;
}
void Font::drawGlyphs(GraphicsContext* graphicsContext,
const SimpleFontData* font,
const GlyphBuffer& glyphBuffer,
int from,
int numGlyphs,
const FloatPoint& point) const
{
PlatformGraphicsContext* context = graphicsContext->platformContext();
const int kMaxBufferLength = 1024;
const int kDefaultBufferLength = 256;
SkColor color = context->fillColor();
unsigned char alpha = SkColorGetA(color);
if (!alpha && context->getStrokeStyle() == NoStroke)
return;
HDC hdc = context->canvas()->beginPlatformPaint();
HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont());
color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
SetTextColor(hdc, skia::SkColorToCOLORREF(color));
SetBkMode(hdc, TRANSPARENT);
Vector<WORD, kDefaultBufferLength> glyphs;
Vector<int, kDefaultBufferLength> advances;
int x = static_cast<int>(point.x());
int lineTop = static_cast<int>(point.y()) - font->ascent();
bool canUseGDI = windowsCanHandleTextDrawing(graphicsContext);
int glyphIndex = 0;
while (glyphIndex < numGlyphs) {
int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
glyphs.resize(curLen);
advances.resize(curLen);
int curWidth = 0;
for (int i = 0; i < curLen; ++i, ++glyphIndex) {
glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
curWidth += advances[i];
}
bool success = false;
for (int executions = 0; executions < 2; ++executions) {
if (canUseGDI)
success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), curLen, &advances[0]);
else {
SkPoint origin = { x, point.y() };
success = paintSkiaText(context, font->platformData().hfont(), numGlyphs, reinterpret_cast<const WORD*>(&glyphs[0]), &advances[0], origin);
}
if (!success && executions == 0) {
ChromiumBridge::ensureFontLoaded(font->platformData().hfont());
continue;
}
break;
}
ASSERT(success);
x += curWidth;
}
SelectObject(hdc, oldFont);
context->canvas()->endPlatformPaint();
}
FloatRect Font::selectionRectForComplexText(const TextRun& run,
const IntPoint& point,
int h,
int from,
int to) const
{
UniscribeHelperTextRun state(run, *this);
float left = static_cast<float>(point.x() + state.characterToX(from));
float right = static_cast<float>(point.x() + state.characterToX(to));
if (left < right)
return FloatRect(left, static_cast<float>(point.y()),
right - left, static_cast<float>(h));
return FloatRect(right, static_cast<float>(point.y()),
left - right, static_cast<float>(h));
}
void Font::drawComplexText(GraphicsContext* graphicsContext,
const TextRun& run,
const FloatPoint& point,
int from,
int to) const
{
PlatformGraphicsContext* context = graphicsContext->platformContext();
UniscribeHelperTextRun state(run, *this);
SkColor color = context->fillColor();
unsigned char alpha = SkColorGetA(color);
if (!alpha)
return;
HDC hdc = context->canvas()->beginPlatformPaint();
color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
SetTextColor(hdc, skia::SkColorToCOLORREF(color));
SetBkMode(hdc, TRANSPARENT);
state.draw(hdc, static_cast<int>(point.x()), static_cast<int>(point.y() - ascent()), from, to);
context->canvas()->endPlatformPaint();
}
float Font::floatWidthForComplexText(const TextRun& run) const
{
UniscribeHelperTextRun state(run, *this);
return static_cast<float>(state.width());
}
int Font::offsetForPositionForComplexText(const TextRun& run, int x,
bool includePartialGlyphs) const
{
UniscribeHelperTextRun state(run, *this);
int charIndex = state.xToCharacter(x);
if (charIndex < 0)
charIndex = 0;
return charIndex;
}
}