#include "config.h"
#include "FontPlatformData.h"
#include "wtf/OwnArrayPtr.h"
#include "SkFontHost.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkPoint.h"
#include "SkRect.h"
extern "C" {
#include "harfbuzz-shaper.h"
}
namespace WebCore {
static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
{
return value * 64;
}
static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
{
FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
SkPaint paint;
font->setupPaint(&paint);
paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs));
for (int i = numGlyphs - 1; i >= 0; --i) {
uint16_t value;
memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t));
glyphs[i] = value;
}
*glyphsSize = numGlyphs;
return 1;
}
static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags)
{
FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
SkPaint paint;
font->setupPaint(&paint);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
OwnArrayPtr<uint16_t> glyphs16(new uint16_t[numGlyphs]);
if (!glyphs16.get())
return;
for (unsigned i = 0; i < numGlyphs; ++i)
glyphs16[i] = glyphs[i];
paint.getTextWidths(glyphs16.get(), numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
for (unsigned i = 0; i < numGlyphs; ++i) {
float value;
memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(float));
advances[i] = SkiaScalarToHarfbuzzFixed(value);
}
}
static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
{
FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
SkPaint paint;
font->setupPaint(&paint);
paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
OwnArrayPtr<uint16_t> glyphs16(new uint16_t[length]);
if (!glyphs16.get())
return 0;
int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16.get());
bool canRender = true;
for (int i = 0; i < numGlyphs; ++i) {
if (!glyphs16[i]) {
canRender = false;
break;
}
}
return canRender;
}
static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
{
FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
SkPaint paint;
if (flags & HB_ShaperFlag_UseDesignMetrics)
return HB_Err_Invalid_Argument;
font->setupPaint(&paint);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
uint16_t glyph16 = glyph;
SkPath path;
paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
int numPoints = path.getPoints(NULL, 0);
if (point >= numPoints)
return HB_Err_Invalid_SubTable;
SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1)));
if (!points)
return HB_Err_Invalid_SubTable;
path.getPoints(points, point + 1);
*xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
*yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
*resultingNumPoints = numPoints;
fastFree(points);
return HB_Err_Ok;
}
static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
{
FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
SkPaint paint;
font->setupPaint(&paint);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
uint16_t glyph16 = glyph;
SkScalar width;
SkRect bounds;
paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
metrics->yOffset = 0;
}
static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
{
FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
SkPaint paint;
font->setupPaint(&paint);
SkPaint::FontMetrics skiaMetrics;
paint.getFontMetrics(&skiaMetrics);
switch (metric) {
case HB_FontAscent:
return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
default:
return 0;
}
}
HB_FontClass harfbuzzSkiaClass = {
stringToGlyphs,
glyphsToAdvances,
canRender,
getOutlinePoint,
getGlyphMetrics,
getFontMetric,
};
HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
{
FontPlatformData* font = reinterpret_cast<FontPlatformData*>(voidface);
const size_t tableSize = SkFontHost::GetTableSize(font->uniqueID(), tag);
if (!tableSize)
return HB_Err_Invalid_Argument;
if (!buffer) {
*len = tableSize;
return HB_Err_Ok;
}
if (*len < tableSize)
return HB_Err_Invalid_Argument;
SkFontHost::GetTableData(font->uniqueID(), tag, 0, tableSize, buffer);
return HB_Err_Ok;
}
}