blob: f6f7b452468e35eb48e896a71e528e0a828148de [file] [log] [blame]
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -08001/*
2 * Copyright 2011, The Android Open Source Project
3 * Copyright 2011, Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "HarfbuzzSkia.h"
28
29#include "SkFontHost.h"
30
31#include "SkPaint.h"
32#include "SkPath.h"
33#include "SkPoint.h"
34#include "SkRect.h"
35#include "SkTypeface.h"
36
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070037#include <utils/Log.h>
38
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080039extern "C" {
40#include "harfbuzz-shaper.h"
41}
42
43// This file implements the callbacks which Harfbuzz requires by using Skia
44// calls. See the Harfbuzz source for references about what these callbacks do.
45
46namespace android {
47
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080048static void setupPaintWithFontData(SkPaint* paint, FontData* data) {
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080049 paint->setTypeface(data->typeFace);
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070050 paint->setTextSize(data->textSize);
51 paint->setTextSkewX(data->textSkewX);
52 paint->setTextScaleX(data->textScaleX);
53 paint->setFlags(data->flags);
54 paint->setHinting(data->hinting);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080055}
56
57static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length,
58 HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
59{
60 FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
61 SkPaint paint;
62 setupPaintWithFontData(&paint, data);
63
64 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070065 uint16_t* skiaGlyphs = reinterpret_cast<uint16_t*>(glyphs);
66 int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), skiaGlyphs);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080067
68 // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
69 // |glyphs| array needs to be converted.
70 for (int i = numGlyphs - 1; i >= 0; --i) {
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070071 glyphs[i] = skiaGlyphs[i];
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080072 }
73
74 *glyphsSize = numGlyphs;
75 return 1;
76}
77
78static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs,
79 HB_Fixed* advances, int flags)
80{
81 FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
82 SkPaint paint;
83 setupPaintWithFontData(&paint, data);
84
85 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
86
87 uint16_t* glyphs16 = new uint16_t[numGlyphs];
88 if (!glyphs16)
89 return;
90 for (unsigned i = 0; i < numGlyphs; ++i)
91 glyphs16[i] = glyphs[i];
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070092 SkScalar* scalarAdvances = reinterpret_cast<SkScalar*>(advances);
93 paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarAdvances);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080094
95 // The |advances| values which Skia outputs are SkScalars, which are floats
96 // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
97 // These two formats are both 32-bits long.
98 for (unsigned i = 0; i < numGlyphs; ++i) {
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070099 advances[i] = SkScalarToHBFixed(scalarAdvances[i]);
100#if DEBUG_ADVANCES
101 LOGD("glyphsToAdvances -- advances[%d]=%d", i, advances[i]);
102#endif
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800103 }
104 delete glyphs16;
105}
106
107static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
108{
109 FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
110 SkPaint paint;
111 setupPaintWithFontData(&paint, data);
112
113 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
114
115 uint16_t* glyphs16 = new uint16_t[length];
116 int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16);
117
118 bool result = true;
119 for (int i = 0; i < numGlyphs; ++i) {
120 if (!glyphs16[i]) {
121 result = false;
122 break;
123 }
124 }
125 delete glyphs16;
126 return result;
127}
128
129static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point,
130 HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
131{
132 FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
133 SkPaint paint;
134 setupPaintWithFontData(&paint, data);
135
136 if (flags & HB_ShaperFlag_UseDesignMetrics)
137 // This is requesting pre-hinted positions. We can't support this.
138 return HB_Err_Invalid_Argument;
139
140 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
141 uint16_t glyph16 = glyph;
142 SkPath path;
143 paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
144 uint32_t numPoints = path.getPoints(0, 0);
145 if (point >= numPoints)
146 return HB_Err_Invalid_SubTable;
147 SkPoint* points = reinterpret_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1)));
148 if (!points)
149 return HB_Err_Invalid_SubTable;
150 // Skia does let us get a single point from the path.
151 path.getPoints(points, point + 1);
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700152 *xPos = SkScalarToHBFixed(points[point].fX);
153 *yPos = SkScalarToHBFixed(points[point].fY);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800154 *resultingNumPoints = numPoints;
155 delete points;
156
157 return HB_Err_Ok;
158}
159
160static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
161{
162 FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
163 SkPaint paint;
164 setupPaintWithFontData(&paint, data);
165
166 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
167 uint16_t glyph16 = glyph;
168 SkScalar width;
169 SkRect bounds;
170 paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
171
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700172 metrics->x = SkScalarToHBFixed(bounds.fLeft);
173 metrics->y = SkScalarToHBFixed(bounds.fTop);
174 metrics->width = SkScalarToHBFixed(bounds.width());
175 metrics->height = SkScalarToHBFixed(bounds.height());
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800176
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700177 metrics->xOffset = SkScalarToHBFixed(width);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800178 // We can't actually get the |y| correct because Skia doesn't export
179 // the vertical advance. However, nor we do ever render vertical text at
180 // the moment so it's unimportant.
181 metrics->yOffset = 0;
182}
183
184static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
185{
186 FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
187 SkPaint paint;
188 setupPaintWithFontData(&paint, data);
189
190 SkPaint::FontMetrics skiaMetrics;
191 paint.getFontMetrics(&skiaMetrics);
192
193 switch (metric) {
194 case HB_FontAscent:
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700195 return SkScalarToHBFixed(-skiaMetrics.fAscent);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800196 // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
197 default:
198 return 0;
199 }
200 return 0;
201}
202
203const HB_FontClass harfbuzzSkiaClass = {
204 stringToGlyphs,
205 glyphsToAdvances,
206 canRender,
207 getOutlinePoint,
208 getGlyphMetrics,
209 getFontMetric,
210};
211
212HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
213{
Fabrice Di Meglio99cdc6a2011-12-06 14:27:12 -0800214 return HB_Err_Invalid_Argument;
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800215}
216
217} // namespace android