1 /*
2 * Copyright (C) 2006, 2007 Apple Computer, Inc.
3 * Copyright (c) 2006, 2007, 2008, 2009, 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 are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "config.h"
33 #include "Font.h"
34
35 #include "FontFallbackList.h"
36 #include "GlyphBuffer.h"
37 #include "NotImplemented.h"
38 #include "PlatformBridge.h"
39 #include "PlatformContextSkia.h"
40 #include "SimpleFontData.h"
41 #include "SkiaFontWin.h"
42 #include "SkiaUtils.h"
43 #include "TransparencyWin.h"
44 #include "UniscribeHelperTextRun.h"
45
46 #include "skia/ext/platform_canvas.h"
47 #include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency.
48
49 #include <windows.h>
50
51 namespace WebCore {
52
53 namespace {
54
canvasHasMultipleLayers(const SkCanvas * canvas)55 bool canvasHasMultipleLayers(const SkCanvas* canvas)
56 {
57 SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
58 iter.next(); // There is always at least one layer.
59 return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
60 }
61
62 class TransparencyAwareFontPainter {
63 public:
64 TransparencyAwareFontPainter(GraphicsContext*, const FloatPoint&);
65 ~TransparencyAwareFontPainter();
66
67 protected:
68 // Called by our subclass' constructor to initialize GDI if necessary. This
69 // is a separate function so it can be called after the subclass finishes
70 // construction (it calls virtual functions).
71 void init();
72
73 virtual IntRect estimateTextBounds() = 0;
74
75 // Use the context from the transparency helper when drawing with GDI. It
76 // may point to a temporary one.
77 GraphicsContext* m_graphicsContext;
78 PlatformGraphicsContext* m_platformContext;
79
80 FloatPoint m_point;
81
82 // Set when Windows can handle the type of drawing we're doing.
83 bool m_useGDI;
84
85 // These members are valid only when m_useGDI is set.
86 HDC m_hdc;
87 TransparencyWin m_transparency;
88
89 private:
90 // Call when we're using GDI mode to initialize the TransparencyWin to help
91 // us draw GDI text.
92 void initializeForGDI();
93
94 bool m_createdTransparencyLayer; // We created a layer to give the font some alpha.
95 };
96
TransparencyAwareFontPainter(GraphicsContext * context,const FloatPoint & point)97 TransparencyAwareFontPainter::TransparencyAwareFontPainter(GraphicsContext* context,
98 const FloatPoint& point)
99 : m_graphicsContext(context)
100 , m_platformContext(context->platformContext())
101 , m_point(point)
102 , m_useGDI(windowsCanHandleTextDrawing(context))
103 , m_hdc(0)
104 , m_createdTransparencyLayer(false)
105 {
106 }
107
init()108 void TransparencyAwareFontPainter::init()
109 {
110 if (m_useGDI)
111 initializeForGDI();
112 }
113
initializeForGDI()114 void TransparencyAwareFontPainter::initializeForGDI()
115 {
116 m_graphicsContext->save();
117 SkColor color = m_platformContext->effectiveFillColor();
118 // Used only when m_createdTransparencyLayer is true.
119 float layerAlpha = 0.0f;
120 if (SkColorGetA(color) != 0xFF) {
121 // When the font has some transparency, apply it by creating a new
122 // transparency layer with that opacity applied. We'll actually create
123 // a new transparency layer after we calculate the bounding box.
124 m_createdTransparencyLayer = true;
125 layerAlpha = SkColorGetA(color) / 255.0f;
126 // The color should be opaque now.
127 color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
128 }
129
130 TransparencyWin::LayerMode layerMode;
131 IntRect layerRect;
132 if (m_platformContext->isDrawingToImageBuffer()) {
133 // Assume if we're drawing to an image buffer that the background
134 // is not opaque and we have to undo ClearType. We may want to
135 // enhance this to actually check, since it will often be opaque
136 // and we could do ClearType in that case.
137 layerMode = TransparencyWin::TextComposite;
138 layerRect = estimateTextBounds();
139 m_graphicsContext->clip(layerRect);
140 if (m_createdTransparencyLayer)
141 m_graphicsContext->beginTransparencyLayer(layerAlpha);
142
143 // The transparency helper requires that we draw text in black in
144 // this mode and it will apply the color.
145 m_transparency.setTextCompositeColor(color);
146 color = SkColorSetRGB(0, 0, 0);
147 } else if (m_createdTransparencyLayer || canvasHasMultipleLayers(m_platformContext->canvas())) {
148 // When we're drawing a web page, we know the background is opaque,
149 // but if we're drawing to a layer, we still need extra work.
150 layerMode = TransparencyWin::OpaqueCompositeLayer;
151 layerRect = estimateTextBounds();
152 m_graphicsContext->clip(layerRect);
153 if (m_createdTransparencyLayer)
154 m_graphicsContext->beginTransparencyLayer(layerAlpha);
155 } else {
156 // Common case of drawing onto the bottom layer of a web page: we
157 // know everything is opaque so don't need to do anything special.
158 layerMode = TransparencyWin::NoLayer;
159 }
160
161 // Bug 26088 - init() might fail if layerRect is invalid. Given this, we
162 // need to be careful to check for null pointers everywhere after this call
163 m_transparency.init(m_graphicsContext, layerMode,
164 TransparencyWin::KeepTransform, layerRect);
165
166 // Set up the DC, using the one from the transparency helper.
167 if (m_transparency.platformContext()) {
168 m_hdc = skia::BeginPlatformPaint(m_transparency.platformContext()->canvas());
169 SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
170 SetBkMode(m_hdc, TRANSPARENT);
171 }
172 }
173
~TransparencyAwareFontPainter()174 TransparencyAwareFontPainter::~TransparencyAwareFontPainter()
175 {
176 if (!m_useGDI || !m_graphicsContext || !m_platformContext)
177 return; // Nothing to do.
178 m_transparency.composite();
179 if (m_createdTransparencyLayer)
180 m_graphicsContext->endTransparencyLayer();
181 m_graphicsContext->restore();
182 skia::EndPlatformPaint(m_platformContext->canvas());
183 }
184
185 // Specialization for simple GlyphBuffer painting.
186 class TransparencyAwareGlyphPainter : public TransparencyAwareFontPainter {
187 public:
188 TransparencyAwareGlyphPainter(GraphicsContext*,
189 const SimpleFontData*,
190 const GlyphBuffer&,
191 int from, int numGlyphs,
192 const FloatPoint&);
193 ~TransparencyAwareGlyphPainter();
194
195 // Draws the partial string of glyphs, starting at |startAdvance| to the
196 // left of m_point. We express it this way so that if we're using the Skia
197 // drawing path we can use floating-point positioning, even though we have
198 // to use integer positioning in the GDI path.
199 bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, float startAdvance) const;
200
201 private:
202 virtual IntRect estimateTextBounds();
203
204 const SimpleFontData* m_font;
205 const GlyphBuffer& m_glyphBuffer;
206 int m_from;
207 int m_numGlyphs;
208
209 // When m_useGdi is set, this stores the previous HFONT selected into the
210 // m_hdc so we can restore it.
211 HGDIOBJ m_oldFont; // For restoring the DC to its original state.
212 };
213
TransparencyAwareGlyphPainter(GraphicsContext * context,const SimpleFontData * font,const GlyphBuffer & glyphBuffer,int from,int numGlyphs,const FloatPoint & point)214 TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter(
215 GraphicsContext* context,
216 const SimpleFontData* font,
217 const GlyphBuffer& glyphBuffer,
218 int from, int numGlyphs,
219 const FloatPoint& point)
220 : TransparencyAwareFontPainter(context, point)
221 , m_font(font)
222 , m_glyphBuffer(glyphBuffer)
223 , m_from(from)
224 , m_numGlyphs(numGlyphs)
225 , m_oldFont(0)
226 {
227 init();
228
229 if (m_hdc)
230 m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
231 }
232
~TransparencyAwareGlyphPainter()233 TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter()
234 {
235 if (m_useGDI && m_hdc)
236 ::SelectObject(m_hdc, m_oldFont);
237 }
238
239
240 // Estimates the bounding box of the given text. This is copied from
241 // FontCGWin.cpp, it is possible, but a lot more work, to get the precide
242 // bounds.
estimateTextBounds()243 IntRect TransparencyAwareGlyphPainter::estimateTextBounds()
244 {
245 int totalWidth = 0;
246 for (int i = 0; i < m_numGlyphs; i++)
247 totalWidth += lroundf(m_glyphBuffer.advanceAt(m_from + i));
248
249 const FontMetrics& fontMetrics = m_font->fontMetrics();
250 return IntRect(m_point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2,
251 m_point.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
252 totalWidth + fontMetrics.ascent() + fontMetrics.descent(),
253 fontMetrics.lineSpacing());
254 }
255
drawGlyphs(int numGlyphs,const WORD * glyphs,const int * advances,float startAdvance) const256 bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
257 const WORD* glyphs,
258 const int* advances,
259 float startAdvance) const
260 {
261 if (!m_useGDI) {
262 SkPoint origin = m_point;
263 origin.fX += SkFloatToScalar(startAdvance);
264 return paintSkiaText(m_graphicsContext, m_font->platformData().hfont(),
265 numGlyphs, glyphs, advances, 0, &origin);
266 }
267
268 if (!m_graphicsContext || !m_hdc)
269 return true;
270
271 // Windows' origin is the top-left of the bounding box, so we have
272 // to subtract off the font ascent to get it.
273 int x = lroundf(m_point.x() + startAdvance);
274 int y = lroundf(m_point.y() - m_font->fontMetrics().ascent());
275
276 // If there is a non-blur shadow and both the fill color and shadow color
277 // are opaque, handle without skia.
278 FloatSize shadowOffset;
279 float shadowBlur;
280 Color shadowColor;
281 ColorSpace shadowColorSpace;
282 if (m_graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)) {
283 // If there is a shadow and this code is reached, windowsCanHandleDrawTextShadow()
284 // will have already returned true during the ctor initiatization of m_useGDI
285 ASSERT(shadowColor.alpha() == 255);
286 ASSERT(m_graphicsContext->fillColor().alpha() == 255);
287 ASSERT(shadowBlur == 0);
288 COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue()));
289 COLORREF savedTextColor = GetTextColor(m_hdc);
290 SetTextColor(m_hdc, textColor);
291 ExtTextOut(m_hdc, x + shadowOffset.width(), y + shadowOffset.height(), ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
292 SetTextColor(m_hdc, savedTextColor);
293 }
294
295 return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
296 }
297
298 class TransparencyAwareUniscribePainter : public TransparencyAwareFontPainter {
299 public:
300 TransparencyAwareUniscribePainter(GraphicsContext*,
301 const Font*,
302 const TextRun&,
303 int from, int to,
304 const FloatPoint&);
305 ~TransparencyAwareUniscribePainter();
306
307 // Uniscibe will draw directly into our buffer, so we need to expose our DC.
hdc() const308 HDC hdc() const { return m_hdc; }
309
310 private:
311 virtual IntRect estimateTextBounds();
312
313 const Font* m_font;
314 const TextRun& m_run;
315 int m_from;
316 int m_to;
317 };
318
TransparencyAwareUniscribePainter(GraphicsContext * context,const Font * font,const TextRun & run,int from,int to,const FloatPoint & point)319 TransparencyAwareUniscribePainter::TransparencyAwareUniscribePainter(
320 GraphicsContext* context,
321 const Font* font,
322 const TextRun& run,
323 int from, int to,
324 const FloatPoint& point)
325 : TransparencyAwareFontPainter(context, point)
326 , m_font(font)
327 , m_run(run)
328 , m_from(from)
329 , m_to(to)
330 {
331 init();
332 }
333
~TransparencyAwareUniscribePainter()334 TransparencyAwareUniscribePainter::~TransparencyAwareUniscribePainter()
335 {
336 }
337
estimateTextBounds()338 IntRect TransparencyAwareUniscribePainter::estimateTextBounds()
339 {
340 // This case really really sucks. There is no convenient way to estimate
341 // the bounding box. So we run Uniscribe twice. If we find this happens a
342 // lot, the way to fix it is to make the extra layer after the
343 // UniscribeHelper has measured the text.
344 IntPoint intPoint(lroundf(m_point.x()),
345 lroundf(m_point.y()));
346
347 UniscribeHelperTextRun state(m_run, *m_font);
348 int left = lroundf(m_point.x()) + state.characterToX(m_from);
349 int right = lroundf(m_point.x()) + state.characterToX(m_to);
350
351 // Adjust for RTL script since we just want to know the text bounds.
352 if (left > right)
353 std::swap(left, right);
354
355 // This algorithm for estimating how much extra space we need (the text may
356 // go outside the selection rect) is based roughly on
357 // TransparencyAwareGlyphPainter::estimateTextBounds above.
358 const FontMetrics& fontMetrics = m_font->fontMetrics();
359 return IntRect(left - (fontMetrics.ascent() + fontMetrics.descent()) / 2,
360 m_point.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
361 (right - left) + fontMetrics.ascent() + fontMetrics.descent(),
362 fontMetrics.lineSpacing());
363 }
364
365 } // namespace
366
canReturnFallbackFontsForComplexText()367 bool Font::canReturnFallbackFontsForComplexText()
368 {
369 return false;
370 }
371
canExpandAroundIdeographsInComplexText()372 bool Font::canExpandAroundIdeographsInComplexText()
373 {
374 return false;
375 }
376
drawGlyphsWin(GraphicsContext * graphicsContext,const SimpleFontData * font,const GlyphBuffer & glyphBuffer,int from,int numGlyphs,const FloatPoint & point)377 static void drawGlyphsWin(GraphicsContext* graphicsContext,
378 const SimpleFontData* font,
379 const GlyphBuffer& glyphBuffer,
380 int from,
381 int numGlyphs,
382 const FloatPoint& point) {
383 graphicsContext->platformContext()->prepareForSoftwareDraw();
384
385 TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
386
387 // We draw the glyphs in chunks to avoid having to do a heap allocation for
388 // the arrays of characters and advances. Since ExtTextOut is the
389 // lowest-level text output function on Windows, there should be little
390 // penalty for splitting up the text. On the other hand, the buffer cannot
391 // be bigger than 4094 or the function will fail.
392 const int kMaxBufferLength = 256;
393 Vector<WORD, kMaxBufferLength> glyphs;
394 Vector<int, kMaxBufferLength> advances;
395 int glyphIndex = 0; // The starting glyph of the current chunk.
396
397 // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position
398 // of each glyph in floating point units and rounds to integer advances at the last possible moment.
399
400 float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph.
401 int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered.
402 while (glyphIndex < numGlyphs) {
403 // How many chars will be in this chunk?
404 int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
405 glyphs.resize(curLen);
406 advances.resize(curLen);
407
408 float currentWidth = 0;
409 for (int i = 0; i < curLen; ++i, ++glyphIndex) {
410 glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
411 horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex);
412 advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded;
413 lastHorizontalOffsetRounded += advances[i];
414 currentWidth += glyphBuffer.advanceAt(from + glyphIndex);
415
416 // Bug 26088 - very large positive or negative runs can fail to
417 // render so we clamp the size here. In the specs, negative
418 // letter-spacing is implementation-defined, so this should be
419 // fine, and it matches Safari's implementation. The call actually
420 // seems to crash if kMaxNegativeRun is set to somewhere around
421 // -32830, so we give ourselves a little breathing room.
422 const int maxNegativeRun = -32768;
423 const int maxPositiveRun = 32768;
424 if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun))
425 advances[i] = 0;
426 }
427
428 // Actually draw the glyphs (with retry on failure).
429 bool success = false;
430 for (int executions = 0; executions < 2; ++executions) {
431 success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], horizontalOffset - point.x() - currentWidth);
432 if (!success && executions == 0) {
433 // Ask the browser to load the font for us and retry.
434 PlatformBridge::ensureFontLoaded(font->platformData().hfont());
435 continue;
436 }
437 break;
438 }
439
440 if (!success)
441 LOG_ERROR("Unable to draw the glyphs after second attempt");
442 }
443 }
444
drawGlyphs(GraphicsContext * graphicsContext,const SimpleFontData * font,const GlyphBuffer & glyphBuffer,int from,int numGlyphs,const FloatPoint & point) const445 void Font::drawGlyphs(GraphicsContext* graphicsContext,
446 const SimpleFontData* font,
447 const GlyphBuffer& glyphBuffer,
448 int from,
449 int numGlyphs,
450 const FloatPoint& point) const
451 {
452 SkColor color = graphicsContext->platformContext()->effectiveFillColor();
453 unsigned char alpha = SkColorGetA(color);
454 // Skip 100% transparent text; no need to draw anything.
455 if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke && !graphicsContext->hasShadow())
456 return;
457
458 drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
459 }
460
selectionRectForComplexText(const TextRun & run,const FloatPoint & point,int h,int from,int to) const461 FloatRect Font::selectionRectForComplexText(const TextRun& run,
462 const FloatPoint& point,
463 int h,
464 int from,
465 int to) const
466 {
467 UniscribeHelperTextRun state(run, *this);
468 float left = static_cast<float>(point.x() + state.characterToX(from));
469 float right = static_cast<float>(point.x() + state.characterToX(to));
470
471 // If the text is RTL, left will actually be after right.
472 if (left < right)
473 return FloatRect(left, point.y(),
474 right - left, static_cast<float>(h));
475
476 return FloatRect(right, point.y(),
477 left - right, static_cast<float>(h));
478 }
479
drawComplexText(GraphicsContext * graphicsContext,const TextRun & run,const FloatPoint & point,int from,int to) const480 void Font::drawComplexText(GraphicsContext* graphicsContext,
481 const TextRun& run,
482 const FloatPoint& point,
483 int from,
484 int to) const
485 {
486 PlatformGraphicsContext* context = graphicsContext->platformContext();
487 UniscribeHelperTextRun state(run, *this);
488
489 SkColor color = graphicsContext->platformContext()->effectiveFillColor();
490 unsigned char alpha = SkColorGetA(color);
491 // Skip 100% transparent text; no need to draw anything.
492 if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
493 return;
494
495 TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point);
496
497 HDC hdc = painter.hdc();
498 if (windowsCanHandleTextDrawing(graphicsContext) && !hdc)
499 return;
500
501 // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
502 // Enforce non-transparent color.
503 color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
504 if (hdc) {
505 SetTextColor(hdc, skia::SkColorToCOLORREF(color));
506 SetBkMode(hdc, TRANSPARENT);
507 }
508
509 // If there is a non-blur shadow and both the fill color and shadow color
510 // are opaque, handle without skia.
511 FloatSize shadowOffset;
512 float shadowBlur;
513 Color shadowColor;
514 ColorSpace shadowColorSpace;
515 if (graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace) && windowsCanHandleDrawTextShadow(graphicsContext)) {
516 COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue()));
517 COLORREF savedTextColor = GetTextColor(hdc);
518 SetTextColor(hdc, textColor);
519 state.draw(graphicsContext, hdc, static_cast<int>(point.x()) + shadowOffset.width(),
520 static_cast<int>(point.y() - fontMetrics().ascent()) + shadowOffset.height(), from, to);
521 SetTextColor(hdc, savedTextColor);
522 }
523
524 // Uniscribe counts the coordinates from the upper left, while WebKit uses
525 // the baseline, so we have to subtract off the ascent.
526 state.draw(graphicsContext, hdc, lroundf(point.x()), lroundf(point.y() - fontMetrics().ascent()), from, to);
527
528 skia::EndPlatformPaint(context->canvas());
529 }
530
drawEmphasisMarksForComplexText(GraphicsContext *,const TextRun &,const AtomicString &,const FloatPoint &,int,int) const531 void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
532 {
533 notImplemented();
534 }
535
floatWidthForComplexText(const TextRun & run,HashSet<const SimpleFontData * > *,GlyphOverflow *) const536 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
537 {
538 UniscribeHelperTextRun state(run, *this);
539 return static_cast<float>(state.width());
540 }
541
offsetForPositionForComplexText(const TextRun & run,float xFloat,bool includePartialGlyphs) const542 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
543 bool includePartialGlyphs) const
544 {
545 // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
546 // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
547 int x = static_cast<int>(xFloat);
548
549 // Mac code ignores includePartialGlyphs, and they don't know what it's
550 // supposed to do, so we just ignore it as well.
551 UniscribeHelperTextRun state(run, *this);
552 int charIndex = state.xToCharacter(x);
553
554 // XToCharacter will return -1 if the position is before the first
555 // character (we get called like this sometimes).
556 if (charIndex < 0)
557 charIndex = 0;
558 return charIndex;
559 }
560
561 } // namespace WebCore
562