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

Side by Side Diff: third_party/WebKit/WebCore/platform/graphics/chromium/FontChromiumWin.cpp

Issue 21201: Transparency (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 10 months 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
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « skia/ext/platform_device_win.h ('k') | third_party/WebKit/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698