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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
===================================================================
--- third_party/WebKit/WebCore/platform/graphics/chromium/FontChromiumWin.cpp (revision 10194)
+++ third_party/WebKit/WebCore/platform/graphics/chromium/FontChromiumWin.cpp (working copy)
@@ -39,6 +39,7 @@
#include "SimpleFontData.h"
#include "SkiaFontWin.h"
#include "SkiaUtils.h"
+#include "TransparencyWin.h"
#include "UniscribeHelperTextRun.h"
#include "skia/ext/platform_canvas_win.h"
@@ -48,6 +49,163 @@
namespace WebCore {
+namespace {
+
+bool canvasHasMultipleLayers(const SkCanvas* canvas)
+{
+ SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
+ iter.next(); // There is always at least one layer.
+ return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
+}
+
+// Estimates the bounding box of the given text. This is copied from
+// FontCGWin.cpp, it is possible, but a lot more work, to get the precide
+// bounds.
+IntRect estimateTextBounds(const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs,
+ const FloatPoint& point)
+{
+ int totalWidth = 0;
+ for (int i = 0; i < numGlyphs; i++)
+ totalWidth += lroundf(glyphBuffer.advanceAt(from + i));
+
+ return IntRect(point.x() - (font->ascent() + font->descent()) / 2,
+ point.y() - font->ascent() - font->lineGap(),
+ totalWidth + font->ascent() + font->descent(),
+ font->lineSpacing());
+}
+
+class TransparencyAwareFontPainter {
+public:
+ TransparencyAwareFontPainter(GraphicsContext* context,
+ const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs,
+ const FloatPoint& point);
+ TransparencyAwareFontPainter(GraphicsContext* context,
+ const SimpleFontData* font);
+ ~TransparencyAwareFontPainter();
+
+ // Draws the partial string of glyphs, starting at |startAdvance| to the
+ // left of m_point. We express it this way so that if we're using the Skia
+ // drawing path we can use floating-point positioning, even though we have
+ // to use integer positioning in the GDI path.
+ bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances,
+ int startAdvance) const;
+
+private:
+ // Use the context from the transparency helper when drawing with GDI. It
+ // may point to a temporary one.
+ GraphicsContext* m_graphicsContext;
+ PlatformGraphicsContext* m_platformContext;
+
+ const SimpleFontData* m_font;
+ FloatPoint m_point;
+
+ // Set when Windows can handle the type of drawing we're doing.
+ bool m_useGDI;
+
+ // These members are valid only when m_useGDI is set.
+ HDC m_hdc;
+ HGDIOBJ m_oldFont; // For restoring the DC to its original state.
+ TransparencyWin m_transparency;
+ bool m_createdLayer; // We created a layer to give the font some alpha.
+};
+
+TransparencyAwareFontPainter::TransparencyAwareFontPainter(
+ GraphicsContext* context,
+ const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs,
+ const FloatPoint& point)
+ : m_graphicsContext(context)
+ , m_platformContext(context->platformContext())
+ , m_font(font)
+ , m_point(point)
+ , m_useGDI(windowsCanHandleTextDrawing(context))
+ , m_hdc(0)
+ , m_oldFont(0)
+ , m_createdLayer(false)
+{
+ if (!m_useGDI)
+ return; // Nothing to do.
+
+ SkColor color = m_platformContext->effectiveFillColor();
+ if (SkColorGetA(color) != 0xFF) {
+ // When the font has some transparency, apply it by creating a new
+ // transparency layer with that opacity applied.
+ m_createdLayer = true;
+ m_graphicsContext->beginTransparencyLayer(SkColorGetA(color) / 255.0f);
+ // The color should be opaque now.
+ color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
+ }
+
+ TransparencyWin::LayerMode layerMode;
+ IntRect layerRect;
+ if (m_platformContext->isDrawingToImageBuffer()) {
+ // Assume if we're drawing to an image buffer that the background
+ // is not opaque and we have to undo ClearType. We may want to
+ // enhance this to actually check, since it will often be opaque
+ // and we could do ClearType in that case.
+ layerMode = TransparencyWin::TextComposite;
+ layerRect = estimateTextBounds(m_font, glyphBuffer, from, numGlyphs, point);
+
+ // The transparency helper requires that we draw text in black in
+ // this mode and it will apply the color.
+ m_transparency.setTextCompositeColor(color);
+ color = SkColorSetRGB(0, 0, 0);
+ } else if (canvasHasMultipleLayers(m_platformContext->canvas())) {
+ // When we're drawing a web page, we know the background is opaque,
+ // but if we're drawing to a layer, we still need extra work.
+ layerMode = TransparencyWin::OpaqueCompositeLayer;
+ layerRect = estimateTextBounds(m_font, glyphBuffer, from, numGlyphs, point);
+ } else {
+ // Common case of drawing onto the bottom layer of a web page: we
+ // know everything is opaque so don't need to do anything special.
+ layerMode = TransparencyWin::NoLayer;
+ }
+ m_transparency.init(m_graphicsContext, layerMode, TransparencyWin::KeepTransform, layerRect);
+
+ // Set up the DC, using the one from the transparency helper.
+ m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint();
+ m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
+ SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(m_hdc, TRANSPARENT);
+}
+
+TransparencyAwareFontPainter::~TransparencyAwareFontPainter()
+{
+ if (!m_useGDI)
+ return; // Nothing to do.
+ if (m_createdLayer)
+ m_graphicsContext->endTransparencyLayer();
+
+ ::SelectObject(m_hdc, m_oldFont);
+ m_platformContext->canvas()->endPlatformPaint();
+}
+
+bool TransparencyAwareFontPainter::drawGlyphs(int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ int startAdvance) const
+{
+ if (!m_useGDI) {
+ SkPoint origin = { SkFloatToScalar(m_point.x() + startAdvance),
+ SkFloatToScalar(m_point.y()) };
+ return paintSkiaText(m_platformContext, m_font->platformData().hfont(),
+ numGlyphs, glyphs, advances, 0, &origin);
+ }
+
+ // Windows' origin is the top-left of the bounding box, so we have
+ // to subtract off the font ascent to get it.
+ int x = lroundf(m_point.x() + startAdvance);
+ int y = lroundf(m_point.y() - m_font->ascent());
+ return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
+}
+
+} // namespace
+
void Font::drawGlyphs(GraphicsContext* graphicsContext,
const SimpleFontData* font,
const GlyphBuffer& glyphBuffer,
@@ -55,62 +213,27 @@
int numGlyphs,
const FloatPoint& point) const
{
- PlatformGraphicsContext* context = graphicsContext->platformContext();
-
- bool canUseGDI = windowsCanHandleTextDrawing(graphicsContext);
- bool createdLayer = false;
-
- if (canUseGDI && context->isDrawingToImageBuffer()) {
- // We're drawing to an image buffer and about to render text with GDI.
- // We need to start a layer here, otherwise the alpha values rendered
- // by GDI are never correctly updated.
- // NOTE: this doesn't handle clear type well and should be removed when
- // we have better text handling code.
- graphicsContext->beginTransparencyLayer(1.0);
- createdLayer = true;
- }
-
- // Max buffer length passed to the underlying windows API.
- const int kMaxBufferLength = 1024;
- // Default size for the buffer. It should be enough for most of cases.
- const int kDefaultBufferLength = 256;
-
- SkColor color = context->effectiveFillColor();
+ SkColor color = graphicsContext->platformContext()->effectiveFillColor();
unsigned char alpha = SkColorGetA(color);
// Skip 100% transparent text; no need to draw anything.
- if (!alpha && context->getStrokeStyle() == NoStroke)
+ if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
return;
- // Set up our graphics context.
- HDC hdc = context->canvas()->beginPlatformPaint();
- HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont());
+ TransparencyAwareFontPainter helper(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
- // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
- // Enforce non-transparent color.
- color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
- SetTextColor(hdc, skia::SkColorToCOLORREF(color));
- SetBkMode(hdc, TRANSPARENT);
-
- // Windows needs the characters and the advances in nice contiguous
- // buffers, which we build here.
- Vector<WORD, kDefaultBufferLength> glyphs;
- Vector<int, kDefaultBufferLength> advances;
-
- // Compute the coordinate. The 'origin' represents the baseline, so we need
- // to move it up to the top of the bounding square.
- int x = static_cast<int>(point.x());
- int lineTop = static_cast<int>(point.y()) - font->ascent();
-
// We draw the glyphs in chunks to avoid having to do a heap allocation for
// the arrays of characters and advances. Since ExtTextOut is the
// lowest-level text output function on Windows, there should be little
// penalty for splitting up the text. On the other hand, the buffer cannot
// be bigger than 4094 or the function will fail.
- int glyphIndex = 0;
+ const int kMaxBufferLength = 256;
+ Vector<WORD, kMaxBufferLength> glyphs;
+ Vector<int, kMaxBufferLength> advances;
+ int glyphIndex = 0; // The starting glyph of the current chunk.
+ int curAdvance = 0; // How far from the left the current chunk is.
while (glyphIndex < numGlyphs) {
- // how many chars will be in this chunk?
+ // How many chars will be in this chunk?
int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
-
glyphs.resize(curLen);
advances.resize(curLen);
@@ -121,21 +244,10 @@
curWidth += advances[i];
}
+ // Actually draw the glyphs (with retry on failure).
bool success = false;
for (int executions = 0; executions < 2; ++executions) {
- if (canUseGDI)
- success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, 0,
- reinterpret_cast<const wchar_t*>(&glyphs[0]),
- curLen, &advances[0]);
- else {
- // Skia's text drawing origin is the baseline, like WebKit, not
- // the top, like Windows.
- SkPoint origin = { x, point.y() };
- success = paintSkiaText(context, font->platformData().hfont(),
- numGlyphs, reinterpret_cast<const WORD*>(&glyphs[0]),
- &advances[0], 0, &origin);
- }
-
+ success = helper.drawGlyphs(curLen, &glyphs[0], &advances[0], curAdvance);
if (!success && executions == 0) {
// Ask the browser to load the font for us and retry.
ChromiumBridge::ensureFontLoaded(font->platformData().hfont());
@@ -145,14 +257,8 @@
}
ASSERT(success);
-
- x += curWidth;
+ curAdvance += curWidth;
}
-
- SelectObject(hdc, oldFont);
- if (createdLayer)
- graphicsContext->endTransparencyLayer();
- context->canvas()->endPlatformPaint();
}
FloatRect Font::selectionRectForComplexText(const TextRun& run,
« 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