18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/* 2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without 58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions 68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met: 78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright 88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * notice, this list of conditions and the following disclaimer. 98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright 108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * notice, this list of conditions and the following disclaimer in the 118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * documentation and/or other materials provided with the distribution. 128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */ 258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h" 278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Font.h" 288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 298a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#include "AffineTransform.h" 308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FloatConversion.h" 318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GlyphBuffer.h" 328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContext.h" 338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "IntRect.h" 348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SimpleFontData.h" 358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "UniscribeController.h" 368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebCoreTextRenderer.h" 378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <ApplicationServices/ApplicationServices.h> 388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <WebKitSystemInterface/WebKitSystemInterface.h> 398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/MathExtras.h> 408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore { 428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst int syntheticObliqueAngle = 14; 448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline CGFloat toCGFloat(FIXED f) 468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return f.value + f.fract / CGFloat(65536.0); 488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic CGPathRef createPathForGlyph(HDC hdc, Glyph glyph) 518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGMutablePathRef path = CGPathCreateMutable(); 538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; 558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project GLYPHMETRICS glyphMetrics; 568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // GGO_NATIVE matches the outline perfectly when Windows font smoothing is off. 578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // GGO_NATIVE | GGO_UNHINTED does not match perfectly either when Windows font smoothing is on or off. 588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project DWORD outlineLength = GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, 0, 0, &identity); 598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ASSERT(outlineLength >= 0); 608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (outlineLength < 0) 618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return path; 628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Vector<UInt8> outline(outlineLength); 648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, outlineLength, outline.data(), &identity); 658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project unsigned offset = 0; 678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (offset < outlineLength) { 688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project LPTTPOLYGONHEADER subpath = reinterpret_cast<LPTTPOLYGONHEADER>(outline.data() + offset); 698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ASSERT(subpath->dwType == TT_POLYGON_TYPE); 708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (subpath->dwType != TT_POLYGON_TYPE) 718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return path; 728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGPathMoveToPoint(path, 0, toCGFloat(subpath->pfxStart.x), toCGFloat(subpath->pfxStart.y)); 748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project unsigned subpathOffset = sizeof(*subpath); 768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (subpathOffset < subpath->cb) { 778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project LPTTPOLYCURVE segment = reinterpret_cast<LPTTPOLYCURVE>(reinterpret_cast<UInt8*>(subpath) + subpathOffset); 788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project switch (segment->wType) { 798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project case TT_PRIM_LINE: 808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (unsigned i = 0; i < segment->cpfx; i++) 818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGPathAddLineToPoint(path, 0, toCGFloat(segment->apfx[i].x), toCGFloat(segment->apfx[i].y)); 828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project case TT_PRIM_QSPLINE: 858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (unsigned i = 0; i < segment->cpfx; i++) { 868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat x = toCGFloat(segment->apfx[i].x); 878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat y = toCGFloat(segment->apfx[i].y); 888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat cpx; 898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat cpy; 908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (i == segment->cpfx - 2) { 928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project cpx = toCGFloat(segment->apfx[i + 1].x); 938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project cpy = toCGFloat(segment->apfx[i + 1].y); 948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project i++; 958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else { 968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project cpx = (toCGFloat(segment->apfx[i].x) + toCGFloat(segment->apfx[i + 1].x)) / 2; 978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project cpy = (toCGFloat(segment->apfx[i].y) + toCGFloat(segment->apfx[i + 1].y)) / 2; 988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGPathAddQuadCurveToPoint(path, 0, x, y, cpx, cpy); 1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project case TT_PRIM_CSPLINE: 1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (unsigned i = 0; i < segment->cpfx; i += 3) { 1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat cp1x = toCGFloat(segment->apfx[i].x); 1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat cp1y = toCGFloat(segment->apfx[i].y); 1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat cp2x = toCGFloat(segment->apfx[i + 1].x); 1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat cp2y = toCGFloat(segment->apfx[i + 1].y); 1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat x = toCGFloat(segment->apfx[i + 2].x); 1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGFloat y = toCGFloat(segment->apfx[i + 2].y); 1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGPathAddCurveToPoint(path, 0, cp1x, cp1y, cp2x, cp2y, x, y); 1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project default: 1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ASSERT_NOT_REACHED(); 1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return path; 1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project subpathOffset += sizeof(*segment) + (segment->cpfx - 1) * sizeof(segment->apfx[0]); 1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGPathCloseSubpath(path); 1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project offset += subpath->cb; 1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return path; 1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, 1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int from, int numGlyphs, const FloatPoint& point) 1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Color fillColor = graphicsContext->fillColor(); 1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project bool drawIntoBitmap = false; 136f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch TextDrawingModeFlags drawingMode = graphicsContext->textDrawingMode(); 137f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (drawingMode == TextModeFill) { 1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!fillColor.alpha()) 1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return; 1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer(); 1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!drawIntoBitmap) { 1435ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen FloatSize offset; 144545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch float blur; 1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Color color; 146f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch ColorSpace shadowColorSpace; 147f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 148f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch graphicsContext->getShadow(offset, blur, color, shadowColorSpace); 1495ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen drawIntoBitmap = offset.width() || offset.height() || blur; 1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances. 1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Vector<int, 2048> gdiAdvances; 1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int totalWidth = 0; 1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (int i = 0; i < numGlyphs; i++) { 1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i))); 1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project totalWidth += gdiAdvances[i]; 1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project HDC hdc = 0; 1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project OwnPtr<GraphicsContext::WindowsBitmap> bitmap; 1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project IntRect textRect; 1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!drawIntoBitmap) 1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project hdc = graphicsContext->getWindowsContext(textRect, true, false); 1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!hdc) { 1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project drawIntoBitmap = true; 1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. 1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: Can get glyphs' optical bounds (even from CG) to get this right. 1702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block const FontMetrics& fontMetrics = font->fontMetrics(); 1712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block int lineGap = fontMetrics.lineGap(); 1722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block textRect = IntRect(point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2, 1732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block point.y() - fontMetrics.ascent() - lineGap, 1742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block totalWidth + fontMetrics.ascent() + fontMetrics.descent(), 1752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block fontMetrics.lineSpacing()); 1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project bitmap.set(graphicsContext->createWindowsBitmap(textRect.size())); 1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project memset(bitmap->buffer(), 255, bitmap->bufferLength()); 1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project hdc = bitmap->hdc(); 1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project XFORM xform; 1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM11 = 1.0f; 1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM12 = 0.0f; 1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM21 = 0.0f; 1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM22 = 1.0f; 1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eDx = -textRect.x(); 1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eDy = -textRect.y(); 1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project SetWorldTransform(hdc, &xform); 1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian SelectObject(hdc, font->platformData().hfont()); 1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Set the correct color. 1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (drawIntoBitmap) 1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project SetTextColor(hdc, RGB(0, 0, 0)); 1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project else 1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue())); 1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project SetBkMode(hdc, TRANSPARENT); 1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project SetTextAlign(hdc, TA_LEFT | TA_BASELINE); 2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Uniscribe gives us offsets to help refine the positioning of combining glyphs. 2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project FloatSize translation = glyphBuffer.offsetAt(from); 2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (translation.width() || translation.height()) { 2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project XFORM xform; 2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM11 = 1.0; 2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM12 = 0; 2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM21 = 0; 2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM22 = 1.0; 2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eDx = translation.width(); 2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eDy = translation.height(); 2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); 2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 214f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (drawingMode == TextModeFill) { 2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project XFORM xform; 2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM11 = 1.0; 2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM12 = 0; 2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0; 2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM22 = 1.0; 2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eDx = point.x(); 2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eDy = point.y(); 2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); 2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); 2245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (font->syntheticBoldOffset()) { 2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eM21 = 0; 2265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian xform.eDx = font->syntheticBoldOffset(); 2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project xform.eDy = 0; 2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); 2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); 2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else { 2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project XFORM xform; 2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project GetWorldTransform(hdc, &xform); 2348a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); 2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity; 2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (font->platformData().syntheticOblique()) 2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0)); 2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project initialGlyphTransform.tx = 0; 2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project initialGlyphTransform.ty = 0; 2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextRef cgContext = graphicsContext->platformContext(); 2418f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextSaveGState(cgContext); 2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project BOOL fontSmoothingEnabled = false; 2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); 2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled); 2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextScaleCTM(cgContext, 1.0, -1.0); 2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height())); 2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2518f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian for (unsigned i = 0; i < numGlyphs; ++i) { 2528f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i))); 2538f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextSaveGState(cgContext); 2548f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextConcatCTM(cgContext, initialGlyphTransform); 2558f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 256f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (drawingMode & TextModeFill) { 2578f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextAddPath(cgContext, glyphPath.get()); 2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextFillPath(cgContext); 2595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (font->syntheticBoldOffset()) { 2605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); 2618f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextAddPath(cgContext, glyphPath.get()); 2628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextFillPath(cgContext); 2635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); 2648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian } 2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 266f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (drawingMode & TextModeStroke) { 2678f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextAddPath(cgContext, glyphPath.get()); 2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextStrokePath(cgContext); 2695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (font->syntheticBoldOffset()) { 2705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); 2718f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextAddPath(cgContext, glyphPath.get()); 2728f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextStrokePath(cgContext); 2735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); 2748f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian } 2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2768f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 2778f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextRestoreGState(cgContext); 2788f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian CGContextTranslateCTM(cgContext, gdiAdvances[i], 0); 2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2808f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextRestoreGState(cgContext); 2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (drawIntoBitmap) { 2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project UInt8* buffer = bitmap->buffer(); 2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project unsigned bufferLength = bitmap->bufferLength(); 2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (unsigned i = 0; i < bufferLength; i += 4) { 2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Use green, which is always in the middle. 2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255; 2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project buffer[i] = fillColor.blue(); 2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project buffer[i + 1] = fillColor.green(); 2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project buffer[i + 2] = fillColor.red(); 2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project buffer[i + 3] = alpha; 2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.location()); 2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else 2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project graphicsContext->releaseWindowsContext(hdc, textRect, true, false); 2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, 3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int from, int numGlyphs, const FloatPoint& point) const 3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextRef cgContext = graphicsContext->platformContext(); 304635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); 305635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 306231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block switch(fontDescription().fontSmoothing()) { 307231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case Antialiased: { 308231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block graphicsContext->setShouldAntialias(true); 309231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block shouldUseFontSmoothing = false; 310231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 311231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 312231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case SubpixelAntialiased: { 313231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block graphicsContext->setShouldAntialias(true); 314231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block shouldUseFontSmoothing = true; 315231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 316231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 317231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case NoSmoothing: { 318231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block graphicsContext->setShouldAntialias(false); 319231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block shouldUseFontSmoothing = false; 320231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 321231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 322231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case AutoSmoothing: { 323231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block // For the AutoSmooth case, don't do anything! Keep the default settings. 324231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 325231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 326231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block default: 327231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ASSERT_NOT_REACHED(); 328231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 329231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 330dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (font->platformData().useGDI() && !shouldUseFontSmoothing) { 331dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); 332dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return; 333635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 335635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing); 3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project const FontPlatformData& platformData = font->platformData(); 3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextSetFont(cgContext, platformData.cgFont()); 3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGAffineTransform matrix = CGAffineTransformIdentity; 3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project matrix.b = -matrix.b; 3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project matrix.d = -matrix.d; 3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (platformData.syntheticOblique()) { 3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f); 3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0)); 3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextSetTextMatrix(cgContext, matrix); 3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Uniscribe gives us offsets to help refine the positioning of combining glyphs. 3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project FloatSize translation = glyphBuffer.offsetAt(from); 3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextSetFontSize(cgContext, platformData.size()); 356635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI()); 3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3585ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen FloatSize shadowOffset; 359545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch float shadowBlur; 3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Color shadowColor; 361f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch ColorSpace shadowColorSpace; 362f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); 3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 364f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch bool hasSimpleShadow = graphicsContext->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && (!graphicsContext->shadowsIgnoreTransforms() || graphicsContext->getCTM().isIdentityOrTranslationOrFlipped()); 3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (hasSimpleShadow) { 3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. 3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project graphicsContext->clearShadow(); 3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Color fillColor = graphicsContext->fillColor(); 3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); 370a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch graphicsContext->setFillColor(shadowFillColor, ColorSpaceDeviceRGB); 371f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch float shadowTextX = point.x() + translation.width() + shadowOffset.width(); 372f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative. 373f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch float shadowTextY = point.y() + translation.height() + shadowOffset.height() * (graphicsContext->shadowsIgnoreTransforms() ? -1 : 1); 374f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY); 3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); 3765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (font->syntheticBoldOffset()) { 3775ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowOffset.height()); 3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); 3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 380a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch graphicsContext->setFillColor(fillColor, ColorSpaceDeviceRGB); 3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); 3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); 3855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (font->syntheticBoldOffset()) { 3865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height()); 3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); 3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (hasSimpleShadow) 391a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB); 3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); 3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 397