OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2007 Apple Computer, Inc. | 2 * Copyright (C) 2006, 2007 Apple Computer, Inc. |
3 * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. | 3 * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "config.h" | 32 #include "config.h" |
33 #include "Font.h" | 33 #include "Font.h" |
34 | 34 |
35 #include "ChromiumBridge.h" | 35 #include "ChromiumBridge.h" |
36 #include "FontFallbackList.h" | 36 #include "FontFallbackList.h" |
37 #include "GlyphBuffer.h" | 37 #include "GlyphBuffer.h" |
38 #include "PlatformContextSkia.h" | 38 #include "PlatformContextSkia.h" |
39 #include "SimpleFontData.h" | 39 #include "SimpleFontData.h" |
40 #include "SkiaFontWin.h" | 40 #include "SkiaFontWin.h" |
41 #include "SkiaUtils.h" | 41 #include "SkiaUtils.h" |
| 42 #include "TransparencyWin.h" |
42 #include "UniscribeHelperTextRun.h" | 43 #include "UniscribeHelperTextRun.h" |
43 | 44 |
44 #include "skia/ext/platform_canvas_win.h" | 45 #include "skia/ext/platform_canvas_win.h" |
45 #include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency. | 46 #include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency. |
46 | 47 |
47 #include <windows.h> | 48 #include <windows.h> |
48 | 49 |
49 namespace WebCore { | 50 namespace WebCore { |
50 | 51 |
| 52 namespace { |
| 53 |
| 54 bool canvasHasMultipleLayers(const SkCanvas* canvas) |
| 55 { |
| 56 SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false); |
| 57 iter.next(); // There is always at least one layer. |
| 58 return !iter.done(); // There is > 1 layer if the the iterator can stil adv
ance. |
| 59 } |
| 60 |
| 61 // Estimates the bounding box of the given text. This is copied from |
| 62 // FontCGWin.cpp, it is possible, but a lot more work, to get the precide |
| 63 // bounds. |
| 64 IntRect estimateTextBounds(const SimpleFontData* font, |
| 65 const GlyphBuffer& glyphBuffer, |
| 66 int from, int numGlyphs, |
| 67 const FloatPoint& point) |
| 68 { |
| 69 int totalWidth = 0; |
| 70 for (int i = 0; i < numGlyphs; i++) |
| 71 totalWidth += lroundf(glyphBuffer.advanceAt(from + i)); |
| 72 |
| 73 return IntRect(point.x() - (font->ascent() + font->descent()) / 2, |
| 74 point.y() - font->ascent() - font->lineGap(), |
| 75 totalWidth + font->ascent() + font->descent(), |
| 76 font->lineSpacing()); |
| 77 } |
| 78 |
| 79 class TransparencyAwareFontPainter { |
| 80 public: |
| 81 TransparencyAwareFontPainter(GraphicsContext* context, |
| 82 const SimpleFontData* font, |
| 83 const GlyphBuffer& glyphBuffer, |
| 84 int from, int numGlyphs, |
| 85 const FloatPoint& point); |
| 86 TransparencyAwareFontPainter(GraphicsContext* context, |
| 87 const SimpleFontData* font); |
| 88 ~TransparencyAwareFontPainter(); |
| 89 |
| 90 // Draws the partial string of glyphs, starting at |startAdvance| to the |
| 91 // left of m_point. We express it this way so that if we're using the Skia |
| 92 // drawing path we can use floating-point positioning, even though we have |
| 93 // to use integer positioning in the GDI path. |
| 94 bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, |
| 95 int startAdvance) const; |
| 96 |
| 97 private: |
| 98 // Use the context from the transparency helper when drawing with GDI. It |
| 99 // may point to a temporary one. |
| 100 GraphicsContext* m_graphicsContext; |
| 101 PlatformGraphicsContext* m_platformContext; |
| 102 |
| 103 const SimpleFontData* m_font; |
| 104 FloatPoint m_point; |
| 105 |
| 106 // Set when Windows can handle the type of drawing we're doing. |
| 107 bool m_useGDI; |
| 108 |
| 109 // These members are valid only when m_useGDI is set. |
| 110 HDC m_hdc; |
| 111 HGDIOBJ m_oldFont; // For restoring the DC to its original state. |
| 112 TransparencyWin m_transparency; |
| 113 bool m_createdLayer; // We created a layer to give the font some alpha. |
| 114 }; |
| 115 |
| 116 TransparencyAwareFontPainter::TransparencyAwareFontPainter( |
| 117 GraphicsContext* context, |
| 118 const SimpleFontData* font, |
| 119 const GlyphBuffer& glyphBuffer, |
| 120 int from, int numGlyphs, |
| 121 const FloatPoint& point) |
| 122 : m_graphicsContext(context) |
| 123 , m_platformContext(context->platformContext()) |
| 124 , m_font(font) |
| 125 , m_point(point) |
| 126 , m_useGDI(windowsCanHandleTextDrawing(context)) |
| 127 , m_hdc(0) |
| 128 , m_oldFont(0) |
| 129 , m_createdLayer(false) |
| 130 { |
| 131 if (!m_useGDI) |
| 132 return; // Nothing to do. |
| 133 |
| 134 SkColor color = m_platformContext->effectiveFillColor(); |
| 135 if (SkColorGetA(color) != 0xFF) { |
| 136 // When the font has some transparency, apply it by creating a new |
| 137 // transparency layer with that opacity applied. |
| 138 m_createdLayer = true; |
| 139 m_graphicsContext->beginTransparencyLayer(SkColorGetA(color) / 255.0f); |
| 140 // The color should be opaque now. |
| 141 color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGet
B(color)); |
| 142 } |
| 143 |
| 144 TransparencyWin::LayerMode layerMode; |
| 145 IntRect layerRect; |
| 146 if (m_platformContext->isDrawingToImageBuffer()) { |
| 147 // Assume if we're drawing to an image buffer that the background |
| 148 // is not opaque and we have to undo ClearType. We may want to |
| 149 // enhance this to actually check, since it will often be opaque |
| 150 // and we could do ClearType in that case. |
| 151 layerMode = TransparencyWin::TextComposite; |
| 152 layerRect = estimateTextBounds(m_font, glyphBuffer, from, numGlyphs, poi
nt); |
| 153 |
| 154 // The transparency helper requires that we draw text in black in |
| 155 // this mode and it will apply the color. |
| 156 m_transparency.setTextCompositeColor(color); |
| 157 color = SkColorSetRGB(0, 0, 0); |
| 158 } else if (canvasHasMultipleLayers(m_platformContext->canvas())) { |
| 159 // When we're drawing a web page, we know the background is opaque, |
| 160 // but if we're drawing to a layer, we still need extra work. |
| 161 layerMode = TransparencyWin::OpaqueCompositeLayer; |
| 162 layerRect = estimateTextBounds(m_font, glyphBuffer, from, numGlyphs, poi
nt); |
| 163 } else { |
| 164 // Common case of drawing onto the bottom layer of a web page: we |
| 165 // know everything is opaque so don't need to do anything special. |
| 166 layerMode = TransparencyWin::NoLayer; |
| 167 } |
| 168 m_transparency.init(m_graphicsContext, layerMode, TransparencyWin::KeepTrans
form, layerRect); |
| 169 |
| 170 // Set up the DC, using the one from the transparency helper. |
| 171 m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint(); |
| 172 m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont()); |
| 173 SetTextColor(m_hdc, skia::SkColorToCOLORREF(color)); |
| 174 SetBkMode(m_hdc, TRANSPARENT); |
| 175 } |
| 176 |
| 177 TransparencyAwareFontPainter::~TransparencyAwareFontPainter() |
| 178 { |
| 179 if (!m_useGDI) |
| 180 return; // Nothing to do. |
| 181 if (m_createdLayer) |
| 182 m_graphicsContext->endTransparencyLayer(); |
| 183 |
| 184 ::SelectObject(m_hdc, m_oldFont); |
| 185 m_platformContext->canvas()->endPlatformPaint(); |
| 186 } |
| 187 |
| 188 bool TransparencyAwareFontPainter::drawGlyphs(int numGlyphs, |
| 189 const WORD* glyphs, |
| 190 const int* advances, |
| 191 int startAdvance) const |
| 192 { |
| 193 if (!m_useGDI) { |
| 194 SkPoint origin = { SkFloatToScalar(m_point.x() + startAdvance), |
| 195 SkFloatToScalar(m_point.y()) }; |
| 196 return paintSkiaText(m_platformContext, m_font->platformData().hfont(), |
| 197 numGlyphs, glyphs, advances, 0, &origin); |
| 198 } |
| 199 |
| 200 // Windows' origin is the top-left of the bounding box, so we have |
| 201 // to subtract off the font ascent to get it. |
| 202 int x = lroundf(m_point.x() + startAdvance); |
| 203 int y = lroundf(m_point.y() - m_font->ascent()); |
| 204 return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const
wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]); |
| 205 } |
| 206 |
| 207 } // namespace |
| 208 |
51 void Font::drawGlyphs(GraphicsContext* graphicsContext, | 209 void Font::drawGlyphs(GraphicsContext* graphicsContext, |
52 const SimpleFontData* font, | 210 const SimpleFontData* font, |
53 const GlyphBuffer& glyphBuffer, | 211 const GlyphBuffer& glyphBuffer, |
54 int from, | 212 int from, |
55 int numGlyphs, | 213 int numGlyphs, |
56 const FloatPoint& point) const | 214 const FloatPoint& point) const |
57 { | 215 { |
58 PlatformGraphicsContext* context = graphicsContext->platformContext(); | 216 SkColor color = graphicsContext->platformContext()->effectiveFillColor(); |
59 | |
60 bool canUseGDI = windowsCanHandleTextDrawing(graphicsContext); | |
61 bool createdLayer = false; | |
62 | |
63 if (canUseGDI && context->isDrawingToImageBuffer()) { | |
64 // We're drawing to an image buffer and about to render text with GDI. | |
65 // We need to start a layer here, otherwise the alpha values rendered | |
66 // by GDI are never correctly updated. | |
67 // NOTE: this doesn't handle clear type well and should be removed when | |
68 // we have better text handling code. | |
69 graphicsContext->beginTransparencyLayer(1.0); | |
70 createdLayer = true; | |
71 } | |
72 | |
73 // Max buffer length passed to the underlying windows API. | |
74 const int kMaxBufferLength = 1024; | |
75 // Default size for the buffer. It should be enough for most of cases. | |
76 const int kDefaultBufferLength = 256; | |
77 | |
78 SkColor color = context->effectiveFillColor(); | |
79 unsigned char alpha = SkColorGetA(color); | 217 unsigned char alpha = SkColorGetA(color); |
80 // Skip 100% transparent text; no need to draw anything. | 218 // Skip 100% transparent text; no need to draw anything. |
81 if (!alpha && context->getStrokeStyle() == NoStroke) | 219 if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStro
ke) |
82 return; | 220 return; |
83 | 221 |
84 // Set up our graphics context. | 222 TransparencyAwareFontPainter helper(graphicsContext, font, glyphBuffer, from
, numGlyphs, point); |
85 HDC hdc = context->canvas()->beginPlatformPaint(); | |
86 HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont()); | |
87 | |
88 // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency. | |
89 // Enforce non-transparent color. | |
90 color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(co
lor)); | |
91 SetTextColor(hdc, skia::SkColorToCOLORREF(color)); | |
92 SetBkMode(hdc, TRANSPARENT); | |
93 | |
94 // Windows needs the characters and the advances in nice contiguous | |
95 // buffers, which we build here. | |
96 Vector<WORD, kDefaultBufferLength> glyphs; | |
97 Vector<int, kDefaultBufferLength> advances; | |
98 | |
99 // Compute the coordinate. The 'origin' represents the baseline, so we need | |
100 // to move it up to the top of the bounding square. | |
101 int x = static_cast<int>(point.x()); | |
102 int lineTop = static_cast<int>(point.y()) - font->ascent(); | |
103 | 223 |
104 // We draw the glyphs in chunks to avoid having to do a heap allocation for | 224 // We draw the glyphs in chunks to avoid having to do a heap allocation for |
105 // the arrays of characters and advances. Since ExtTextOut is the | 225 // the arrays of characters and advances. Since ExtTextOut is the |
106 // lowest-level text output function on Windows, there should be little | 226 // lowest-level text output function on Windows, there should be little |
107 // penalty for splitting up the text. On the other hand, the buffer cannot | 227 // penalty for splitting up the text. On the other hand, the buffer cannot |
108 // be bigger than 4094 or the function will fail. | 228 // be bigger than 4094 or the function will fail. |
109 int glyphIndex = 0; | 229 const int kMaxBufferLength = 256; |
| 230 Vector<WORD, kMaxBufferLength> glyphs; |
| 231 Vector<int, kMaxBufferLength> advances; |
| 232 int glyphIndex = 0; // The starting glyph of the current chunk. |
| 233 int curAdvance = 0; // How far from the left the current chunk is. |
110 while (glyphIndex < numGlyphs) { | 234 while (glyphIndex < numGlyphs) { |
111 // how many chars will be in this chunk? | 235 // How many chars will be in this chunk? |
112 int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); | 236 int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); |
113 | |
114 glyphs.resize(curLen); | 237 glyphs.resize(curLen); |
115 advances.resize(curLen); | 238 advances.resize(curLen); |
116 | 239 |
117 int curWidth = 0; | 240 int curWidth = 0; |
118 for (int i = 0; i < curLen; ++i, ++glyphIndex) { | 241 for (int i = 0; i < curLen; ++i, ++glyphIndex) { |
119 glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); | 242 glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); |
120 advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphInd
ex)); | 243 advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphInd
ex)); |
121 curWidth += advances[i]; | 244 curWidth += advances[i]; |
122 } | 245 } |
123 | 246 |
| 247 // Actually draw the glyphs (with retry on failure). |
124 bool success = false; | 248 bool success = false; |
125 for (int executions = 0; executions < 2; ++executions) { | 249 for (int executions = 0; executions < 2; ++executions) { |
126 if (canUseGDI) | 250 success = helper.drawGlyphs(curLen, &glyphs[0], &advances[0], curAdv
ance); |
127 success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, 0, | |
128 reinterpret_cast<const wchar_t*>(&glyphs[0]), | |
129 curLen, &advances[0]); | |
130 else { | |
131 // Skia's text drawing origin is the baseline, like WebKit, not | |
132 // the top, like Windows. | |
133 SkPoint origin = { x, point.y() }; | |
134 success = paintSkiaText(context, font->platformData().hfont(), | |
135 numGlyphs, reinterpret_cast<const WORD*>(&glyphs[0]), | |
136 &advances[0], 0, &origin); | |
137 } | |
138 | |
139 if (!success && executions == 0) { | 251 if (!success && executions == 0) { |
140 // Ask the browser to load the font for us and retry. | 252 // Ask the browser to load the font for us and retry. |
141 ChromiumBridge::ensureFontLoaded(font->platformData().hfont()); | 253 ChromiumBridge::ensureFontLoaded(font->platformData().hfont()); |
142 continue; | 254 continue; |
143 } | 255 } |
144 break; | 256 break; |
145 } | 257 } |
146 | 258 |
147 ASSERT(success); | 259 ASSERT(success); |
148 | 260 curAdvance += curWidth; |
149 x += curWidth; | |
150 } | 261 } |
151 | |
152 SelectObject(hdc, oldFont); | |
153 if (createdLayer) | |
154 graphicsContext->endTransparencyLayer(); | |
155 context->canvas()->endPlatformPaint(); | |
156 } | 262 } |
157 | 263 |
158 FloatRect Font::selectionRectForComplexText(const TextRun& run, | 264 FloatRect Font::selectionRectForComplexText(const TextRun& run, |
159 const IntPoint& point, | 265 const IntPoint& point, |
160 int h, | 266 int h, |
161 int from, | 267 int from, |
162 int to) const | 268 int to) const |
163 { | 269 { |
164 UniscribeHelperTextRun state(run, *this); | 270 UniscribeHelperTextRun state(run, *this); |
165 float left = static_cast<float>(point.x() + state.characterToX(from)); | 271 float left = static_cast<float>(point.x() + state.characterToX(from)); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 int charIndex = state.xToCharacter(x); | 326 int charIndex = state.xToCharacter(x); |
221 | 327 |
222 // XToCharacter will return -1 if the position is before the first | 328 // XToCharacter will return -1 if the position is before the first |
223 // character (we get called like this sometimes). | 329 // character (we get called like this sometimes). |
224 if (charIndex < 0) | 330 if (charIndex < 0) |
225 charIndex = 0; | 331 charIndex = 0; |
226 return charIndex; | 332 return charIndex; |
227 } | 333 } |
228 | 334 |
229 } // namespace WebCore | 335 } // namespace WebCore |
OLD | NEW |