1a00833feecb2f3a842fb9ce999a6b1f90da00d2
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / FontChromiumWin.cpp
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 "ChromiumBridge.h"
36 #include "FontFallbackList.h"
37 #include "GlyphBuffer.h"
38 #include "NotImplemented.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_win.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
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
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
108 void TransparencyAwareFontPainter::init()
109 {
110     if (m_useGDI)
111         initializeForGDI();
112 }
113
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 = m_transparency.platformContext()->canvas()->beginPlatformPaint();
169         SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
170         SetBkMode(m_hdc, TRANSPARENT);
171     }
172 }
173
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     m_platformContext->canvas()->endPlatformPaint();
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, int 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
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
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.
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     return IntRect(m_point.x() - (m_font->ascent() + m_font->descent()) / 2,
250                    m_point.y() - m_font->ascent() - m_font->lineGap(),
251                    totalWidth + m_font->ascent() + m_font->descent(),
252                    m_font->lineSpacing()); 
253 }
254
255 bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
256                                                const WORD* glyphs,
257                                                const int* advances,
258                                                int startAdvance) const
259 {
260     if (!m_useGDI) {
261         SkPoint origin = m_point;
262         origin.fX += startAdvance;
263         return paintSkiaText(m_graphicsContext, m_font->platformData().hfont(),
264                              numGlyphs, glyphs, advances, 0, &origin);
265     }
266
267     if (!m_graphicsContext || !m_hdc)
268         return true;
269
270     // Windows' origin is the top-left of the bounding box, so we have
271     // to subtract off the font ascent to get it.
272     int x = lroundf(m_point.x() + startAdvance);
273     int y = lroundf(m_point.y() - m_font->ascent());
274
275     // If there is a non-blur shadow and both the fill color and shadow color 
276     // are opaque, handle without skia. 
277     FloatSize shadowOffset;
278     float shadowBlur;
279     Color shadowColor;
280     ColorSpace shadowColorSpace;
281     if (m_graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)) {
282         // If there is a shadow and this code is reached, windowsCanHandleDrawTextShadow()
283         // will have already returned true during the ctor initiatization of m_useGDI
284         ASSERT(shadowColor.alpha() == 255);
285         ASSERT(m_graphicsContext->fillColor().alpha() == 255);
286         ASSERT(shadowBlur == 0);
287         COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue()));
288         COLORREF savedTextColor = GetTextColor(m_hdc);
289         SetTextColor(m_hdc, textColor);
290         ExtTextOut(m_hdc, x + shadowOffset.width(), y + shadowOffset.height(), ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
291         SetTextColor(m_hdc, savedTextColor);
292     }
293     
294     return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
295 }
296
297 class TransparencyAwareUniscribePainter : public TransparencyAwareFontPainter {
298  public:
299     TransparencyAwareUniscribePainter(GraphicsContext*,
300                                       const Font*,
301                                       const TextRun&,
302                                       int from, int to,
303                                       const FloatPoint&);
304     ~TransparencyAwareUniscribePainter();
305
306     // Uniscibe will draw directly into our buffer, so we need to expose our DC.
307     HDC hdc() const { return m_hdc; }
308
309  private:
310     virtual IntRect estimateTextBounds();
311
312     const Font* m_font;
313     const TextRun& m_run;
314     int m_from;
315     int m_to;
316 };
317
318 TransparencyAwareUniscribePainter::TransparencyAwareUniscribePainter(
319     GraphicsContext* context,
320     const Font* font,
321     const TextRun& run,
322     int from, int to,
323     const FloatPoint& point)
324     : TransparencyAwareFontPainter(context, point)
325     , m_font(font)
326     , m_run(run)
327     , m_from(from)
328     , m_to(to)
329 {
330     init();
331 }
332
333 TransparencyAwareUniscribePainter::~TransparencyAwareUniscribePainter()
334 {
335 }
336
337 IntRect TransparencyAwareUniscribePainter::estimateTextBounds()
338 {
339     // This case really really sucks. There is no convenient way to estimate
340     // the bounding box. So we run Uniscribe twice. If we find this happens a
341     // lot, the way to fix it is to make the extra layer after the
342     // UniscribeHelper has measured the text.
343     IntPoint intPoint(lroundf(m_point.x()),
344                       lroundf(m_point.y()));
345
346     UniscribeHelperTextRun state(m_run, *m_font);
347     int left = lroundf(m_point.x()) + state.characterToX(m_from);
348     int right = lroundf(m_point.x()) + state.characterToX(m_to);
349     
350     // Adjust for RTL script since we just want to know the text bounds.
351     if (left > right)
352         std::swap(left, right);
353
354     // This algorithm for estimating how much extra space we need (the text may
355     // go outside the selection rect) is based roughly on
356     // TransparencyAwareGlyphPainter::estimateTextBounds above.
357     return IntRect(left - (m_font->ascent() + m_font->descent()) / 2,
358                    m_point.y() - m_font->ascent() - m_font->lineGap(),
359                    (right - left) + m_font->ascent() + m_font->descent(),
360                    m_font->lineSpacing());
361 }
362
363 }  // namespace
364
365 bool Font::canReturnFallbackFontsForComplexText()
366 {
367     return false;
368 }
369
370 void Font::drawGlyphs(GraphicsContext* graphicsContext,
371                       const SimpleFontData* font,
372                       const GlyphBuffer& glyphBuffer,
373                       int from,
374                       int numGlyphs,
375                       const FloatPoint& point) const
376 {
377     graphicsContext->platformContext()->prepareForSoftwareDraw();
378
379     SkColor color = graphicsContext->platformContext()->effectiveFillColor();
380     unsigned char alpha = SkColorGetA(color);
381     // Skip 100% transparent text; no need to draw anything.
382     if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
383         return;
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     int curAdvance = 0;  // How far from the left the current chunk is.
397     while (glyphIndex < numGlyphs) {
398         // How many chars will be in this chunk?
399         int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
400         glyphs.resize(curLen);
401         advances.resize(curLen);
402
403         int curWidth = 0;
404         for (int i = 0; i < curLen; ++i, ++glyphIndex) {
405             glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
406             advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
407             
408             // Bug 26088 - very large positive or negative runs can fail to
409             // render so we clamp the size here. In the specs, negative
410             // letter-spacing is implementation-defined, so this should be
411             // fine, and it matches Safari's implementation. The call actually
412             // seems to crash if kMaxNegativeRun is set to somewhere around
413             // -32830, so we give ourselves a little breathing room.
414             const int maxNegativeRun = -32768;
415             const int maxPositiveRun =  32768;
416             if ((curWidth + advances[i] < maxNegativeRun) || (curWidth + advances[i] > maxPositiveRun)) 
417                 advances[i] = 0;
418             curWidth += advances[i];
419         }
420
421         // Actually draw the glyphs (with retry on failure).
422         bool success = false;
423         for (int executions = 0; executions < 2; ++executions) {
424             success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], curAdvance);
425             if (!success && executions == 0) {
426                 // Ask the browser to load the font for us and retry.
427                 ChromiumBridge::ensureFontLoaded(font->platformData().hfont());
428                 continue;
429             }
430             break;
431         }
432
433         if (!success)
434             LOG_ERROR("Unable to draw the glyphs after second attempt");
435
436         curAdvance += curWidth;
437     }
438 }
439
440 FloatRect Font::selectionRectForComplexText(const TextRun& run,
441                                             const FloatPoint& point,
442                                             int h,
443                                             int from,
444                                             int to) const
445 {
446     UniscribeHelperTextRun state(run, *this);
447     float left = static_cast<float>(point.x() + state.characterToX(from));
448     float right = static_cast<float>(point.x() + state.characterToX(to));
449
450     // If the text is RTL, left will actually be after right.
451     if (left < right)
452         return FloatRect(left, point.y(),
453                        right - left, static_cast<float>(h));
454
455     return FloatRect(right, point.y(),
456                      left - right, static_cast<float>(h));
457 }
458
459 void Font::drawComplexText(GraphicsContext* graphicsContext,
460                            const TextRun& run,
461                            const FloatPoint& point,
462                            int from,
463                            int to) const
464 {
465     PlatformGraphicsContext* context = graphicsContext->platformContext();
466     UniscribeHelperTextRun state(run, *this);
467
468     SkColor color = graphicsContext->platformContext()->effectiveFillColor();
469     unsigned char alpha = SkColorGetA(color);
470     // Skip 100% transparent text; no need to draw anything.
471     if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
472         return;
473
474     TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point);
475
476     HDC hdc = painter.hdc();
477     if (windowsCanHandleTextDrawing(graphicsContext) && !hdc)
478         return;
479
480     // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
481     // Enforce non-transparent color.
482     color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
483     if (hdc) {
484         SetTextColor(hdc, skia::SkColorToCOLORREF(color));
485         SetBkMode(hdc, TRANSPARENT);
486     }
487
488     // If there is a non-blur shadow and both the fill color and shadow color 
489     // are opaque, handle without skia. 
490     FloatSize shadowOffset;
491     float shadowBlur;
492     Color shadowColor;
493     ColorSpace shadowColorSpace;
494     if (graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace) && windowsCanHandleDrawTextShadow(graphicsContext)) {
495         COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue()));
496         COLORREF savedTextColor = GetTextColor(hdc);
497         SetTextColor(hdc, textColor);
498         state.draw(graphicsContext, hdc, static_cast<int>(point.x()) + shadowOffset.width(),
499                    static_cast<int>(point.y() - ascent()) + shadowOffset.height(), from, to);
500         SetTextColor(hdc, savedTextColor); 
501     }
502
503     // Uniscribe counts the coordinates from the upper left, while WebKit uses
504     // the baseline, so we have to subtract off the ascent.
505     state.draw(graphicsContext, hdc, static_cast<int>(point.x()),
506                static_cast<int>(point.y() - ascent()), from, to);
507
508     context->canvas()->endPlatformPaint();
509 }
510
511 void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
512 {
513     notImplemented();
514 }
515
516 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
517 {
518     UniscribeHelperTextRun state(run, *this);
519     return static_cast<float>(state.width());
520 }
521
522 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
523                                           bool includePartialGlyphs) const
524 {
525     // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
526     // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
527     int x = static_cast<int>(xFloat);
528
529     // Mac code ignores includePartialGlyphs, and they don't know what it's
530     // supposed to do, so we just ignore it as well.
531     UniscribeHelperTextRun state(run, *this);
532     int charIndex = state.xToCharacter(x);
533
534     // XToCharacter will return -1 if the position is before the first
535     // character (we get called like this sometimes).
536     if (charIndex < 0)
537         charIndex = 0;
538     return charIndex;
539 }
540
541 } // namespace WebCore