Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(288)

Side by Side Diff: webkit/port/platform/graphics/skia/SkiaFontWin.cpp

Issue 8615: Add support for transformed, stoked, shadowed, filled text. We do this by... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:mergeinfo
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <windows.h>
6
7 #include "base/basictypes.h"
8
9 #include "WTF/ListHashSet.h"
10 #include "WTF/Vector.h"
11
12 #include "SkiaFontWin.h"
13
14 #include "SkCanvas.h"
15 #include "SkPaint.h"
16
17 namespace WebCore {
18
19 namespace {
20
21 struct CachedOutlineKey {
22 CachedOutlineKey() : font(NULL), glyph(0), path(NULL) {}
23 CachedOutlineKey(HFONT f, WORD g) : font(f), glyph(g), path(NULL) {}
24
25 HFONT font;
26 WORD glyph;
27
28 // The lifetime of this pointer is managed externally to this class. Be sure
29 // to call DeleteOutline to remove items.
30 SkPath* path;
31 };
32
33 const bool operator==(const CachedOutlineKey& a, const CachedOutlineKey& b)
34 {
35 return a.font == b.font && a.glyph == b.glyph;
36 }
37
38 struct CachedOutlineKeyHash {
39 static unsigned hash(const CachedOutlineKey& key)
40 {
41 return bit_cast<unsigned>(key.font) + key.glyph;
42 }
43
44 static unsigned equal(const CachedOutlineKey& a,
45 const CachedOutlineKey& b)
46 {
47 return a.font == b.font && a.glyph == b.glyph;
48 }
49
50 static const bool safeToCompareToEmptyOrDeleted = true;
51 };
52
53 typedef ListHashSet<CachedOutlineKey, CachedOutlineKeyHash> OutlineCache;
54 OutlineCache outlineCache;
55
56 // The global number of glyph outlines we'll cache.
57 const int outlineCacheSize = 256;
58
59 inline FIXED SkScalarToFIXED(SkScalar x)
60 {
61 return bit_cast<FIXED>(SkScalarToFixed(x));
62 }
63
64 inline SkScalar FIXEDToSkScalar(FIXED fixed)
65 {
66 return SkFixedToScalar(bit_cast<SkFixed>(fixed));
67 }
68
69 // Removes the given key from the cached outlines, also deleting the path.
70 void DeleteOutline(OutlineCache::iterator deleteMe)
71 {
72 delete deleteMe->path;
73 outlineCache.remove(deleteMe);
74 }
75
76 void AddPolyCurveToPath(const TTPOLYCURVE* polyCurve, SkPath* path)
77 {
78 switch (polyCurve->wType) {
79 case TT_PRIM_LINE:
80 for (WORD i = 0; i < polyCurve->cpfx; i++) {
81 path->lineTo(FIXEDToSkScalar(polyCurve->apfx[i].x),
82 -FIXEDToSkScalar(polyCurve->apfx[i].y));
83 }
84 break;
85
86 case TT_PRIM_QSPLINE:
87 // FIXME(brettw) doesn't this duplicate points if we do the loop > once?
88 for (WORD i = 0; i < polyCurve->cpfx - 1; i++) {
89 SkScalar bx = FIXEDToSkScalar(polyCurve->apfx[i].x);
90 SkScalar by = FIXEDToSkScalar(polyCurve->apfx[i].y);
91
92 SkScalar cx = FIXEDToSkScalar(polyCurve->apfx[i + 1].x);
93 SkScalar cy = FIXEDToSkScalar(polyCurve->apfx[i + 1].y);
94 if (i < polyCurve->cpfx - 2) {
95 // We're not the last point, compute C.
96 cx = SkScalarAve(bx, cx);
97 cy = SkScalarAve(by, cy);
98 }
99
100 // Need to flip the y coordinates since the font's coordinate system is
M-A Ruel 2008/12/15 19:54:51 80 cols, if you care.
101 // flipped from ours vertically.
102 path->quadTo(bx, -by, cx, -cy);
103 }
104 break;
105
106 case TT_PRIM_CSPLINE:
107 // FIXME
108 break;
109 }
110 }
111
112 // Fills the given SkPath with the outline for the given glyph index. The font
113 // currently selected into the given DC is used. Returns true on success.
114 bool GetPathForGlyph(HDC dc, WORD glyph, SkPath* path)
115 {
116 char buffer[4096];
117 GLYPHMETRICS gm;
118 MAT2 mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; // Each one is (fract,value).
119
120 DWORD totalSize = GetGlyphOutlineW(dc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE,
121 &gm, arraysize(buffer), buffer, &mat);
122 if (totalSize == GDI_ERROR)
123 return false;
124
125 const char* curGlyph = buffer;
126 const char* endGlyph = &buffer[totalSize];
127 while (curGlyph < endGlyph) {
128 const TTPOLYGONHEADER* polyHeader =
129 reinterpret_cast<const TTPOLYGONHEADER*>(curGlyph);
130 path->moveTo(FIXEDToSkScalar(polyHeader->pfxStart.x),
131 -FIXEDToSkScalar(polyHeader->pfxStart.y));
132
133 const char* curPoly = curGlyph + sizeof(TTPOLYGONHEADER);
134 const char* endPoly = curGlyph + polyHeader->cb;
135 while (curPoly < endPoly) {
136 const TTPOLYCURVE* polyCurve =
137 reinterpret_cast<const TTPOLYCURVE*>(curPoly);
138 AddPolyCurveToPath(polyCurve, path);
139 curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx;
140 }
141 curGlyph += polyHeader->cb;
142 }
143
144 path->close();
145 return true;
146 }
147
148 // Returns a SkPath corresponding to the give glyph in the given font. The font
149 // should be selected into the given DC. The returned path is owned by the
150 // hashtable. Returns NULL on error.
151 const SkPath* GetCachedPathForGlyph(HDC hdc, HFONT font, WORD glyph)
152 {
153 CachedOutlineKey key(font, glyph);
154 OutlineCache::iterator found = outlineCache.find(key);
155 if (found != outlineCache.end()) {
156 // Keep in MRU order by removing & reinserting the value.
157 key = *found;
158 outlineCache.remove(found);
159 outlineCache.add(key);
160 return key.path;
161 }
162
163 key.path = new SkPath;
164 if (!GetPathForGlyph(hdc, glyph, key.path))
165 return NULL;
166
167 if (outlineCache.size() > outlineCacheSize) {
168 // The cache is too big, find the oldest value (first in the list).
169 DeleteOutline(outlineCache.begin());
170 }
171
172 outlineCache.add(key);
173 return key.path;
174 }
175
176 } // namespace
177
178 bool SkiaDrawText(HFONT hfont,
179 SkCanvas* canvas,
180 const SkPoint& point,
181 SkPaint* paint,
182 const WORD* glyphs,
183 const int* advances,
184 int num_glyphs)
185 {
186 HDC dc = GetDC(0);
187 HGDIOBJ old_font = SelectObject(dc, hfont);
188
189 canvas->save();
190 canvas->translate(point.fX, point.fY);
191
192 for (int i = 0; i < num_glyphs; i++) {
193 const SkPath* path = GetCachedPathForGlyph(dc, hfont, glyphs[i]);
194 if (!path)
195 return false;
196 canvas->drawPath(*path, *paint);
197 canvas->translate(advances[i], 0);
198 }
199
200 canvas->restore();
201
202 SelectObject(dc, old_font);
203 ReleaseDC(0, dc);
204 return true;
205 }
206
207 /* TODO(brettw) finish this implementation
208 bool SkiaDrawComplexText(HFONT font,
209 SkCanvas* canvas,
210 const SkPoint& point,
211 SkPaint* paint
212 UINT fuOptions,
213 const SCRIPT_ANALYSIS* psa,
214 const WORD* pwGlyphs,
215 int cGlyphs,
216 const int* advances,
217 const int* justifies,
218 const GOFFSET* glyph_offsets)
219 {
220 HDC dc = GetDC(0);
221 HGDIOBJ old_font = SelectObject(dc, hfont);
222
223 canvas->save();
224 canvas->translate(point.fX, point.fY);
225
226 for (int i = 0; i < cGlyphs; i++) {
227 canvas->translate(glyph_offsets[i].du, glyph_offsets[i].dv);
228
229
230
231
232 // Undo the offset for this glyph.
233 canvas->translate(-glyph_offsets[i].du, -glyph_offsets[i].dv);
234
235 // And advance to where we're drawing the next one. We use the justifies
236 // run since that is the justified advances for each character, rather t han
237 // the adnvaces one.
238 canvas->translate(justifies[i], 0);
239 }
240
241 canvas->restore();
242
243 SelectObject(dc, old_font);
244 ReleaseDC(0, dc);
245 }*/
246
247 void RemoveFontFromSkiaFontWinCache(HFONT hfont)
248 {
249 // ListHashSet isn't the greatest structure for deleting stuff out of, but
250 // removing entries will be relatively rare (we don't remove fonts much, nor
251 // do we draw out own glyphs using these routines much either).
252 //
253 // We keep a list of all glyphs we're removing which we do in a separate
254 // pass.
255 Vector<CachedOutlineKey> outlinesToDelete;
M-A Ruel 2008/12/15 19:54:51 I guess Vector<OutlineCache::iterator> would break
256 for (OutlineCache::iterator i = outlineCache.begin();
257 i != outlineCache.end(); ++i)
258 outlinesToDelete.append(*i);
259
260 for (Vector<CachedOutlineKey>::iterator i = outlinesToDelete.begin();
261 i != outlinesToDelete.end(); ++i)
262 DeleteOutline(outlineCache.find(*i));
263 }
264
265 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698