• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 
33 #include "FontPlatformData.h"
34 #include "wtf/OwnArrayPtr.h"
35 
36 #include "SkFontHost.h"
37 #include "SkPaint.h"
38 #include "SkPath.h"
39 #include "SkPoint.h"
40 #include "SkRect.h"
41 
42 extern "C" {
43 #include "harfbuzz-shaper.h"
44 }
45 
46 // This file implements the callbacks which Harfbuzz requires by using Skia
47 // calls. See the Harfbuzz source for references about what these callbacks do.
48 
49 namespace WebCore {
50 
SkiaScalarToHarfbuzzFixed(SkScalar value)51 static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
52 {
53     // HB_Fixed is a 26.6 fixed point format.
54     return value * 64;
55 }
56 
stringToGlyphs(HB_Font hbFont,const HB_UChar16 * characters,hb_uint32 length,HB_Glyph * glyphs,hb_uint32 * glyphsSize,HB_Bool isRTL)57 static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
58 {
59     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
60     SkPaint paint;
61 
62     font->setupPaint(&paint);
63     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
64     int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs));
65 
66     // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
67     // |glyphs| array needs to be converted.
68     for (int i = numGlyphs - 1; i >= 0; --i) {
69         uint16_t value;
70         // We use a memcpy to avoid breaking strict aliasing rules.
71         memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t));
72         glyphs[i] = value;
73     }
74 
75     *glyphsSize = numGlyphs;
76     return 1;
77 }
78 
glyphsToAdvances(HB_Font hbFont,const HB_Glyph * glyphs,hb_uint32 numGlyphs,HB_Fixed * advances,int flags)79 static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags)
80 {
81     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
82     SkPaint paint;
83 
84     font->setupPaint(&paint);
85     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
86 
87     OwnArrayPtr<uint16_t> glyphs16(new uint16_t[numGlyphs]);
88     if (!glyphs16.get())
89         return;
90     for (unsigned i = 0; i < numGlyphs; ++i)
91         glyphs16[i] = glyphs[i];
92     paint.getTextWidths(glyphs16.get(), numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
93 
94     // The |advances| values which Skia outputs are SkScalars, which are floats
95     // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
96     // These two formats are both 32-bits long.
97     for (unsigned i = 0; i < numGlyphs; ++i) {
98         float value;
99         // We use a memcpy to avoid breaking strict aliasing rules.
100         memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(float));
101         advances[i] = SkiaScalarToHarfbuzzFixed(value);
102     }
103 }
104 
canRender(HB_Font hbFont,const HB_UChar16 * characters,hb_uint32 length)105 static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
106 {
107     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
108     SkPaint paint;
109 
110     font->setupPaint(&paint);
111     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
112 
113     OwnArrayPtr<uint16_t> glyphs16(new uint16_t[length]);
114     if (!glyphs16.get())
115         return 0;
116     int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16.get());
117 
118     bool canRender = true;
119     for (int i = 0; i < numGlyphs; ++i) {
120         if (!glyphs16[i]) {
121             canRender = false;
122             break;
123         }
124     }
125 
126     return canRender;
127 }
128 
getOutlinePoint(HB_Font hbFont,HB_Glyph glyph,int flags,hb_uint32 point,HB_Fixed * xPos,HB_Fixed * yPos,hb_uint32 * resultingNumPoints)129 static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
130 {
131     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
132     SkPaint paint;
133 
134     if (flags & HB_ShaperFlag_UseDesignMetrics)
135         return HB_Err_Invalid_Argument;  // This is requesting pre-hinted positions. We can't support this.
136 
137     font->setupPaint(&paint);
138     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
139     uint16_t glyph16 = glyph;
140     SkPath path;
141     paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
142     int numPoints = path.getPoints(NULL, 0);
143     if (point >= numPoints)
144         return HB_Err_Invalid_SubTable;
145     SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1)));
146     if (!points)
147         return HB_Err_Invalid_SubTable;
148     // Skia does let us get a single point from the path.
149     path.getPoints(points, point + 1);
150     *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
151     *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
152     *resultingNumPoints = numPoints;
153     fastFree(points);
154 
155     return HB_Err_Ok;
156 }
157 
getGlyphMetrics(HB_Font hbFont,HB_Glyph glyph,HB_GlyphMetrics * metrics)158 static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
159 {
160     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
161     SkPaint paint;
162 
163     font->setupPaint(&paint);
164     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
165     uint16_t glyph16 = glyph;
166     SkScalar width;
167     SkRect bounds;
168     paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
169 
170     metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
171     metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
172     metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
173     metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
174 
175     metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
176     // We can't actually get the |y| correct because Skia doesn't export
177     // the vertical advance. However, nor we do ever render vertical text at
178     // the moment so it's unimportant.
179     metrics->yOffset = 0;
180 }
181 
getFontMetric(HB_Font hbFont,HB_FontMetric metric)182 static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
183 {
184     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
185     SkPaint paint;
186 
187     font->setupPaint(&paint);
188     SkPaint::FontMetrics skiaMetrics;
189     paint.getFontMetrics(&skiaMetrics);
190 
191     switch (metric) {
192     case HB_FontAscent:
193         return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
194     // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
195     default:
196         return 0;
197     }
198 }
199 
200 HB_FontClass harfbuzzSkiaClass = {
201     stringToGlyphs,
202     glyphsToAdvances,
203     canRender,
204     getOutlinePoint,
205     getGlyphMetrics,
206     getFontMetric,
207 };
208 
harfbuzzSkiaGetTable(void * voidface,const HB_Tag tag,HB_Byte * buffer,HB_UInt * len)209 HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
210 {
211     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(voidface);
212 
213     const size_t tableSize = SkFontHost::GetTableSize(font->uniqueID(), tag);
214     if (!tableSize)
215         return HB_Err_Invalid_Argument;
216     // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
217     if (!buffer) {
218         *len = tableSize;
219         return HB_Err_Ok;
220     }
221 
222     if (*len < tableSize)
223         return HB_Err_Invalid_Argument;
224     SkFontHost::GetTableData(font->uniqueID(), tag, 0, tableSize, buffer);
225     return HB_Err_Ok;
226 }
227 
228 }  // namespace WebCore
229