blob: 7e0837950b16c2405425b0145d905e8470779d4f [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
Fabrice Di Meglio208d4592011-11-08 15:49:20 -080027#define LOG_TAG "HarfbuzzSkia"
28
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080029#include "HarfbuzzSkia.h"
30
31#include "SkFontHost.h"
32
33#include "SkPaint.h"
34#include "SkPath.h"
35#include "SkPoint.h"
36#include "SkRect.h"
37#include "SkTypeface.h"
38
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070039#include <utils/Log.h>
40
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080041extern "C" {
42#include "harfbuzz-shaper.h"
43}
44
45// This file implements the callbacks which Harfbuzz requires by using Skia
46// calls. See the Harfbuzz source for references about what these callbacks do.
47
48namespace android {
49
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080050static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length,
51 HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
52{
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -080053 SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
54 paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080055
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070056 uint16_t* skiaGlyphs = reinterpret_cast<uint16_t*>(glyphs);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -080057 int numGlyphs = paint->textToGlyphs(characters, length * sizeof(uint16_t), skiaGlyphs);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080058
59 // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
60 // |glyphs| array needs to be converted.
61 for (int i = numGlyphs - 1; i >= 0; --i) {
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070062 glyphs[i] = skiaGlyphs[i];
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080063 }
64
65 *glyphsSize = numGlyphs;
66 return 1;
67}
68
69static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs,
70 HB_Fixed* advances, int flags)
71{
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -080072 SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
73 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080074
75 uint16_t* glyphs16 = new uint16_t[numGlyphs];
76 if (!glyphs16)
77 return;
78 for (unsigned i = 0; i < numGlyphs; ++i)
79 glyphs16[i] = glyphs[i];
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070080 SkScalar* scalarAdvances = reinterpret_cast<SkScalar*>(advances);
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -080081 paint->getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarAdvances);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080082
83 // The |advances| values which Skia outputs are SkScalars, which are floats
84 // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
85 // These two formats are both 32-bits long.
86 for (unsigned i = 0; i < numGlyphs; ++i) {
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070087 advances[i] = SkScalarToHBFixed(scalarAdvances[i]);
88#if DEBUG_ADVANCES
Steve Block5baa3a62011-12-20 16:23:08 +000089 ALOGD("glyphsToAdvances -- advances[%d]=%d", i, advances[i]);
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -070090#endif
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080091 }
92 delete glyphs16;
93}
94
95static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
96{
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -080097 SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
98 paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -080099
100 uint16_t* glyphs16 = new uint16_t[length];
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800101 int numGlyphs = paint->textToGlyphs(characters, length * sizeof(uint16_t), glyphs16);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800102
103 bool result = true;
104 for (int i = 0; i < numGlyphs; ++i) {
105 if (!glyphs16[i]) {
106 result = false;
107 break;
108 }
109 }
110 delete glyphs16;
111 return result;
112}
113
114static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point,
115 HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
116{
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800117 if (flags & HB_ShaperFlag_UseDesignMetrics)
118 // This is requesting pre-hinted positions. We can't support this.
119 return HB_Err_Invalid_Argument;
120
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800121 SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
122 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
123
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800124 uint16_t glyph16 = glyph;
125 SkPath path;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800126 paint->getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800127 uint32_t numPoints = path.getPoints(0, 0);
128 if (point >= numPoints)
129 return HB_Err_Invalid_SubTable;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800130 SkPoint* points = static_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1)));
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800131 if (!points)
132 return HB_Err_Invalid_SubTable;
133 // Skia does let us get a single point from the path.
134 path.getPoints(points, point + 1);
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700135 *xPos = SkScalarToHBFixed(points[point].fX);
136 *yPos = SkScalarToHBFixed(points[point].fY);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800137 *resultingNumPoints = numPoints;
138 delete points;
139
140 return HB_Err_Ok;
141}
142
143static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
144{
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800145 SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
146 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800147
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800148 uint16_t glyph16 = glyph;
149 SkScalar width;
150 SkRect bounds;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800151 paint->getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800152
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700153 metrics->x = SkScalarToHBFixed(bounds.fLeft);
154 metrics->y = SkScalarToHBFixed(bounds.fTop);
155 metrics->width = SkScalarToHBFixed(bounds.width());
156 metrics->height = SkScalarToHBFixed(bounds.height());
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800157
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700158 metrics->xOffset = SkScalarToHBFixed(width);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800159 // We can't actually get the |y| correct because Skia doesn't export
160 // the vertical advance. However, nor we do ever render vertical text at
161 // the moment so it's unimportant.
162 metrics->yOffset = 0;
163}
164
165static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
166{
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800167 SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800168
169 SkPaint::FontMetrics skiaMetrics;
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800170 paint->getFontMetrics(&skiaMetrics);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800171
172 switch (metric) {
173 case HB_FontAscent:
Fabrice Di Meglioeee49c62011-03-24 17:21:23 -0700174 return SkScalarToHBFixed(-skiaMetrics.fAscent);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800175 // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
176 default:
177 return 0;
178 }
179 return 0;
180}
181
182const HB_FontClass harfbuzzSkiaClass = {
183 stringToGlyphs,
184 glyphsToAdvances,
185 canRender,
186 getOutlinePoint,
187 getGlyphMetrics,
188 getFontMetric,
189};
190
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800191HB_Error harfbuzzSkiaGetTable(void* font, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800192{
Fabrice Di Meglio0af10b52011-11-18 17:36:41 -0800193 SkTypeface* typeface = static_cast<SkTypeface*>(font);
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800194
Fabrice Di Meglio208d4592011-11-08 15:49:20 -0800195 if (!typeface) {
Steve Block5baa3a62011-12-20 16:23:08 +0000196 ALOGD("Typeface cannot be null");
Fabrice Di Meglio208d4592011-11-08 15:49:20 -0800197 return HB_Err_Invalid_Argument;
198 }
Fabrice Di Meglio9f82b582011-03-08 12:02:59 -0800199 const size_t tableSize = SkFontHost::GetTableSize(typeface->uniqueID(), tag);
200 if (!tableSize)
201 return HB_Err_Invalid_Argument;
202 // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
203 if (!buffer) {
204 *len = tableSize;
205 return HB_Err_Ok;
206 }
207
208 if (*len < tableSize)
209 return HB_Err_Invalid_Argument;
210 SkFontHost::GetTableData(typeface->uniqueID(), tag, 0, tableSize, buffer);
211 return HB_Err_Ok;
212}
213
214} // namespace android