summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/win
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
commit1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch)
tree4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /WebCore/platform/graphics/win
parent9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff)
downloadexternal_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'WebCore/platform/graphics/win')
-rw-r--r--WebCore/platform/graphics/win/ColorSafari.cpp5
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp314
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp289
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.cpp173
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.h20
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp61
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h49
-rw-r--r--WebCore/platform/graphics/win/FontPlatformData.h111
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp134
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp89
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataWin.cpp170
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp (renamed from WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp)6
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp72
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp114
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp38
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp77
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp34
-rw-r--r--WebCore/platform/graphics/win/ImageWin.cpp6
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp61
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h9
-rw-r--r--WebCore/platform/graphics/win/OpenTypeUtilities.cpp387
-rw-r--r--WebCore/platform/graphics/win/OpenTypeUtilities.h (renamed from WebCore/platform/graphics/win/FontCairoWin.cpp)23
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.cpp214
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp53
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp97
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataWin.cpp49
-rw-r--r--WebCore/platform/graphics/win/UniscribeController.cpp26
27 files changed, 2112 insertions, 569 deletions
diff --git a/WebCore/platform/graphics/win/ColorSafari.cpp b/WebCore/platform/graphics/win/ColorSafari.cpp
index e7fbf47..a04fd81 100644
--- a/WebCore/platform/graphics/win/ColorSafari.cpp
+++ b/WebCore/platform/graphics/win/ColorSafari.cpp
@@ -68,9 +68,4 @@ Color focusRingColor()
return focusRingColor;
}
-void setFocusRingColorChangeFunction(void (*)())
-{
- notImplemented();
-}
-
} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
index 8b59a48..1766cd9 100644
--- a/WebCore/platform/graphics/win/FontCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -26,11 +26,14 @@
#include "config.h"
#include "Font.h"
+#include "AffineTransform.h"
+#include "FloatConversion.h"
#include "GlyphBuffer.h"
#include "GraphicsContext.h"
#include "IntRect.h"
#include "SimpleFontData.h"
#include "UniscribeController.h"
+#include "WebCoreTextRenderer.h"
#include <ApplicationServices/ApplicationServices.h>
#include <WebKitSystemInterface/WebKitSystemInterface.h>
#include <wtf/MathExtras.h>
@@ -39,59 +42,266 @@ namespace WebCore {
const int syntheticObliqueAngle = 14;
-void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
- int from, int numGlyphs, const FloatPoint& point) const
+static inline CGFloat toCGFloat(FIXED f)
{
- if (font->m_font.useGDI()) {
- // FIXME: Support alpha blending.
- // FIXME: Support text stroke/fill.
- // FIXME: Support text shadow.
- Color fillColor = graphicsContext->fillColor();
- if (fillColor.alpha() == 0)
+ return f.value + f.fract / CGFloat(65536.0);
+}
+
+static CGPathRef createPathForGlyph(HDC hdc, Glyph glyph)
+{
+ CGMutablePathRef path = CGPathCreateMutable();
+
+ static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 };
+ GLYPHMETRICS glyphMetrics;
+ // GGO_NATIVE matches the outline perfectly when Windows font smoothing is off.
+ // GGO_NATIVE | GGO_UNHINTED does not match perfectly either when Windows font smoothing is on or off.
+ DWORD outlineLength = GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, 0, 0, &identity);
+ ASSERT(outlineLength >= 0);
+ if (outlineLength < 0)
+ return path;
+
+ Vector<UInt8> outline(outlineLength);
+ GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, outlineLength, outline.data(), &identity);
+
+ unsigned offset = 0;
+ while (offset < outlineLength) {
+ LPTTPOLYGONHEADER subpath = reinterpret_cast<LPTTPOLYGONHEADER>(outline.data() + offset);
+ ASSERT(subpath->dwType == TT_POLYGON_TYPE);
+ if (subpath->dwType != TT_POLYGON_TYPE)
+ return path;
+
+ CGPathMoveToPoint(path, 0, toCGFloat(subpath->pfxStart.x), toCGFloat(subpath->pfxStart.y));
+
+ unsigned subpathOffset = sizeof(*subpath);
+ while (subpathOffset < subpath->cb) {
+ LPTTPOLYCURVE segment = reinterpret_cast<LPTTPOLYCURVE>(reinterpret_cast<UInt8*>(subpath) + subpathOffset);
+ switch (segment->wType) {
+ case TT_PRIM_LINE:
+ for (unsigned i = 0; i < segment->cpfx; i++)
+ CGPathAddLineToPoint(path, 0, toCGFloat(segment->apfx[i].x), toCGFloat(segment->apfx[i].y));
+ break;
+
+ case TT_PRIM_QSPLINE:
+ for (unsigned i = 0; i < segment->cpfx; i++) {
+ CGFloat x = toCGFloat(segment->apfx[i].x);
+ CGFloat y = toCGFloat(segment->apfx[i].y);
+ CGFloat cpx;
+ CGFloat cpy;
+
+ if (i == segment->cpfx - 2) {
+ cpx = toCGFloat(segment->apfx[i + 1].x);
+ cpy = toCGFloat(segment->apfx[i + 1].y);
+ i++;
+ } else {
+ cpx = (toCGFloat(segment->apfx[i].x) + toCGFloat(segment->apfx[i + 1].x)) / 2;
+ cpy = (toCGFloat(segment->apfx[i].y) + toCGFloat(segment->apfx[i + 1].y)) / 2;
+ }
+
+ CGPathAddQuadCurveToPoint(path, 0, x, y, cpx, cpy);
+ }
+ break;
+
+ case TT_PRIM_CSPLINE:
+ for (unsigned i = 0; i < segment->cpfx; i += 3) {
+ CGFloat cp1x = toCGFloat(segment->apfx[i].x);
+ CGFloat cp1y = toCGFloat(segment->apfx[i].y);
+ CGFloat cp2x = toCGFloat(segment->apfx[i + 1].x);
+ CGFloat cp2y = toCGFloat(segment->apfx[i + 1].y);
+ CGFloat x = toCGFloat(segment->apfx[i + 2].x);
+ CGFloat y = toCGFloat(segment->apfx[i + 2].y);
+
+ CGPathAddCurveToPoint(path, 0, cp1x, cp1y, cp2x, cp2y, x, y);
+ }
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return path;
+ }
+
+ subpathOffset += sizeof(*segment) + (segment->cpfx - 1) * sizeof(segment->apfx[0]);
+ }
+ CGPathCloseSubpath(path);
+ offset += subpath->cb;
+ }
+ return path;
+}
+
+static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point)
+{
+ Color fillColor = graphicsContext->fillColor();
+
+ bool drawIntoBitmap = false;
+ int drawingMode = graphicsContext->textDrawingMode();
+ if (drawingMode == cTextFill) {
+ if (!fillColor.alpha())
return;
- // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances.
- Vector<int, 2048> gdiAdvances;
- int totalWidth = 0;
- for (int i = 0; i < numGlyphs; i++) {
- gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i)));
- totalWidth += gdiAdvances[i];
+ drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer();
+ if (!drawIntoBitmap) {
+ IntSize size;
+ int blur;
+ Color color;
+ graphicsContext->getShadow(size, blur, color);
+ drawIntoBitmap = !size.isEmpty() || blur;
}
+ }
+
+ // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances.
+ Vector<int, 2048> gdiAdvances;
+ int totalWidth = 0;
+ for (int i = 0; i < numGlyphs; i++) {
+ gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i)));
+ totalWidth += gdiAdvances[i];
+ }
+ HDC hdc = 0;
+ OwnPtr<GraphicsContext::WindowsBitmap> bitmap;
+ IntRect textRect;
+ if (!drawIntoBitmap)
+ hdc = graphicsContext->getWindowsContext(textRect, true, false);
+ if (!hdc) {
+ drawIntoBitmap = true;
// We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges.
+ // FIXME: Can get glyphs' optical bounds (even from CG) to get this right.
int lineGap = font->lineGap();
- IntRect textRect(point.x() - lineGap, point.y() - font->ascent() - lineGap, totalWidth + 2 * lineGap, font->lineSpacing());
- HDC hdc = graphicsContext->getWindowsContext(textRect);
- SelectObject(hdc, font->m_font.hfont());
+ textRect = IntRect(point.x() - (font->ascent() + font->descent()) / 2, point.y() - font->ascent() - lineGap, totalWidth + font->ascent() + font->descent(), font->lineSpacing());
+ bitmap.set(graphicsContext->createWindowsBitmap(textRect.size()));
+ memset(bitmap->buffer(), 255, bitmap->bufferLength());
+ hdc = bitmap->hdc();
- // Set the correct color.
- HDC textDrawingDC = hdc;
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -textRect.x();
+ xform.eDy = -textRect.y();
+ SetWorldTransform(hdc, &xform);
+ }
+
+ SelectObject(hdc, font->m_font.hfont());
+
+ // Set the correct color.
+ if (drawIntoBitmap)
+ SetTextColor(hdc, RGB(0, 0, 0));
+ else
SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue()));
- SetBkMode(hdc, TRANSPARENT);
- SetTextAlign(hdc, TA_LEFT | TA_BASELINE);
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextAlign(hdc, TA_LEFT | TA_BASELINE);
- // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
- FloatSize translation = glyphBuffer.offsetAt(from);
- if (translation.width() || translation.height()) {
- XFORM xform;
- xform.eM11 = 1.0;
- xform.eM12 = 0;
+ // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
+ FloatSize translation = glyphBuffer.offsetAt(from);
+ if (translation.width() || translation.height()) {
+ XFORM xform;
+ xform.eM11 = 1.0;
+ xform.eM12 = 0;
+ xform.eM21 = 0;
+ xform.eM22 = 1.0;
+ xform.eDx = translation.width();
+ xform.eDy = translation.height();
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ }
+
+ if (drawingMode == cTextFill) {
+ XFORM xform;
+ xform.eM11 = 1.0;
+ xform.eM12 = 0;
+ xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0;
+ xform.eM22 = 1.0;
+ xform.eDx = point.x();
+ xform.eDy = point.y();
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
+ if (font->m_syntheticBoldOffset) {
xform.eM21 = 0;
- xform.eM22 = 1.0;
- xform.eDx = translation.width();
- xform.eDy = translation.height();
+ xform.eDx = font->m_syntheticBoldOffset;
+ xform.eDy = 0;
ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
+ }
+ } else {
+ RetainPtr<CGMutablePathRef> path(AdoptCF, CGPathCreateMutable());
+
+ XFORM xform;
+ GetWorldTransform(hdc, &xform);
+ AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy);
+ CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity;
+ if (font->platformData().syntheticOblique())
+ initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0));
+ initialGlyphTransform.tx = 0;
+ initialGlyphTransform.ty = 0;
+ CGAffineTransform glyphTranslation = CGAffineTransformIdentity;
+
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
+ CGAffineTransform glyphTransform = CGAffineTransformConcat(initialGlyphTransform, glyphTranslation);
+ CGPathAddPath(path.get(), &glyphTransform, glyphPath.get());
+ glyphTranslation = CGAffineTransformTranslate(glyphTranslation, gdiAdvances[i], 0);
+ }
+
+ CGContextRef cgContext = graphicsContext->platformContext();
+ CGContextSaveGState(cgContext);
+
+ BOOL fontSmoothingEnabled = false;
+ SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0);
+ CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled);
+
+ CGContextScaleCTM(cgContext, 1.0, -1.0);
+ CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height()));
+
+ if (drawingMode & cTextFill) {
+ CGContextAddPath(cgContext, path.get());
+ CGContextFillPath(cgContext);
+ if (font->m_syntheticBoldOffset) {
+ CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
+ CGContextAddPath(cgContext, path.get());
+ CGContextFillPath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ }
+ }
+ if (drawingMode & cTextStroke) {
+ CGContextAddPath(cgContext, path.get());
+ CGContextStrokePath(cgContext);
+ if (font->m_syntheticBoldOffset) {
+ CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
+ CGContextAddPath(cgContext, path.get());
+ CGContextStrokePath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ }
}
- ExtTextOut(hdc, point.x(), point.y(), ETO_GLYPH_INDEX, 0, (WCHAR*)glyphBuffer.glyphs(from), numGlyphs, gdiAdvances.data());
+ CGContextRestoreGState(cgContext);
+ }
+
+ if (drawIntoBitmap) {
+ UInt8* buffer = bitmap->buffer();
+ unsigned bufferLength = bitmap->bufferLength();
+ for (unsigned i = 0; i < bufferLength; i += 4) {
+ // Use green, which is always in the middle.
+ UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255;
+ buffer[i] = fillColor.blue();
+ buffer[i + 1] = fillColor.green();
+ buffer[i + 2] = fillColor.red();
+ buffer[i + 3] = alpha;
+ }
+ graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.topLeft());
+ } else
+ graphicsContext->releaseWindowsContext(hdc, textRect, true, false);
+}
- graphicsContext->releaseWindowsContext(hdc, textRect);
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ if (font->m_font.useGDI()) {
+ drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
return;
}
CGContextRef cgContext = graphicsContext->platformContext();
- uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext);
+ uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, WebCoreShouldUseFontSmoothing());
const FontPlatformData& platformData = font->platformData();
@@ -102,25 +312,49 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
matrix.d = -matrix.d;
if (platformData.syntheticOblique()) {
- static float skew = -tanf(syntheticObliqueAngle * acosf(0) / 90.0f);
+ static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f);
matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0));
}
+ CGContextSetTextMatrix(cgContext, matrix);
+
// Uniscribe gives us offsets to help refine the positioning of combining glyphs.
FloatSize translation = glyphBuffer.offsetAt(from);
- if (translation.width() || translation.height())
- CGAffineTransformTranslate(matrix, translation.width(), translation.height());
-
- CGContextSetTextMatrix(cgContext, matrix);
CGContextSetFontSize(cgContext, platformData.size());
- CGContextSetTextPosition(cgContext, point.x(), point.y());
+ wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false);
+
+ IntSize shadowSize;
+ int shadowBlur;
+ Color shadowColor;
+ graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor);
+
+ bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur;
+ if (hasSimpleShadow) {
+ // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
+ graphicsContext->clearShadow();
+ Color fillColor = graphicsContext->fillColor();
+ Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
+ graphicsContext->setFillColor(shadowFillColor);
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->m_syntheticBoldOffset) {
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + translation.height() + shadowSize.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+ graphicsContext->setFillColor(fillColor);
+ }
+
+ CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height());
CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
if (font->m_syntheticBoldOffset) {
- CGContextSetTextPosition(cgContext, point.x() + font->m_syntheticBoldOffset, point.y());
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->m_syntheticBoldOffset, point.y() + translation.height());
CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
}
+ if (hasSimpleShadow)
+ graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor);
+
wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
}
diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp
index 502863b..49b3d76 100644
--- a/WebCore/platform/graphics/win/FontCacheWin.cpp
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,8 +35,10 @@
#include "UnicodeRange.h"
#include <windows.h>
#include <mlang.h>
+#if PLATFORM(CG)
#include <ApplicationServices/ApplicationServices.h>
#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
using std::min;
@@ -45,7 +47,9 @@ namespace WebCore
void FontCache::platformInit()
{
+#if PLATFORM(CG)
wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac.
+#endif
}
IMLangFontLink2* FontCache::getFontLinkInterface()
@@ -304,55 +308,169 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fo
return getCachedFontPlatformData(fontDescription, timesStr);
}
-bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
+static LONG toGDIFontWeight(FontWeight fontWeight)
{
- LOGFONT winfont;
-
- // The size here looks unusual. The negative number is intentional. The logical size constant is 32.
- winfont.lfHeight = -fontDescription.computedPixelSize() * 32;
- winfont.lfWidth = 0;
- winfont.lfEscapement = 0;
- winfont.lfOrientation = 0;
- winfont.lfUnderline = false;
- winfont.lfStrikeOut = false;
- winfont.lfCharSet = DEFAULT_CHARSET;
-#if PLATFORM(CG)
- winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ static LONG gdiFontWeights[] = {
+ FW_THIN, // FontWeight100
+ FW_EXTRALIGHT, // FontWeight200
+ FW_LIGHT, // FontWeight300
+ FW_NORMAL, // FontWeight400
+ FW_MEDIUM, // FontWeight500
+ FW_SEMIBOLD, // FontWeight600
+ FW_BOLD, // FontWeight700
+ FW_EXTRABOLD, // FontWeight800
+ FW_HEAVY // FontWeight900
+ };
+ return gdiFontWeights[fontWeight];
+}
+
+static inline bool isGDIFontWeightBold(LONG gdiFontWeight)
+{
+ return gdiFontWeight >= FW_SEMIBOLD;
+}
+
+static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family)
+{
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr)) {
+ if (gdiFontWeight == FW_NORMAL)
+ return FW_MEDIUM;
+ if (gdiFontWeight == FW_BOLD)
+ return FW_SEMIBOLD;
+ }
+ return gdiFontWeight;
+}
+
+struct MatchImprovingProcData {
+ MatchImprovingProcData(LONG desiredWeight, bool desiredItalic)
+ : m_desiredWeight(desiredWeight)
+ , m_desiredItalic(desiredItalic)
+ , m_hasMatched(false)
+ {
+ }
+
+ LONG m_desiredWeight;
+ bool m_desiredItalic;
+ bool m_hasMatched;
+ LOGFONT m_chosen;
+};
+
+static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ MatchImprovingProcData* matchData = reinterpret_cast<MatchImprovingProcData*>(lParam);
+
+ if (!matchData->m_hasMatched) {
+ matchData->m_hasMatched = true;
+ matchData->m_chosen = *candidate;
+ return 1;
+ }
+
+ if (!candidate->lfItalic != !matchData->m_chosen.lfItalic) {
+ if (!candidate->lfItalic == !matchData->m_desiredItalic)
+ matchData->m_chosen = *candidate;
+
+ return 1;
+ }
+
+ unsigned chosenWeightDeltaMagnitude = abs(matchData->m_chosen.lfWeight - matchData->m_desiredWeight);
+ unsigned candidateWeightDeltaMagnitude = abs(candidate->lfWeight - matchData->m_desiredWeight);
+
+ // If both are the same distance from the desired weight, prefer the candidate if it is further from regular.
+ if (chosenWeightDeltaMagnitude == candidateWeightDeltaMagnitude && abs(candidate->lfWeight - FW_NORMAL) > abs(matchData->m_chosen.lfWeight - FW_NORMAL)) {
+ matchData->m_chosen = *candidate;
+ return 1;
+ }
+
+ // Otherwise, prefer the one closer to the desired weight.
+ if (candidateWeightDeltaMagnitude < chosenWeightDeltaMagnitude)
+ matchData->m_chosen = *candidate;
+
+ return 1;
+}
+
+static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = min(family.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, family.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ MatchImprovingProcData matchData(desiredWeight, desiredItalic);
+ EnumFontFamiliesEx(hdc, &logFont, matchImprovingEnumProc, reinterpret_cast<LPARAM>(&matchData), 0);
+
+ ReleaseDC(0, hdc);
+
+ if (!matchData.m_hasMatched)
+ return 0;
+
+ matchData.m_chosen.lfHeight = -size;
+ matchData.m_chosen.lfWidth = 0;
+ matchData.m_chosen.lfEscapement = 0;
+ matchData.m_chosen.lfOrientation = 0;
+ matchData.m_chosen.lfUnderline = false;
+ matchData.m_chosen.lfStrikeOut = false;
+ matchData.m_chosen.lfCharSet = DEFAULT_CHARSET;
+#if PLATFORM(CG) || PLATFORM(CAIRO)
+ matchData.m_chosen.lfOutPrecision = OUT_TT_ONLY_PRECIS;
#else
- winfont.lfOutPrecision = OUT_TT_PRECIS;
+ matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS;
#endif
- winfont.lfQuality = 5; // Force cleartype.
- winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- winfont.lfItalic = fontDescription.italic();
-
- // FIXME: Support weights for real. Do our own enumeration of the available weights.
- // We can't rely on Windows here, since we need to follow the CSS2 algorithm for how to fill in
- // gaps in the weight list.
- // FIXME: Hardcoding Lucida Grande for now. It uses different weights than typical Win32 fonts
- // (500/600 instead of 400/700).
- static AtomicString lucidaStr("Lucida Grande");
- if (equalIgnoringCase(family, lucidaStr))
- winfont.lfWeight = fontDescription.bold() ? 600 : 500;
- else
- winfont.lfWeight = fontDescription.bold() ? 700 : 400;
- int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
- memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
- winfont.lfFaceName[len] = '\0';
-
- HFONT hfont = CreateFontIndirect(&winfont);
- // Windows will always give us a valid pointer here, even if the face name is non-existent. We have to double-check
- // and see if the family name was really used.
- HDC dc = GetDC(0);
- SaveDC(dc);
- SelectObject(dc, hfont);
- WCHAR name[LF_FACESIZE];
- GetTextFace(dc, LF_FACESIZE, name);
- RestoreDC(dc, -1);
- ReleaseDC(0, dc);
-
- DeleteObject(hfont);
-
- return !wcsicmp(winfont.lfFaceName, name);
+ matchData.m_chosen.lfQuality = DEFAULT_QUALITY;
+ matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ return CreateFontIndirect(&matchData.m_chosen);
+}
+
+struct TraitsInFamilyProcData {
+ TraitsInFamilyProcData(const AtomicString& familyName)
+ : m_familyName(familyName)
+ {
+ }
+
+ const AtomicString& m_familyName;
+ HashSet<unsigned> m_traitsMasks;
+};
+
+static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
+
+ unsigned traitsMask = 0;
+ traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask;
+ traitsMask |= FontVariantNormalMask;
+ LONG weight = adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName);
+ traitsMask |= weight == FW_THIN ? FontWeight100Mask :
+ weight == FW_EXTRALIGHT ? FontWeight200Mask :
+ weight == FW_LIGHT ? FontWeight300Mask :
+ weight == FW_NORMAL ? FontWeight400Mask :
+ weight == FW_MEDIUM ? FontWeight500Mask :
+ weight == FW_SEMIBOLD ? FontWeight600Mask :
+ weight == FW_BOLD ? FontWeight700Mask :
+ weight == FW_EXTRABOLD ? FontWeight800Mask :
+ FontWeight900Mask;
+ procData->m_traitsMasks.add(traitsMask);
+ return 1;
+}
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ TraitsInFamilyProcData procData(familyName);
+ EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
+ copyToVector(procData.m_traitsMasks, traitsMasks);
+
+ ReleaseDC(0, hdc);
}
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
@@ -364,57 +482,34 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande;
- LOGFONT winfont;
-
- // The size here looks unusual. The negative number is intentional. The logical size constant is 32. We do this
- // for subpixel precision when rendering using Uniscribe. This masks rounding errors related to the HFONT metrics being
- // different from the CGFont metrics.
- // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't look as nice. That may be solvable though.
- winfont.lfHeight = -fontDescription.computedPixelSize() * (useGDI ? 1 : 32);
- winfont.lfWidth = 0;
- winfont.lfEscapement = 0;
- winfont.lfOrientation = 0;
- winfont.lfUnderline = false;
- winfont.lfStrikeOut = false;
- winfont.lfCharSet = DEFAULT_CHARSET;
- winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
- winfont.lfQuality = DEFAULT_QUALITY;
- winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- winfont.lfItalic = fontDescription.italic();
-
- // FIXME: Support weights for real. Do our own enumeration of the available weights.
- // We can't rely on Windows here, since we need to follow the CSS2 algorithm for how to fill in
- // gaps in the weight list.
- // FIXME: Hardcoding Lucida Grande for now. It uses different weights than typical Win32 fonts
- // (500/600 instead of 400/700).
- if (isLucidaGrande) {
- winfont.lfWeight = fontDescription.bold() ? 600 : 500;
- useGDI = false; // Never use GDI for Lucida Grande.
- } else
- winfont.lfWeight = fontDescription.bold() ? 700 : 400;
- int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
- memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
- winfont.lfFaceName[len] = '\0';
-
- HFONT hfont = CreateFontIndirect(&winfont);
- // Windows will always give us a valid pointer here, even if the face name is non-existent. We have to double-check
- // and see if the family name was really used.
- HDC dc = GetDC(0);
- SaveDC(dc);
- SelectObject(dc, hfont);
- WCHAR name[LF_FACESIZE];
- GetTextFace(dc, LF_FACESIZE, name);
- RestoreDC(dc, -1);
- ReleaseDC(0, dc);
-
- if (_wcsicmp(winfont.lfFaceName, name)) {
- DeleteObject(hfont);
+ // The logical size constant is 32. We do this for subpixel precision when rendering using Uniscribe.
+ // This masks rounding errors related to the HFONT metrics being different from the CGFont metrics.
+ // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't
+ // look as nice. That may be solvable though.
+ LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()), family);
+ HFONT hfont = createGDIFont(family, weight, fontDescription.italic(), fontDescription.computedPixelSize() * (useGDI ? 1 : 32));
+
+ if (!hfont)
return 0;
- }
-
- FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(),
- fontDescription.bold(), fontDescription.italic(), useGDI);
- if (!result->cgFont()) {
+
+ if (isLucidaGrande)
+ useGDI = false; // Never use GDI for Lucida Grande.
+
+ LOGFONT logFont;
+ GetObject(hfont, sizeof(LOGFONT), &logFont);
+
+ bool synthesizeBold = isGDIFontWeightBold(weight) && !isGDIFontWeightBold(logFont.lfWeight);
+ bool synthesizeItalic = fontDescription.italic() && !logFont.lfItalic;
+
+ FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), synthesizeBold, synthesizeItalic, useGDI);
+
+#if PLATFORM(CG)
+ bool fontCreationFailed = !result->cgFont();
+#elif PLATFORM(CAIRO)
+ bool fontCreationFailed = !result->fontFace();
+#endif
+
+ if (fontCreationFailed) {
// The creation of the CGFontRef failed for some reason. We already asserted in debug builds, but to make
// absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next
// font.
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
index cf03502..26fceba 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Computer, Inc.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,21 +21,72 @@
#include "config.h"
#include "FontCustomPlatformData.h"
-#include <wtf/RetainPtr.h>
-#include <ApplicationServices/ApplicationServices.h>
-#include "SharedBuffer.h"
+#include "Base64.h"
#include "FontPlatformData.h"
+#include "OpenTypeUtilities.h"
+#include "SharedBuffer.h"
+#include "SoftLinking.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/RetainPtr.h>
+
+// From t2embapi.h, which is missing from the Microsoft Platform SDK.
+typedef unsigned long(WINAPIV *READEMBEDPROC) (void*, void*, unsigned long);
+struct TTLOADINFO;
+#define TTLOAD_PRIVATE 0x00000001
+#define LICENSE_PREVIEWPRINT 0x0004
+#define E_NONE 0x0000L
namespace WebCore {
+using namespace std;
+
+SOFT_LINK_LIBRARY(T2embed);
+SOFT_LINK(T2embed, TTLoadEmbeddedFont, LONG, __stdcall, (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus, READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName, LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo), (phFontReference, ulFlags,pulPrivStatus, ulPrivs, pulStatus, lpfnReadFromStream, lpvReadStream, szWinFamilyName, szMacFamilyName, pTTLoadInfo));
+SOFT_LINK(T2embed, TTGetNewFontName, LONG, __stdcall, (HANDLE* phFontReference, LPWSTR szWinFamilyName, long cchMaxWinName, LPSTR szMacFamilyName, long cchMaxMacName), (phFontReference, szWinFamilyName, cchMaxWinName, szMacFamilyName, cchMaxMacName));
+SOFT_LINK(T2embed, TTDeleteEmbeddedFont, LONG, __stdcall, (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus), (hFontReference, ulFlags, pulStatus));
+
FontCustomPlatformData::~FontCustomPlatformData()
{
CGFontRelease(m_cgFont);
+ if (m_fontReference) {
+ if (m_name.isNull()) {
+ ASSERT(T2embedLibrary());
+ ULONG status;
+ TTDeleteEmbeddedFont(m_fontReference, 0, &status);
+ } else
+ RemoveFontMemResourceEx(m_fontReference);
+ }
}
-FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic)
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode renderingMode)
{
- return FontPlatformData(m_cgFont, size, bold, italic);
+ ASSERT(m_cgFont);
+ ASSERT(m_fontReference);
+ ASSERT(T2embedLibrary());
+
+ LOGFONT logFont;
+ if (m_name.isNull())
+ TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0);
+ else
+ memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), sizeof(logFont.lfFaceName[0]) * min(static_cast<size_t>(LF_FACESIZE), 1 + m_name.length()));
+
+ logFont.lfHeight = -size;
+ if (renderingMode == NormalRenderingMode)
+ logFont.lfHeight *= 32;
+ logFont.lfWidth = 0;
+ logFont.lfEscapement = 0;
+ logFont.lfOrientation = 0;
+ logFont.lfUnderline = false;
+ logFont.lfStrikeOut = false;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ logFont.lfQuality = CLEARTYPE_QUALITY;
+ logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ logFont.lfItalic = italic;
+ logFont.lfWeight = bold ? 700 : 400;
+
+ HFONT hfont = CreateFontIndirect(&logFont);
+ return FontPlatformData(hfont, m_cgFont, size, bold, italic, renderingMode == AlternateRenderingMode);
}
const void* getData(void* info)
@@ -60,9 +111,82 @@ size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count)
return availBytes;
}
+// Streams the concatenation of a header and font data.
+class EOTStream {
+public:
+ EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
+ : m_eotHeader(eotHeader)
+ , m_fontData(fontData)
+ , m_overlayDst(overlayDst)
+ , m_overlaySrc(overlaySrc)
+ , m_overlayLength(overlayLength)
+ , m_offset(0)
+ , m_inHeader(true)
+ {
+ }
+
+ size_t read(void* buffer, size_t count);
+
+private:
+ const Vector<UInt8, 512>& m_eotHeader;
+ const SharedBuffer* m_fontData;
+ size_t m_overlayDst;
+ size_t m_overlaySrc;
+ size_t m_overlayLength;
+ size_t m_offset;
+ bool m_inHeader;
+};
+
+size_t EOTStream::read(void* buffer, size_t count)
+{
+ size_t bytesToRead = count;
+ if (m_inHeader) {
+ size_t bytesFromHeader = min(m_eotHeader.size() - m_offset, count);
+ memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader);
+ m_offset += bytesFromHeader;
+ bytesToRead -= bytesFromHeader;
+ if (m_offset == m_eotHeader.size()) {
+ m_inHeader = false;
+ m_offset = 0;
+ }
+ }
+ if (bytesToRead && !m_inHeader) {
+ size_t bytesFromData = min(m_fontData->size() - m_offset, bytesToRead);
+ memcpy(buffer, m_fontData->data() + m_offset, bytesFromData);
+ if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) {
+ size_t dstOffset = max<int>(m_overlayDst - m_offset, 0);
+ size_t srcOffset = max<int>(0, m_offset - m_overlayDst);
+ size_t bytesToCopy = min(bytesFromData - dstOffset, m_overlayLength - srcOffset);
+ memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy);
+ }
+ m_offset += bytesFromData;
+ bytesToRead -= bytesFromData;
+ }
+ return count - bytesToRead;
+}
+
+static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length)
+{
+ return static_cast<EOTStream*>(stream)->read(buffer, length);
+}
+
+// Creates a unique and unpredictable font name, in order to avoid collisions and to
+// not allow access from CSS.
+static String createUniqueFontName()
+{
+ Vector<char> fontUuid(sizeof(GUID));
+ CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data()));
+
+ Vector<char> fontNameVector;
+ base64Encode(fontUuid, fontNameVector);
+ ASSERT(fontNameVector.size() < LF_FACESIZE);
+ return String(fontNameVector.data(), fontNameVector.size());
+}
+
FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
{
ASSERT_ARG(buffer, buffer);
+ ASSERT(T2embedLibrary());
// Get CG to create the font.
CGDataProviderDirectAccessCallbacks callbacks = { &getData, &releaseData, &getBytesWithOffset, NULL };
@@ -70,7 +194,42 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider.get());
if (!cgFont)
return 0;
- return new FontCustomPlatformData(cgFont);
+
+ // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's
+ // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the
+ // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name
+ // we avoid namespace collisions.
+
+ String fontName = createUniqueFontName();
+
+ // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, so we need to create an EOT header
+ // and prepend it to the font data.
+ Vector<UInt8, 512> eotHeader;
+ size_t overlayDst;
+ size_t overlaySrc;
+ size_t overlayLength;
+ if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength)) {
+ CGFontRelease(cgFont);
+ return 0;
+ }
+
+ HANDLE fontReference;
+ ULONG privStatus;
+ ULONG status;
+ EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength);
+
+ LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0);
+ if (loadEmbeddedFontResult == E_NONE)
+ fontName = String();
+ else {
+ fontReference = renameAndActivateFont(buffer, fontName);
+ if (!fontReference) {
+ CGFontRelease(cgFont);
+ return 0;
+ }
+ }
+
+ return new FontCustomPlatformData(cgFont, fontReference, fontName);
}
}
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.h b/WebCore/platform/graphics/win/FontCustomPlatformData.h
index 9f30424..34a9851 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Computer, Inc.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,6 +21,8 @@
#ifndef FontCustomPlatformData_h
#define FontCustomPlatformData_h
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
#include <wtf/Noncopyable.h>
typedef struct CGFont* CGFontRef;
@@ -31,17 +33,23 @@ class FontPlatformData;
class SharedBuffer;
struct FontCustomPlatformData : Noncopyable {
- FontCustomPlatformData(CGFontRef cgFont)
- : m_cgFont(cgFont)
- {}
+ FontCustomPlatformData(CGFontRef cgFont, HANDLE fontReference, const String& name)
+ : m_cgFont(cgFont)
+ , m_fontReference(fontReference)
+ , m_name(name)
+ {
+ }
+
~FontCustomPlatformData();
- FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
CGFontRef m_cgFont;
+ HANDLE m_fontReference;
+ String m_name;
};
-FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
}
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
new file mode 100644
index 0000000..e54d85a
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformDataCairo.h"
+
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+FontCustomPlatformDataCairo::~FontCustomPlatformDataCairo()
+{
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData FontCustomPlatformDataCairo::fontPlatformData(int size, bool bold, bool italic)
+{
+ return FontPlatformData(m_fontFace, size, bold, italic);
+}
+
+static void releaseData(void* data)
+{
+ static_cast<SharedBuffer*>(data)->deref();
+}
+
+FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ buffer->ref();
+ HFONT font = reinterpret_cast<HFONT>(buffer);
+ cairo_font_face_t* fontFace = cairo_win32_font_face_create_for_hfont(font);
+ if (!fontFace)
+ return 0;
+
+ static cairo_user_data_key_t bufferKey;
+ cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData);
+
+ return new FontCustomPlatformDataCairo(fontFace);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
new file mode 100644
index 0000000..87794b5
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformDataCairo_h
+#define FontCustomPlatformDataCairo_h
+
+#include <wtf/Noncopyable.h>
+
+#include <cairo.h>
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformDataCairo : Noncopyable {
+ FontCustomPlatformDataCairo(cairo_font_face_t* fontFace)
+ : m_fontFace(fontFace)
+ {
+ }
+ ~FontCustomPlatformDataCairo();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+
+ cairo_font_face_t* m_fontFace;
+};
+
+FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h
index 15d23cd..d61afa8 100644
--- a/WebCore/platform/graphics/win/FontPlatformData.h
+++ b/WebCore/platform/graphics/win/FontPlatformData.h
@@ -2,7 +2,7 @@
* This file is part of the internal font implementation. It should not be included by anyone other than
* FontMac.cpp, FontWin.cpp and Font.cpp.
*
- * Copyright (C) 2006, 2007 Apple Inc.
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -25,45 +25,58 @@
#define FontPlatformData_H
#include "StringImpl.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/RefCounted.h>
-typedef struct HFONT__ *HFONT;
-typedef struct CGFont *CGFontRef;
+#if PLATFORM(CAIRO)
+#include <cairo-win32.h>
+#endif
+
+typedef struct HFONT__* HFONT;
+typedef struct CGFont* CGFontRef;
namespace WebCore {
class FontDescription;
-class FontPlatformData
-{
+class FontPlatformData {
public:
- class Deleted {};
-
- // Used for deleted values in the font cache's hash tables.
- FontPlatformData(Deleted)
- : m_font((HFONT)-1)
- , m_cgFont(NULL)
- , m_size(0)
- , m_syntheticBold(false)
- , m_syntheticOblique(false)
- , m_useGDI(false)
- {}
-
FontPlatformData()
- : m_font(0)
- , m_cgFont(NULL)
- , m_size(0)
- , m_syntheticBold(false)
- , m_syntheticOblique(false)
- , m_useGDI(false)
- {}
+#if PLATFORM(CAIRO)
+ : m_fontFace(0)
+ ,
+#else
+ :
+#endif
+ m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_useGDI(false)
+ {
+ }
FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI);
FontPlatformData(float size, bool bold, bool oblique);
- FontPlatformData(CGFontRef, float size, bool bold, bool oblique);
+
+#if PLATFORM(CG)
+ FontPlatformData(HFONT, CGFontRef, float size, bool bold, bool oblique, bool useGDI);
+#elif PLATFORM(CAIRO)
+ FontPlatformData(cairo_font_face_t*, float size, bool bold, bool oblique);
+#endif
~FontPlatformData();
- HFONT hfont() const { return m_font; }
- CGFontRef cgFont() const { return m_cgFont; }
+ FontPlatformData(WTF::HashTableDeletedValueType) : m_font(WTF::HashTableDeletedValue) { }
+ bool isHashTableDeletedValue() const { return m_font.isHashTableDeletedValue(); }
+
+ HFONT hfont() const { return m_font->hfont(); }
+#if PLATFORM(CG)
+ CGFontRef cgFont() const { return m_cgFont.get(); }
+#elif PLATFORM(CAIRO)
+ void setFont(cairo_t* ft) const;
+ cairo_font_face_t* fontFace() const { return m_fontFace; }
+ cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
+#endif
float size() const { return m_size; }
void setSize(float size) { m_size = size; }
@@ -73,19 +86,55 @@ public:
unsigned hash() const
{
- return StringImpl::computeHash((UChar*)(&m_font), sizeof(HFONT) / sizeof(UChar));
+ return m_font->hash();
}
bool operator==(const FontPlatformData& other) const
{
- return m_font == other.m_font && m_cgFont ==other.m_cgFont && m_size == other.m_size &&
+ return m_font == other.m_font &&
+#if PLATFORM(CG)
+ m_cgFont == other.m_cgFont &&
+#elif PLATFORM(CAIRO)
+ m_fontFace == other.m_fontFace &&
+ m_scaledFont == other.m_scaledFont &&
+#endif
+ m_size == other.m_size &&
m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique &&
m_useGDI == other.m_useGDI;
}
private:
- HFONT m_font;
- CGFontRef m_cgFont;
+ class RefCountedHFONT : public RefCounted<RefCountedHFONT> {
+ public:
+ static PassRefPtr<RefCountedHFONT> create(HFONT hfont) { return adoptRef(new RefCountedHFONT(hfont)); }
+ static PassRefPtr<RefCountedHFONT> createDeleted() { return adoptRef(new RefCountedHFONT(reinterpret_cast<HFONT>(-1))); }
+
+ ~RefCountedHFONT() { if (m_hfont != reinterpret_cast<HFONT>(-1)) DeleteObject(m_hfont); }
+
+ HFONT hfont() const { return m_hfont; }
+ unsigned hash() const
+ {
+ return StringImpl::computeHash(reinterpret_cast<const UChar*>(&m_hfont), sizeof(HFONT) / sizeof(UChar));
+ }
+
+ private:
+ RefCountedHFONT(HFONT hfont)
+ : m_hfont(hfont)
+ {
+ }
+
+ HFONT m_hfont;
+ };
+
+ void platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName);
+
+ RefPtr<RefCountedHFONT> m_font;
+#if PLATFORM(CG)
+ RetainPtr<CGFontRef> m_cgFont;
+#elif PLATFORM(CAIRO)
+ cairo_font_face_t* m_fontFace;
+ cairo_scaled_font_t* m_scaledFont;
+#endif
float m_size;
bool m_syntheticBold;
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
new file mode 100644
index 0000000..bbfdb9f
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include "StringHash.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+using std::min;
+
+namespace WebCore {
+
+static inline USHORT readBigEndianWord(const BYTE* word) { return (word[0] << 8) | word[1]; }
+
+static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc)
+{
+ const DWORD cMaxNameTableSize = 1024 * 1024;
+
+ static HashMap<String, RetainPtr<CFStringRef> > nameMap;
+
+ // Check our hash first.
+ String faceString(faceName);
+ RetainPtr<CFStringRef> result = nameMap.get(faceString);
+ if (result)
+ return result.get();
+
+ // We need to obtain the PostScript name from the name table and use it instead,.
+ DWORD bufferSize = GetFontData(dc, 'eman', 0, NULL, 0); // "name" backwards
+ if (bufferSize == 0 || bufferSize == GDI_ERROR || bufferSize > cMaxNameTableSize)
+ return NULL;
+
+ Vector<BYTE> bufferVector(bufferSize);
+ BYTE* buffer = bufferVector.data();
+ if (GetFontData(dc, 'eman', 0, buffer, bufferSize) == GDI_ERROR)
+ return NULL;
+
+ if (bufferSize < 6)
+ return NULL;
+
+ USHORT numberOfRecords = readBigEndianWord(buffer + 2);
+ UINT stringsOffset = readBigEndianWord(buffer + 4);
+ if (bufferSize < stringsOffset)
+ return NULL;
+
+ BYTE* strings = buffer + stringsOffset;
+
+ // Now walk each name record looking for a Mac or Windows PostScript name.
+ UINT offset = 6;
+ for (int i = 0; i < numberOfRecords; i++) {
+ if (bufferSize < offset + 12)
+ return NULL;
+
+ USHORT platformID = readBigEndianWord(buffer + offset);
+ USHORT encodingID = readBigEndianWord(buffer + offset + 2);
+ USHORT languageID = readBigEndianWord(buffer + offset + 4);
+ USHORT nameID = readBigEndianWord(buffer + offset + 6);
+ USHORT length = readBigEndianWord(buffer + offset + 8);
+ USHORT nameOffset = readBigEndianWord(buffer + offset + 10);
+
+ if (platformID == 3 && encodingID == 1 && languageID == 0x409 && nameID == 6) {
+ // This is a Windows PostScript name and is therefore UTF-16.
+ // Pass Big Endian as the encoding.
+ if (bufferSize < stringsOffset + nameOffset + length)
+ return NULL;
+ result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingUTF16BE, false));
+ break;
+ } else if (platformID == 1 && encodingID == 0 && languageID == 0 && nameID == 6) {
+ // This is a Mac PostScript name and is therefore ASCII.
+ // See http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
+ if (bufferSize < stringsOffset + nameOffset + length)
+ return NULL;
+ result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingASCII, false));
+ break;
+ }
+
+ offset += 12;
+ }
+
+ if (result)
+ nameMap.set(faceString, result);
+ return result.get();
+}
+
+void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
+{
+ // Try the face name first. Windows may end up localizing this name, and CG doesn't know about
+ // the localization. If the create fails, we'll try the PostScript name.
+ RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)));
+ m_cgFont.adoptCF(CGFontCreateWithFontName(fullName.get()));
+ if (!m_cgFont) {
+ CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc);
+ if (postScriptName) {
+ m_cgFont.adoptCF(CGFontCreateWithFontName(postScriptName));
+ ASSERT(m_cgFont);
+ }
+ }
+}
+
+FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI)
+ : m_font(RefCountedHFONT::create(hfont))
+ , m_size(size)
+ , m_cgFont(font)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(useGDI)
+{
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
new file mode 100644
index 0000000..438d0a9
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2007 Alp Toker
+ * Copyright (C) 2008 Brent Fulgham
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+#include <cairo-win32.h>
+
+using std::min;
+
+namespace WebCore {
+
+void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
+{
+ m_fontFace = cairo_win32_font_face_create_for_hfont(font);
+ cairo_matrix_t sizeMatrix, ctm;
+ cairo_matrix_init_identity(&ctm);
+ cairo_matrix_init_scale(&sizeMatrix, size, size);
+
+ static cairo_font_options_t* fontOptions = 0;
+ if (!fontOptions)
+ {
+ fontOptions = cairo_font_options_create();
+ cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
+ }
+
+ m_scaledFont = cairo_scaled_font_create(m_fontFace, &sizeMatrix, &ctm, fontOptions);
+}
+
+FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool oblique)
+ : m_font(0)
+ , m_size(size)
+ , m_fontFace(fontFace)
+ , m_scaledFont(0)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(false)
+{
+ cairo_matrix_t fontMatrix;
+ cairo_matrix_init_scale(&fontMatrix, size, size);
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+ cairo_font_options_t* options = cairo_font_options_create();
+
+ // We force antialiasing and disable hinting to provide consistent
+ // typographic qualities for custom fonts on all platforms.
+ cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
+
+ m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
+ cairo_font_options_destroy(options);
+}
+
+void FontPlatformData::setFont(cairo_t* cr) const
+{
+ ASSERT(m_scaledFont);
+
+ cairo_set_scaled_font(cr, m_scaledFont);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
index a5fab36..4b4df5a 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
@@ -2,7 +2,8 @@
* This file is part of the internal font implementation. It should not be included by anyone other than
* FontMac.cpp, FontWin.cpp and Font.cpp.
*
- * Copyright (C) 2006, 2007 Apple Inc.
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2008 Brent Fulgham
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,7 +27,6 @@
#include "PlatformString.h"
#include "StringHash.h"
-#include <ApplicationServices/ApplicationServices.h>
#include <wtf/HashMap.h>
#include <wtf/RetainPtr.h>
#include <wtf/Vector.h>
@@ -35,105 +35,17 @@ using std::min;
namespace WebCore {
-static const int Bold = (1 << 0);
-static const int Italic = (1 << 1);
-static const int BoldOblique = (1 << 2);
-
-static inline USHORT readBigEndianWord(const BYTE* word) { return (word[0] << 8) | word[1]; }
-
-static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc)
-{
- const DWORD cMaxNameTableSize = 1024 * 1024;
-
- static HashMap<String, RetainPtr<CFStringRef> > nameMap;
-
- // Check our hash first.
- String faceString(faceName);
- RetainPtr<CFStringRef> result = nameMap.get(faceString);
- if (result)
- return result.get();
-
- // We need to obtain the PostScript name from the name table and use it instead,.
- DWORD bufferSize = GetFontData(dc, 'eman', 0, NULL, 0); // "name" backwards
- if (bufferSize == 0 || bufferSize == GDI_ERROR || bufferSize > cMaxNameTableSize)
- return NULL;
-
- Vector<BYTE> bufferVector(bufferSize);
- BYTE* buffer = bufferVector.data();
- if (GetFontData(dc, 'eman', 0, buffer, bufferSize) == GDI_ERROR)
- return NULL;
-
- if (bufferSize < 6)
- return NULL;
-
- USHORT numberOfRecords = readBigEndianWord(buffer + 2);
- UINT stringsOffset = readBigEndianWord(buffer + 4);
- if (bufferSize < stringsOffset)
- return NULL;
-
- BYTE* strings = buffer + stringsOffset;
-
- // Now walk each name record looking for a Mac or Windows PostScript name.
- UINT offset = 6;
- for (int i = 0; i < numberOfRecords; i++) {
- if (bufferSize < offset + 12)
- return NULL;
-
- USHORT platformID = readBigEndianWord(buffer + offset);
- USHORT encodingID = readBigEndianWord(buffer + offset + 2);
- USHORT languageID = readBigEndianWord(buffer + offset + 4);
- USHORT nameID = readBigEndianWord(buffer + offset + 6);
- USHORT length = readBigEndianWord(buffer + offset + 8);
- USHORT nameOffset = readBigEndianWord(buffer + offset + 10);
-
- if (platformID == 3 && encodingID == 1 && languageID == 0x409 && nameID == 6) {
- // This is a Windows PostScript name and is therefore UTF-16.
- // Pass Big Endian as the encoding.
- if (bufferSize < stringsOffset + nameOffset + length)
- return NULL;
- result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingUTF16BE, false));
- break;
- } else if (platformID == 1 && encodingID == 0 && languageID == 0 && nameID == 6) {
- // This is a Mac PostScript name and is therefore ASCII.
- // See http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
- if (bufferSize < stringsOffset + nameOffset + length)
- return NULL;
- result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingASCII, false));
- break;
- }
-
- offset += 12;
- }
-
- if (result)
- nameMap.set(faceString, result);
- return result.get();
-}
-
-static int CALLBACK enumStylesCallback(const LOGFONT* logFont, const TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
-{
- int *style = reinterpret_cast<int*>(lParam);
-
- // FIXME: In order to accommodate Lucida we go ahead and consider a weight of 600 to be bold.
- // This does mean we'll consider demibold and semibold fonts on windows to also be bold. This
- // is rare enough that it seems like an ok hack for now.
- if (logFont->lfWeight >= 600) {
- if (logFont->lfItalic)
- *style |= BoldOblique;
- else
- *style |= Bold;
- } else if (logFont->lfItalic)
- *style |= Italic;
-
- return 1;
-}
-
FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI)
- : m_font(font)
+ : m_font(RefCountedHFONT::create(font))
, m_size(size)
+#if PLATFORM(CG)
, m_cgFont(0)
- , m_syntheticBold(false)
- , m_syntheticOblique(false)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
, m_useGDI(useGDI)
{
HDC hdc = GetDC(0);
@@ -142,54 +54,16 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq
SelectObject(hdc, font);
UINT bufferSize = GetOutlineTextMetrics(hdc, 0, NULL);
- ASSERT_WITH_MESSAGE(bufferSize != 0, "Bitmap fonts not supported with CoreGraphics.");
+ ASSERT_WITH_MESSAGE(bufferSize, "Bitmap fonts not supported with CoreGraphics.");
- if (bufferSize != 0) {
+ if (bufferSize) {
OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize);
GetOutlineTextMetricsW(hdc, bufferSize, metrics);
WCHAR* faceName = (WCHAR*)((uintptr_t)metrics + (uintptr_t)metrics->otmpFaceName);
- if (!useGDI && (bold || oblique)) {
- LOGFONT logFont;
-
- int len = min((int)wcslen(faceName), LF_FACESIZE - 1);
- memcpy(logFont.lfFaceName, faceName, len * sizeof(WORD));
- logFont.lfFaceName[len] = '\0';
- logFont.lfCharSet = metrics->otmTextMetrics.tmCharSet;
- logFont.lfPitchAndFamily = 0;
-
- int styles = 0;
- EnumFontFamiliesEx(hdc, &logFont, enumStylesCallback, reinterpret_cast<LPARAM>(&styles), 0);
-
- // Check if we need to synthesize bold or oblique. The rule that complicates things here
- // is that if the requested font is bold and oblique, and both a bold font and an oblique font
- // exist, the bold font should be used, and oblique synthesized.
- if (bold && oblique) {
- if (styles == 0) {
- m_syntheticBold = true;
- m_syntheticOblique = true;
- } else if (styles & Bold)
- m_syntheticOblique = true;
- else if (styles & Italic)
- m_syntheticBold = true;
- } else if (bold && (!(styles & Bold)))
- m_syntheticBold = true;
- else if (oblique && !(styles & Italic))
- m_syntheticOblique = true;
- }
+ platformDataInit(font, size, hdc, faceName);
- // Try the face name first. Windows may end up localizing this name, and CG doesn't know about
- // the localization. If the create fails, we'll try the PostScript name.
- RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)));
- m_cgFont = CGFontCreateWithFontName(fullName.get());
- if (!m_cgFont) {
- CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc);
- if (postScriptName) {
- m_cgFont = CGFontCreateWithFontName(postScriptName);
- ASSERT(m_cgFont);
- }
- }
free(metrics);
}
@@ -198,19 +72,13 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq
}
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
- : m_font(0)
- , m_size(size)
+ : m_size(size)
+#if PLATFORM(CG)
, m_cgFont(0)
- , m_syntheticBold(bold)
- , m_syntheticOblique(oblique)
- , m_useGDI(false)
-{
-}
-
-FontPlatformData::FontPlatformData(CGFontRef font, float size, bool bold, bool oblique)
- : m_font(0)
- , m_size(size)
- , m_cgFont(font)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
, m_syntheticBold(bold)
, m_syntheticOblique(oblique)
, m_useGDI(false)
diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
index 23b756c..c11fc1b 100644
--- a/WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp
+++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,9 +36,9 @@ namespace WebCore {
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
- // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters.
+ // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs.
// We won't support this for now.
- if (bufferLength > GlyphPage::size)
+ if (bufferLength > length)
return false;
bool haveGlyphs = false;
diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
new file mode 100644
index 0000000..b679ced
--- /dev/null
+++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs.
+ // We won't support this for now.
+ if (bufferLength > length)
+ return false;
+
+ bool haveGlyphs = false;
+
+ HDC dc = GetDC((HWND)0);
+ SaveDC(dc);
+ SelectObject(dc, fontData->platformData().hfont());
+
+ TEXTMETRIC tm;
+ GetTextMetrics(dc, &tm);
+
+ WORD localGlyphBuffer[GlyphPage::size * 2];
+ DWORD result = GetGlyphIndices(dc, buffer, bufferLength, localGlyphBuffer, 0);
+ bool success = result != GDI_ERROR && static_cast<unsigned>(result) == bufferLength;
+ if (success) {
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = localGlyphBuffer[i];
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+ }
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+
+ return haveGlyphs;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index 58829b5..5a4279a 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -38,7 +38,7 @@ using namespace std;
namespace WebCore {
-static CGContextRef CGContextWithHDC(HDC hdc)
+static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha)
{
HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
@@ -46,8 +46,10 @@ static CGContextRef CGContextWithHDC(HDC hdc)
GetObject(bitmap, sizeof(info), &info);
ASSERT(info.bmBitsPixel == 32);
+
+ CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | (hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst);
CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
- info.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
+ info.bmWidthBytes, deviceRGB, bitmapInfo);
CGColorSpaceRelease(deviceRGB);
// Flip coords
@@ -60,9 +62,9 @@ static CGContextRef CGContextWithHDC(HDC hdc)
return context;
}
-GraphicsContext::GraphicsContext(HDC hdc)
+GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
: m_common(createGraphicsContextPrivate())
- , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc)))
+ , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha)))
{
CGContextRelease(m_data->m_cgContext);
m_data->m_hdc = hdc;
@@ -76,9 +78,12 @@ GraphicsContext::GraphicsContext(HDC hdc)
bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
-HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend)
+// FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into a single API
+// suitable for all clients?
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
- if (inTransparencyLayer()) {
+ // FIXME: Should a bitmap be created also when a shadow is set?
+ if (mayCreateBitmap && inTransparencyLayer()) {
if (dstRect.isEmpty())
return 0;
@@ -133,9 +138,9 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
return m_data->m_hdc;
}
-void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend)
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
- if (hdc && inTransparencyLayer()) {
+ if (mayCreateBitmap && hdc && inTransparencyLayer()) {
if (dstRect.isEmpty())
return;
@@ -168,75 +173,60 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
m_data->restore();
}
-void GraphicsContextPlatformPrivate::save()
+GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
+ : m_hdc(0)
+ , m_size(size)
{
- if (!m_hdc)
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = m_size.width();
+ bitmapInfo.bmiHeader.biHeight = m_size.height();
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&m_bitmapBuffer), 0, 0);
+ if (!m_bitmap)
return;
- SaveDC(m_hdc);
-}
-void GraphicsContextPlatformPrivate::restore()
-{
- if (!m_hdc)
- return;
- RestoreDC(m_hdc, -1);
-}
+ m_hdc = CreateCompatibleDC(hdc);
+ SelectObject(m_hdc, m_bitmap);
-void GraphicsContextPlatformPrivate::clip(const IntRect& clipRect)
-{
- if (!m_hdc)
- return;
- IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom());
-}
+ BITMAP bmpInfo;
+ GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo);
+ m_bytesPerRow = bmpInfo.bmWidthBytes;
+ m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
-void GraphicsContextPlatformPrivate::clip(const Path&)
-{
- notImplemented();
+ SetGraphicsMode(m_hdc, GM_ADVANCED);
}
-void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
+GraphicsContext::WindowsBitmap::~WindowsBitmap()
{
- if (!m_hdc)
+ if (!m_bitmap)
return;
- XFORM xform;
- xform.eM11 = size.width();
- xform.eM12 = 0.0f;
- xform.eM21 = 0.0f;
- xform.eM22 = size.height();
- xform.eDx = 0.0f;
- xform.eDy = 0.0f;
- ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
-}
-static const double deg2rad = 0.017453292519943295769; // pi/180
+ DeleteDC(m_hdc);
+ DeleteObject(m_bitmap);
+}
-void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
+GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize size)
{
- float radiansAngle = degreesAngle * deg2rad;
- float cosAngle = cosf(radiansAngle);
- float sinAngle = sinf(radiansAngle);
- XFORM xform;
- xform.eM11 = cosAngle;
- xform.eM12 = -sinAngle;
- xform.eM21 = sinAngle;
- xform.eM22 = cosAngle;
- xform.eDx = 0.0f;
- xform.eDy = 0.0f;
- ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+ return new WindowsBitmap(m_data->m_hdc, size);
}
-void GraphicsContextPlatformPrivate::translate(float x , float y)
+void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point)
{
- if (!m_hdc)
- return;
- XFORM xform;
- xform.eM11 = 1.0f;
- xform.eM12 = 0.0f;
- xform.eM21 = 0.0f;
- xform.eM22 = 1.0f;
- xform.eDx = x;
- xform.eDy = y;
- ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+ RetainPtr<CGColorSpaceRef> deviceRGB(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, image->buffer(), image->bufferLength(), kCFAllocatorNull));
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(imageData.get()));
+ RetainPtr<CGImageRef> cgImage(AdoptCF, CGImageCreate(image->size().width(), image->size().height(), 8, 32, image->bytesPerRow(), deviceRGB.get(),
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst, dataProvider.get(), 0, true, kCGRenderingIntentDefault));
+ CGContextDrawImage(m_data->m_cgContext, CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get());
}
void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
index c3fbdd7..3dcf6ba 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -37,7 +37,7 @@ using namespace std;
namespace WebCore {
-GraphicsContext::GraphicsContext(HDC dc)
+GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
: m_common(createGraphicsContextPrivate())
, m_data(new GraphicsContextPlatformPrivate)
{
@@ -58,8 +58,13 @@ GraphicsContext::GraphicsContext(HDC dc)
}
}
-HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend)
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
+ // FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs
+ // to be addressed.
+ if (dstRect.isEmpty())
+ return 0;
+
// This is probably wrong, and definitely out of date. Pulled from old SVN
cairo_surface_t* surface = cairo_get_target(platformContext());
HDC hdc = cairo_win32_surface_get_dc(surface);
@@ -77,36 +82,41 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
xform.eM22 = mat.yy;
xform.eDx = mat.x0;
xform.eDy = mat.y0;
- SetWorldTransform(hdc, &xform);
+ ::SetWorldTransform(hdc, &xform);
return hdc;
}
bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
-void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend)
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
+ // FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs
+ // to be addressed.
+ if (dstRect.isEmpty())
+ return;
+
cairo_surface_t* surface = cairo_get_target(platformContext());
HDC hdc2 = cairo_win32_surface_get_dc(surface);
RestoreDC(hdc2, -1);
cairo_surface_mark_dirty(surface);
}
-void GraphicsContext::concatCTM(const AffineTransform& transform)
+void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
{
- cairo_surface_t* surface = cairo_get_target(platformContext());
+ cairo_surface_t* surface = cairo_get_target(cr);
HDC hdc = cairo_win32_surface_get_dc(surface);
SaveDC(hdc);
- cairo_matrix_t mat;
- cairo_get_matrix(platformContext(), &mat);
+ const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
+
XFORM xform;
- xform.eM11 = mat.xx;
- xform.eM12 = mat.xy;
- xform.eM21 = mat.yx;
- xform.eM22 = mat.yy;
- xform.eDx = mat.x0;
- xform.eDy = mat.y0;
+ xform.eM11 = matrix->xx;
+ xform.eM12 = matrix->xy;
+ xform.eM21 = matrix->yx;
+ xform.eM22 = matrix->yy;
+ xform.eDx = matrix->x0;
+ xform.eDy = matrix->y0;
ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
}
diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
index a8f2148..dbf9fad 100644
--- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -26,6 +26,12 @@
#include "config.h"
#include "GraphicsContext.h"
+#if PLATFORM(CG)
+#include "GraphicsContextPlatformPrivateCG.h"
+#elif PLATFORM(CAIRO)
+#include "GraphicsContextPlatformPrivateCairo.h"
+#endif
+
#include "AffineTransform.h"
#include "NotImplemented.h"
#include "Path.h"
@@ -37,6 +43,77 @@ namespace WebCore {
class SVGResourceImage;
+void GraphicsContextPlatformPrivate::save()
+{
+ if (!m_hdc)
+ return;
+ SaveDC(m_hdc);
+}
+
+void GraphicsContextPlatformPrivate::restore()
+{
+ if (!m_hdc)
+ return;
+ RestoreDC(m_hdc, -1);
+}
+
+void GraphicsContextPlatformPrivate::clip(const FloatRect& clipRect)
+{
+ if (!m_hdc)
+ return;
+ IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom());
+}
+
+void GraphicsContextPlatformPrivate::clip(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
+{
+ if (!m_hdc)
+ return;
+ XFORM xform;
+ xform.eM11 = size.width();
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = size.height();
+ xform.eDx = 0.0f;
+ xform.eDy = 0.0f;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
+{
+ float radiansAngle = degreesAngle * deg2rad;
+ float cosAngle = cosf(radiansAngle);
+ float sinAngle = sinf(radiansAngle);
+ XFORM xform;
+ xform.eM11 = cosAngle;
+ xform.eM12 = -sinAngle;
+ xform.eM21 = sinAngle;
+ xform.eM22 = cosAngle;
+ xform.eDx = 0.0f;
+ xform.eDy = 0.0f;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContextPlatformPrivate::translate(float x , float y)
+{
+ if (!m_hdc)
+ return;
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = x;
+ xform.eDy = y;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
#if ENABLE(SVG)
GraphicsContext* contextForImage(SVGResourceImage*)
{
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
index 60cebe3..c02b56e 100644
--- a/WebCore/platform/graphics/win/IconWin.cpp
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (C) 2006, 2007 Apple Inc.
+* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -23,27 +23,25 @@
#include "GraphicsContext.h"
#include "PlatformString.h"
+#include <tchar.h>
#include <windows.h>
namespace WebCore {
-Icon::Icon()
- : m_hIcon(0)
-{
-}
+static const int shell32MultipleFileIconIndex = 54;
Icon::Icon(HICON icon)
: m_hIcon(icon)
{
+ ASSERT(icon);
}
Icon::~Icon()
{
- if (m_hIcon)
- DestroyIcon(m_hIcon);
+ DestroyIcon(m_hIcon);
}
-PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
@@ -52,9 +50,23 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON))
return 0;
- Icon* icon = new Icon();
- icon->m_hIcon = sfi.hIcon;
- return icon;
+ return adoptRef(new Icon(sfi.hIcon));
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&)
+{
+ TCHAR buffer[MAX_PATH];
+ UINT length = ::GetSystemDirectory(buffer, ARRAYSIZE(buffer));
+ if (!length)
+ return 0;
+
+ if (_tcscat_s(buffer, TEXT("\\shell32.dll")))
+ return 0;
+
+ HICON hIcon;
+ if (!::ExtractIconEx(buffer, shell32MultipleFileIconIndex, 0, &hIcon, 1))
+ return 0;
+ return adoptRef(new Icon(hIcon));
}
void Icon::paint(GraphicsContext* context, const IntRect& r)
diff --git a/WebCore/platform/graphics/win/ImageWin.cpp b/WebCore/platform/graphics/win/ImageWin.cpp
index 2d3a87a..54c5b41 100644
--- a/WebCore/platform/graphics/win/ImageWin.cpp
+++ b/WebCore/platform/graphics/win/ImageWin.cpp
@@ -42,12 +42,12 @@ void BitmapImage::invalidatePlatformData()
{
}
-Image* Image::loadPlatformResource(const char *name)
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
{
RefPtr<SharedBuffer> buffer = loadResourceIntoBuffer(name);
- BitmapImage* img = new BitmapImage;
+ RefPtr<BitmapImage> img = BitmapImage::create();
img->setData(buffer.release(), true);
- return img;
+ return img.release();
}
bool BitmapImage::getHBITMAP(HBITMAP bmp)
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index 65b3db6..cef4217 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -28,13 +28,22 @@
#if ENABLE(VIDEO)
#include "MediaPlayerPrivateQuickTimeWin.h"
-#include "DeprecatedString.h"
#include "GraphicsContext.h"
#include "KURL.h"
#include "QTMovieWin.h"
#include "ScrollView.h"
#include <wtf/MathExtras.h>
+#if DRAW_FRAME_RATE
+#include "Font.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "Document.h"
+#include "RenderObject.h"
+#include "RenderStyle.h"
+#include "Windows.h"
+#endif
+
using namespace std;
namespace WebCore {
@@ -51,6 +60,11 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_readyState(MediaPlayer::DataUnavailable)
, m_startedPlaying(false)
, m_isStreaming(false)
+#if DRAW_FRAME_RATE
+ , m_frameCountWhilePlaying(0)
+ , m_timeStartedPlaying(0)
+ , m_timeStoppedPlaying(0)
+#endif
{
}
@@ -88,6 +102,9 @@ void MediaPlayerPrivate::play()
if (!m_qtMovie)
return;
m_startedPlaying = true;
+#if DRAW_FRAME_RATE
+ m_frameCountWhilePlaying = 0;
+#endif
m_qtMovie->play();
startEndPointTimerIfNeeded();
@@ -98,6 +115,9 @@ void MediaPlayerPrivate::pause()
if (!m_qtMovie)
return;
m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = GetTickCount();
+#endif
m_qtMovie->pause();
m_endPointTimer.stop();
}
@@ -304,7 +324,7 @@ void MediaPlayerPrivate::updateStates()
long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;
- if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData) {
+ if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData && !m_player->inMediaDocument()) {
unsigned enabledTrackCount;
m_qtMovie->disableUnsupportedTracks(enabledTrackCount);
// FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>
@@ -352,6 +372,9 @@ void MediaPlayerPrivate::didEnd()
{
m_endPointTimer.stop();
m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = GetTickCount();
+#endif
updateStates();
m_player->timeChanged();
}
@@ -376,6 +399,31 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
HDC hdc = p->getWindowsContext(r);
m_qtMovie->paint(hdc, r.x(), r.y());
p->releaseWindowsContext(hdc, r);
+
+#if DRAW_FRAME_RATE
+ if (m_frameCountWhilePlaying > 10) {
+ Frame* frame = m_player->m_frameView ? m_player->m_frameView->frame() : NULL;
+ Document* document = frame ? frame->document() : NULL;
+ RenderObject* renderer = document ? document->renderer() : NULL;
+ RenderStyle* styleToUse = renderer ? renderer->style() : NULL;
+ if (styleToUse) {
+ double frameRate = (m_frameCountWhilePlaying - 1) / (0.001 * ( m_startedPlaying ? (GetTickCount() - m_timeStartedPlaying) :
+ (m_timeStoppedPlaying - m_timeStartedPlaying) ));
+ String text = String::format("%1.2f", frameRate);
+ TextRun textRun(text.characters(), text.length());
+ const Color color(255, 0, 0);
+ p->save();
+ p->translate(r.x(), r.y() + r.height());
+ p->setFont(styleToUse->font());
+ p->setStrokeColor(color);
+ p->setStrokeStyle(SolidStroke);
+ p->setStrokeThickness(1.0f);
+ p->setFillColor(color);
+ p->drawText(textRun, IntPoint(2, -3));
+ p->restore();
+ }
+ }
+#endif
}
void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
@@ -417,6 +465,15 @@ void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie)
void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie)
{
ASSERT(m_qtMovie.get() == movie);
+#if DRAW_FRAME_RATE
+ if (m_startedPlaying) {
+ m_frameCountWhilePlaying++;
+ // to eliminate preroll costs from our calculation,
+ // our frame rate calculation excludes the first frame drawn after playback starts
+ if (1==m_frameCountWhilePlaying)
+ m_timeStartedPlaying = GetTickCount();
+ }
+#endif
m_player->repaint();
}
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
index 37b5b05..c4c893c 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -33,6 +33,10 @@
#include <QTMovieWin.h>
#include <wtf/OwnPtr.h>
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
namespace WebCore {
class GraphicsContext;
@@ -111,6 +115,11 @@ private:
MediaPlayer::ReadyState m_readyState;
bool m_startedPlaying;
bool m_isStreaming;
+#if DRAW_FRAME_RATE
+ int m_frameCountWhilePlaying;
+ int m_timeStartedPlaying;
+ int m_timeStoppedPlaying;
+#endif
};
}
diff --git a/WebCore/platform/graphics/win/OpenTypeUtilities.cpp b/WebCore/platform/graphics/win/OpenTypeUtilities.cpp
new file mode 100644
index 0000000..1951320
--- /dev/null
+++ b/WebCore/platform/graphics/win/OpenTypeUtilities.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "OpenTypeUtilities.h"
+
+#include "SharedBuffer.h"
+
+namespace WebCore {
+
+struct BigEndianUShort {
+ operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; }
+ BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { }
+ unsigned short v;
+};
+
+struct BigEndianULong {
+ operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
+ BigEndianULong(unsigned u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24) { }
+ unsigned v;
+};
+
+#pragma pack(1)
+
+struct EOTPrefix {
+ unsigned eotSize;
+ unsigned fontDataSize;
+ unsigned version;
+ unsigned flags;
+ UInt8 fontPANOSE[10];
+ UInt8 charset;
+ UInt8 italic;
+ unsigned weight;
+ unsigned short fsType;
+ unsigned short magicNumber;
+ unsigned unicodeRange[4];
+ unsigned codePageRange[2];
+ unsigned checkSumAdjustment;
+ unsigned reserved[4];
+ unsigned short padding1;
+};
+
+struct TableDirectoryEntry {
+ BigEndianULong tag;
+ BigEndianULong checkSum;
+ BigEndianULong offset;
+ BigEndianULong length;
+};
+
+struct sfntHeader {
+ Fixed version;
+ BigEndianUShort numTables;
+ BigEndianUShort searchRange;
+ BigEndianUShort entrySelector;
+ BigEndianUShort rangeShift;
+ TableDirectoryEntry tables[1];
+};
+
+struct OS2Table {
+ BigEndianUShort version;
+ BigEndianUShort avgCharWidth;
+ BigEndianUShort weightClass;
+ BigEndianUShort widthClass;
+ BigEndianUShort fsType;
+ BigEndianUShort subscriptXSize;
+ BigEndianUShort subscriptYSize;
+ BigEndianUShort subscriptXOffset;
+ BigEndianUShort subscriptYOffset;
+ BigEndianUShort superscriptXSize;
+ BigEndianUShort superscriptYSize;
+ BigEndianUShort superscriptXOffset;
+ BigEndianUShort superscriptYOffset;
+ BigEndianUShort strikeoutSize;
+ BigEndianUShort strikeoutPosition;
+ BigEndianUShort familyClass;
+ UInt8 panose[10];
+ BigEndianULong unicodeRange[4];
+ UInt8 vendID[4];
+ BigEndianUShort fsSelection;
+ BigEndianUShort firstCharIndex;
+ BigEndianUShort lastCharIndex;
+ BigEndianUShort typoAscender;
+ BigEndianUShort typoDescender;
+ BigEndianUShort typoLineGap;
+ BigEndianUShort winAscent;
+ BigEndianUShort winDescent;
+ BigEndianULong codePageRange[2];
+ BigEndianUShort xHeight;
+ BigEndianUShort capHeight;
+ BigEndianUShort defaultChar;
+ BigEndianUShort breakChar;
+ BigEndianUShort maxContext;
+};
+
+struct headTable {
+ Fixed version;
+ Fixed fontRevision;
+ BigEndianULong checkSumAdjustment;
+ BigEndianULong magicNumber;
+ BigEndianUShort flags;
+ BigEndianUShort unitsPerEm;
+ long long created;
+ long long modified;
+ BigEndianUShort xMin;
+ BigEndianUShort xMax;
+ BigEndianUShort yMin;
+ BigEndianUShort yMax;
+ BigEndianUShort macStyle;
+ BigEndianUShort lowestRectPPEM;
+ BigEndianUShort fontDirectionHint;
+ BigEndianUShort indexToLocFormat;
+ BigEndianUShort glyphDataFormat;
+};
+
+struct nameRecord {
+ BigEndianUShort platformID;
+ BigEndianUShort encodingID;
+ BigEndianUShort languageID;
+ BigEndianUShort nameID;
+ BigEndianUShort length;
+ BigEndianUShort offset;
+};
+
+struct nameTable {
+ BigEndianUShort format;
+ BigEndianUShort count;
+ BigEndianUShort stringOffset;
+ nameRecord nameRecords[1];
+};
+
+#pragma pack()
+
+static void appendBigEndianStringToEOTHeader(Vector<UInt8, 512>& eotHeader, const BigEndianUShort* string, unsigned short length)
+{
+ size_t size = eotHeader.size();
+ eotHeader.resize(size + length + 2 * sizeof(unsigned short));
+ UChar* dst = reinterpret_cast<UChar*>(eotHeader.data() + size);
+ unsigned i = 0;
+ dst[i++] = length;
+ unsigned numCharacters = length / 2;
+ for (unsigned j = 0; j < numCharacters; j++)
+ dst[i++] = string[j];
+ dst[i] = 0;
+}
+
+bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
+{
+ overlayDst = 0;
+ overlaySrc = 0;
+ overlayLength = 0;
+
+ size_t dataLength = fontData->size();
+ const char* data = fontData->data();
+
+ eotHeader.resize(sizeof(EOTPrefix));
+ EOTPrefix* prefix = reinterpret_cast<EOTPrefix*>(eotHeader.data());
+
+ prefix->fontDataSize = dataLength;
+ prefix->version = 0x00020001;
+ prefix->flags = 0;
+
+ if (dataLength < offsetof(sfntHeader, tables))
+ return false;
+
+ const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(data);
+
+ if (dataLength < offsetof(sfntHeader, tables) + sfnt->numTables * sizeof(TableDirectoryEntry))
+ return false;
+
+ bool haveOS2 = false;
+ bool haveHead = false;
+ bool haveName = false;
+
+ const BigEndianUShort* familyName = 0;
+ unsigned short familyNameLength = 0;
+ const BigEndianUShort* subfamilyName = 0;
+ unsigned short subfamilyNameLength = 0;
+ const BigEndianUShort* fullName = 0;
+ unsigned short fullNameLength = 0;
+ const BigEndianUShort* versionString = 0;
+ unsigned short versionStringLength = 0;
+
+ for (unsigned i = 0; i < sfnt->numTables; i++) {
+ unsigned tableOffset = sfnt->tables[i].offset;
+ unsigned tableLength = sfnt->tables[i].length;
+
+ if (dataLength < tableOffset || dataLength < tableLength || dataLength < tableOffset + tableLength)
+ return false;
+
+ unsigned tableTag = sfnt->tables[i].tag;
+ switch (tableTag) {
+ case 'OS/2':
+ {
+ if (dataLength < tableOffset + sizeof(OS2Table))
+ return false;
+
+ haveOS2 = true;
+ const OS2Table* OS2 = reinterpret_cast<const OS2Table*>(data + tableOffset);
+ for (unsigned j = 0; j < 10; j++)
+ prefix->fontPANOSE[j] = OS2->panose[j];
+ prefix->italic = OS2->fsSelection & 0x01;
+ prefix->weight = OS2->weightClass;
+ // FIXME: Should use OS2->fsType, but some TrueType fonts set it to an over-restrictive value.
+ // Since ATS does not enforce this on Mac OS X, we do not enforce it either.
+ prefix->fsType = 0;
+ for (unsigned j = 0; j < 4; j++)
+ prefix->unicodeRange[j] = OS2->unicodeRange[j];
+ for (unsigned j = 0; j < 2; j++)
+ prefix->codePageRange[j] = OS2->codePageRange[j];
+ break;
+ }
+ case 'head':
+ {
+ if (dataLength < tableOffset + sizeof(headTable))
+ return false;
+
+ haveHead = true;
+ const headTable* head = reinterpret_cast<const headTable*>(data + tableOffset);
+ prefix->checkSumAdjustment = head->checkSumAdjustment;
+ break;
+ }
+ case 'name':
+ {
+ if (dataLength < tableOffset + offsetof(nameTable, nameRecords))
+ return false;
+
+ haveName = true;
+ const nameTable* name = reinterpret_cast<const nameTable*>(data + tableOffset);
+ for (int j = 0; j < name->count; j++) {
+ if (dataLength < tableOffset + offsetof(nameTable, nameRecords) + (j + 1) * sizeof(nameRecord))
+ return false;
+ if (name->nameRecords[j].platformID == 3 && name->nameRecords[j].encodingID == 1 && name->nameRecords[j].languageID == 0x0409) {
+ if (dataLength < tableOffset + name->stringOffset + name->nameRecords[j].offset + name->nameRecords[j].length)
+ return false;
+
+ unsigned short nameLength = name->nameRecords[j].length;
+ const BigEndianUShort* nameString = reinterpret_cast<const BigEndianUShort*>(data + tableOffset + name->stringOffset + name->nameRecords[j].offset);
+
+ switch (name->nameRecords[j].nameID) {
+ case 1:
+ familyNameLength = nameLength;
+ familyName = nameString;
+ break;
+ case 2:
+ subfamilyNameLength = nameLength;
+ subfamilyName = nameString;
+ break;
+ case 4:
+ fullNameLength = nameLength;
+ fullName = nameString;
+ break;
+ case 5:
+ versionStringLength = nameLength;
+ versionString = nameString;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (haveOS2 && haveHead && haveName)
+ break;
+ }
+
+ prefix->charset = DEFAULT_CHARSET;
+ prefix->magicNumber = 0x504c;
+ prefix->reserved[0] = 0;
+ prefix->reserved[1] = 0;
+ prefix->reserved[2] = 0;
+ prefix->reserved[3] = 0;
+ prefix->padding1 = 0;
+
+ appendBigEndianStringToEOTHeader(eotHeader, familyName, familyNameLength);
+ appendBigEndianStringToEOTHeader(eotHeader, subfamilyName, subfamilyNameLength);
+ appendBigEndianStringToEOTHeader(eotHeader, versionString, versionStringLength);
+
+ // If possible, ensure that the family name is a prefix of the full name.
+ if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) {
+ overlaySrc = reinterpret_cast<const char*>(fullName) - data;
+ overlayDst = reinterpret_cast<const char*>(familyName) - data;
+ overlayLength = familyNameLength;
+ }
+
+ appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength);
+
+ unsigned short padding = 0;
+ eotHeader.append(reinterpret_cast<UInt8*>(&padding), sizeof(padding));
+
+ prefix->eotSize = eotHeader.size() + fontData->size();
+
+ return true;
+}
+
+HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName)
+{
+ size_t originalDataSize = fontData->size();
+ const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(fontData->data());
+
+ unsigned t;
+ for (t = 0; t < sfnt->numTables; ++t) {
+ if (sfnt->tables[t].tag == 'name')
+ break;
+ }
+ if (t == sfnt->numTables)
+ return 0;
+
+ const int nameRecordCount = 5;
+
+ // Rounded up to a multiple of 4 to simplify the checksum calculation.
+ size_t nameTableSize = ((offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord) + fontName.length() * sizeof(UChar)) & ~3) + 4;
+
+ Vector<char> rewrittenFontData(fontData->size() + nameTableSize);
+ char* data = rewrittenFontData.data();
+ memcpy(data, fontData->data(), originalDataSize);
+
+ // Make the table directory entry point to the new 'name' table.
+ sfntHeader* rewrittenSfnt = reinterpret_cast<sfntHeader*>(data);
+ rewrittenSfnt->tables[t].length = nameTableSize;
+ rewrittenSfnt->tables[t].offset = originalDataSize;
+
+ // Write the new 'name' table after the original font data.
+ nameTable* name = reinterpret_cast<nameTable*>(data + originalDataSize);
+ name->format = 0;
+ name->count = nameRecordCount;
+ name->stringOffset = offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord);
+ for (unsigned i = 0; i < nameRecordCount; ++i) {
+ name->nameRecords[i].platformID = 3;
+ name->nameRecords[i].encodingID = 1;
+ name->nameRecords[i].languageID = 0x0409;
+ name->nameRecords[i].offset = 0;
+ name->nameRecords[i].length = fontName.length() * sizeof(UChar);
+ }
+
+ // The required 'name' record types: Family, Style, Unique, Full and PostScript.
+ name->nameRecords[0].nameID = 1;
+ name->nameRecords[1].nameID = 2;
+ name->nameRecords[2].nameID = 3;
+ name->nameRecords[3].nameID = 4;
+ name->nameRecords[4].nameID = 6;
+
+ for (unsigned i = 0; i < fontName.length(); ++i)
+ reinterpret_cast<BigEndianUShort*>(data + originalDataSize + name->stringOffset)[i] = fontName[i];
+
+ // Update the table checksum in the directory entry.
+ rewrittenSfnt->tables[t].checkSum = 0;
+ for (unsigned i = 0; i * sizeof(BigEndianULong) < nameTableSize; ++i)
+ rewrittenSfnt->tables[t].checkSum = rewrittenSfnt->tables[t].checkSum + reinterpret_cast<BigEndianULong*>(name)[i];
+
+ DWORD numFonts = 0;
+ HANDLE fontHandle = AddFontMemResourceEx(data, originalDataSize + nameTableSize, 0, &numFonts);
+
+ if (fontHandle && numFonts != 1) {
+ RemoveFontMemResourceEx(fontHandle);
+ return 0;
+ }
+
+ return fontHandle;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontCairoWin.cpp b/WebCore/platform/graphics/win/OpenTypeUtilities.h
index 302e79d..ab35551 100644
--- a/WebCore/platform/graphics/win/FontCairoWin.cpp
+++ b/WebCore/platform/graphics/win/OpenTypeUtilities.h
@@ -23,20 +23,19 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config.h"
-#include "Font.h"
+#ifndef OpenTypeUtilities_h
+#define OpenTypeUtilities_h
-#include "GlyphBuffer.h"
-#include "GraphicsContext.h"
-#include "NotImplemented.h"
-#include "SimpleFontData.h"
+#include "PlatformString.h"
+#include <wtf/Forward.h>
namespace WebCore {
-void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
- int from, int numGlyphs, const FloatPoint& point) const
-{
- notImplemented();
-}
+class SharedBuffer;
-}
+bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength);
+HANDLE renameAndActivateFont(SharedBuffer*, const String&);
+
+} // namespace WebCore
+
+#endif // OpenTypeUtilities_h
diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp
index 80c6d50..8eee41b 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -30,6 +30,7 @@
// Put Movies.h first so build failures here point clearly to QuickTime
#include <Movies.h>
+#include <QuickTimeComponents.h>
#include <GXMath.h>
#include <QTML.h>
@@ -59,6 +60,7 @@ union UppParam {
static MovieDrawingCompleteUPP gMovieDrawingCompleteUPP = 0;
static HashSet<QTMovieWinPrivate*>* gTaskList;
static Vector<CFStringRef>* gSupportedTypes = 0;
+static SInt32 quickTimeVersion = 0;
static void updateTaskTimer(int maxInterval = 1000)
{
@@ -82,16 +84,19 @@ public:
void startTask();
void endTask();
+ void createMovieController();
void registerDrawingCallback();
void drawingComplete();
void updateGWorld();
void createGWorld();
void deleteGWorld();
+ void clearGWorld();
void setSize(int, int);
QTMovieWin* m_movieWin;
Movie m_movie;
+ MovieController m_movieController;
bool m_tasking;
QTMovieWinClient* m_client;
long m_loadState;
@@ -112,6 +117,7 @@ public:
QTMovieWinPrivate::QTMovieWinPrivate()
: m_movieWin(0)
, m_movie(0)
+ , m_movieController(0)
, m_tasking(false)
, m_client(0)
, m_loadState(0)
@@ -135,6 +141,8 @@ QTMovieWinPrivate::~QTMovieWinPrivate()
endTask();
if (m_gWorld)
deleteGWorld();
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
if (m_movie)
DisposeMovie(m_movie);
}
@@ -175,8 +183,12 @@ void QTMovieWinPrivate::task()
{
ASSERT(m_tasking);
- if (!m_loadError)
- MoviesTask(m_movie, 0);
+ if (!m_loadError) {
+ if (m_movieController)
+ MCIdle(m_movieController);
+ else
+ MoviesTask(m_movie, 0);
+ }
// GetMovieLoadState documentation says that you should not call it more often than every quarter of a second.
if (systemTime() >= m_lastLoadStateCheckTime + 0.25 || m_loadError) {
@@ -184,7 +196,15 @@ void QTMovieWinPrivate::task()
// This is different from QTKit API and seems strange.
long loadState = m_loadError ? kMovieLoadStateError : GetMovieLoadState(m_movie);
if (loadState != m_loadState) {
+
+ // we only need to erase the movie gworld when the load state changes to loaded while it
+ // is visible as the gworld is destroyed/created when visibility changes
+ if (loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded && m_visible)
+ clearGWorld();
+
m_loadState = loadState;
+ if (!m_movieController && m_loadState >= kMovieLoadStateLoaded)
+ createMovieController();
m_client->movieLoadStateChanged(m_movieWin);
}
m_lastLoadStateCheckTime = systemTime();
@@ -209,6 +229,27 @@ void QTMovieWinPrivate::task()
endTask();
}
+void QTMovieWinPrivate::createMovieController()
+{
+ Rect bounds;
+ long flags;
+
+ if (!m_movie)
+ return;
+
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
+
+ GetMovieBox(m_movie, &bounds);
+ flags = mcTopLeftMovie | mcNotVisible;
+ m_movieController = NewMovieController(m_movie, &bounds, flags);
+ if (!m_movieController)
+ return;
+
+ MCSetControllerPort(m_movieController, m_gWorld);
+ MCSetControllerAttached(m_movieController, false);
+}
+
void QTMovieWinPrivate::registerDrawingCallback()
{
UppParam param;
@@ -218,7 +259,7 @@ void QTMovieWinPrivate::registerDrawingCallback()
void QTMovieWinPrivate::drawingComplete()
{
- if (!m_gWorld)
+ if (!m_gWorld || m_loadState < kMovieLoadStateLoaded)
return;
m_client->movieNewImageAvailable(m_movieWin);
}
@@ -257,12 +298,36 @@ void QTMovieWinPrivate::createGWorld()
if (err)
return;
GetMovieGWorld(m_movie, &m_savedGWorld, 0);
+ if (m_movieController)
+ MCSetControllerPort(m_movieController, m_gWorld);
SetMovieGWorld(m_movie, m_gWorld, 0);
bounds.right = m_width;
bounds.bottom = m_height;
+ if (m_movieController)
+ MCSetControllerBoundsRect(m_movieController, &bounds);
SetMovieBox(m_movie, &bounds);
}
+void QTMovieWinPrivate::clearGWorld()
+{
+ if (!m_movie||!m_gWorld)
+ return;
+
+ GrafPtr savePort;
+ GetPort(&savePort);
+ MacSetPort((GrafPtr)m_gWorld);
+
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = m_gWorldWidth;
+ bounds.bottom = m_gWorldHeight;
+ EraseRect(&bounds);
+
+ MacSetPort(savePort);
+}
+
+
void QTMovieWinPrivate::setSize(int width, int height)
{
if (m_width == width && m_height == height)
@@ -276,6 +341,8 @@ void QTMovieWinPrivate::setSize(int width, int height)
bounds.left = 0;
bounds.right = width;
bounds.bottom = height;
+ if (m_movieController)
+ MCSetControllerBoundsRect(m_movieController, &bounds);
SetMovieBox(m_movie, &bounds);
updateGWorld();
}
@@ -283,6 +350,8 @@ void QTMovieWinPrivate::setSize(int width, int height)
void QTMovieWinPrivate::deleteGWorld()
{
ASSERT(m_gWorld);
+ if (m_movieController)
+ MCSetControllerPort(m_movieController, m_savedGWorld);
if (m_movie)
SetMovieGWorld(m_movie, m_savedGWorld, 0);
m_savedGWorld = 0;
@@ -308,24 +377,37 @@ QTMovieWin::~QTMovieWin()
void QTMovieWin::play()
{
- StartMovie(m_private->m_movie);
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)GetMoviePreferredRate(m_private->m_movie));
+ else
+ StartMovie(m_private->m_movie);
m_private->startTask();
}
void QTMovieWin::pause()
{
- StopMovie(m_private->m_movie);
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPlay, 0);
+ else
+ StopMovie(m_private->m_movie);
updateTaskTimer();
}
float QTMovieWin::rate() const
{
+ if (!m_private->m_movie)
+ return 0;
return FixedToFloat(GetMovieRate(m_private->m_movie));
}
void QTMovieWin::setRate(float rate)
{
- SetMovieRate(m_private->m_movie, FloatToFixed(rate));
+ if (!m_private->m_movie)
+ return;
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)FloatToFixed(rate));
+ else
+ SetMovieRate(m_private->m_movie, FloatToFixed(rate));
updateTaskTimer();
}
@@ -353,19 +435,26 @@ void QTMovieWin::setCurrentTime(float time) const
return;
m_private->m_seeking = true;
TimeScale scale = GetMovieTimeScale(m_private->m_movie);
- SetMovieTimeValue(m_private->m_movie, TimeValue(time * scale));
+ if (m_private->m_movieController){
+ QTRestartAtTimeRecord restart = { time * scale , 0 };
+ MCDoAction(m_private->m_movieController, mcActionRestartAtTime, (void *)&restart);
+ } else
+ SetMovieTimeValue(m_private->m_movie, TimeValue(time * scale));
updateTaskTimer();
}
void QTMovieWin::setVolume(float volume)
{
+ if (!m_private->m_movie)
+ return;
SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256));
}
unsigned QTMovieWin::dataSize() const
{
- // FIXME: How to get this?
- return 1000;
+ if (!m_private->m_movie)
+ return 0;
+ return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie));
}
float QTMovieWin::maxTimeLoaded() const
@@ -385,8 +474,10 @@ long QTMovieWin::loadState() const
void QTMovieWin::getNaturalSize(int& width, int& height)
{
- Rect rect;
- GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
+ Rect rect = { 0, };
+
+ if (m_private->m_movie)
+ GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
width = rect.right;
height = rect.bottom;
}
@@ -428,6 +519,9 @@ void QTMovieWin::load(const UChar* url, int len)
m_private->endTask();
if (m_private->m_gWorld)
m_private->deleteGWorld();
+ if (m_private->m_movieController)
+ DisposeMovieController(m_private->m_movieController);
+ m_private->m_movieController = 0;
DisposeMovie(m_private->m_movie);
m_private->m_movie = 0;
}
@@ -630,18 +724,89 @@ static void initializeSupportedTypes()
{
if (gSupportedTypes)
return;
- // FIXME: This list might not be complete.
- // There must be some way to get it out from QuickTime.
+
gSupportedTypes = new Vector<CFStringRef>;
- gSupportedTypes->append(CFSTR("video/3gpp"));
- gSupportedTypes->append(CFSTR("video/3gpp2"));
- gSupportedTypes->append(CFSTR("video/mp4"));
- gSupportedTypes->append(CFSTR("video/mpeg"));
+ if (quickTimeVersion < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Returning empty list of supported media MIME types.", quickTimeVersion, minimumQuickTimeVersion);
+ return;
+ }
+
+ // QuickTime doesn't have an importer for video/quicktime. Add it manually.
gSupportedTypes->append(CFSTR("video/quicktime"));
- gSupportedTypes->append(CFSTR("audio/ac3"));
- gSupportedTypes->append(CFSTR("audio/aiff"));
- gSupportedTypes->append(CFSTR("audio/basic"));
- gSupportedTypes->append(CFSTR("audio/mpeg"));
+
+ for (int index = 0; index < 2; index++) {
+ ComponentDescription findCD;
+
+ // look at all movie importers that can import in place and are installed.
+ findCD.componentType = MovieImportType;
+ findCD.componentSubType = 0;
+ findCD.componentManufacturer = 0;
+ findCD.componentFlagsMask = cmpIsMissing | movieImportSubTypeIsFileExtension | canMovieImportInPlace | dontAutoFileMovieImport;
+
+ // look at those registered by HFS file types the first time through, by file extension the second time
+ findCD.componentFlags = canMovieImportInPlace | (index ? movieImportSubTypeIsFileExtension : 0);
+
+ long componentCount = CountComponents(&findCD);
+ if (!componentCount)
+ continue;
+
+ Component comp = 0;
+ while (comp = FindNextComponent(comp, &findCD)) {
+ // Does this component have a MIME type container?
+ ComponentDescription infoCD;
+ OSErr err = GetComponentInfo(comp, &infoCD, nil /*name*/, nil /*info*/, nil /*icon*/);
+ if (err)
+ continue;
+ if (!(infoCD.componentFlags & hasMovieImportMIMEList))
+ continue;
+ QTAtomContainer mimeList = NULL;
+ err = MovieImportGetMIMETypeList((ComponentInstance)comp, &mimeList);
+ if (err || !mimeList)
+ continue;
+
+ // Grab every type from the container.
+ QTLockContainer(mimeList);
+ int typeCount = QTCountChildrenOfType(mimeList, kParentAtomIsContainer, kMimeInfoMimeTypeTag);
+ for (int typeIndex = 1; typeIndex <= typeCount; typeIndex++) {
+ QTAtom mimeTag = QTFindChildByIndex(mimeList, 0, kMimeInfoMimeTypeTag, typeIndex, NULL);
+ if (!mimeTag)
+ continue;
+ char* atomData;
+ long typeLength;
+ if (noErr != QTGetAtomDataPtr(mimeList, mimeTag, &typeLength, &atomData))
+ continue;
+
+ char typeBuffer[256];
+ if (typeLength >= sizeof(typeBuffer))
+ continue;
+ memcpy(typeBuffer, atomData, typeLength);
+ typeBuffer[typeLength] = 0;
+
+ // Only add "audio/..." and "video/..." types.
+ if (strncmp(typeBuffer, "audio/", 6) && strncmp(typeBuffer, "video/", 6))
+ continue;
+
+ CFStringRef cfMimeType = CFStringCreateWithCString(NULL, typeBuffer, kCFStringEncodingUTF8);
+ if (!cfMimeType)
+ continue;
+
+ // Only add each type once.
+ bool alreadyAdded = false;
+ for (int addedIndex = 0; addedIndex < gSupportedTypes->size(); addedIndex++) {
+ CFStringRef type = gSupportedTypes->at(addedIndex);
+ if (kCFCompareEqualTo == CFStringCompare(cfMimeType, type, kCFCompareCaseInsensitive)) {
+ alreadyAdded = true;
+ break;
+ }
+ }
+ if (!alreadyAdded)
+ gSupportedTypes->append(cfMimeType);
+ else
+ CFRelease(cfMimeType);
+ }
+ DisposeHandle(mimeList);
+ }
+ }
}
unsigned QTMovieWin::countSupportedTypes()
@@ -676,15 +841,14 @@ bool QTMovieWin::initializeQuickTime()
initialized = true;
// Initialize and check QuickTime version
OSErr result = InitializeQTML(0);
- SInt32 version = 0;
if (result == noErr)
- result = Gestalt(gestaltQuickTime, &version);
+ result = Gestalt(gestaltQuickTime, &quickTimeVersion);
if (result != noErr) {
LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support.");
return false;
}
- if (version < minimumQuickTimeVersion) {
- LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", version, minimumQuickTimeVersion);
+ if (quickTimeVersion < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", quickTimeVersion, minimumQuickTimeVersion);
return false;
}
EnterMovies();
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
index 0c31672..8b5ab87 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
@@ -34,7 +34,9 @@
#include "FontCache.h"
#include "FloatRect.h"
#include "FontDescription.h"
+#include "PlatformString.h"
#include <wtf/MathExtras.h>
+#include <wtf/RetainPtr.h>
#include <unicode/uchar.h>
#include <unicode/unorm.h>
#include <ApplicationServices/ApplicationServices.h>
@@ -54,32 +56,9 @@ void SimpleFontData::platformInit()
m_scriptCache = 0;
m_scriptFontProperties = 0;
m_isSystemFont = false;
-
- if (m_font.useGDI()) {
- HDC hdc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
- OUTLINETEXTMETRIC metrics;
- GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
- TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
- m_ascent = textMetrics.tmAscent;
- m_descent = textMetrics.tmDescent;
- m_lineGap = textMetrics.tmExternalLeading;
- m_lineSpacing = m_ascent + m_descent + m_lineGap;
- m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
-
- GLYPHMETRICS gm;
- MAT2 mat = { 1, 0, 0, 1 };
- DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
- if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
- m_xHeight = gm.gmptGlyphOrigin.y;
-
- m_unitsPerEm = metrics.otmEMSquare;
-
- SelectObject(hdc, oldFont);
- ReleaseDC(0, hdc);
-
- return;
- }
+
+ if (m_font.useGDI())
+ return initGDIFont();
CGFontRef font = m_font.cgFont();
int iAscent = CGFontGetAscent(font);
@@ -139,29 +118,13 @@ void SimpleFontData::platformInit()
void SimpleFontData::platformDestroy()
{
- if (!isCustomFont()) {
- DeleteObject(m_font.hfont());
- CGFontRelease(m_font.cgFont());
- }
-
- // We don't hash this on Win32, so it's effectively owned by us.
- delete m_smallCapsFontData;
-
- ScriptFreeCache(&m_scriptCache);
- delete m_scriptFontProperties;
+ platformCommonDestroy();
}
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
- if (m_font.useGDI()) {
- HDC hdc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
- int width;
- GetCharWidthI(hdc, glyph, 1, 0, &width);
- SelectObject(hdc, oldFont);
- ReleaseDC(0, hdc);
- return width;
- }
+ if (m_font.useGDI())
+ return widthForGDIGlyph(glyph);
CGFontRef font = m_font.cgFont();
float pointSize = m_font.size();
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
index e7b2c81..07d5305 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -34,7 +34,10 @@
#include "Font.h"
#include "FontCache.h"
#include "FontDescription.h"
+#include "MathExtras.h"
#include "NotImplemented.h"
+#include <cairo.h>
+#include <cairo-win32.h>
#include <mlang.h>
#include <tchar.h>
@@ -45,58 +48,84 @@ void SimpleFontData::platformInit()
m_scriptCache = 0;
m_scriptFontProperties = 0;
m_isSystemFont = false;
-
- if (m_font.useGDI()) {
- HDC hdc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
- OUTLINETEXTMETRIC metrics;
- GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
- TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
- m_ascent = textMetrics.tmAscent;
- m_descent = textMetrics.tmDescent;
- m_lineGap = textMetrics.tmExternalLeading;
- m_lineSpacing = m_ascent + m_descent + m_lineGap;
- m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
+ m_syntheticBoldOffset = 0;
+ if (m_font.useGDI())
+ return initGDIFont();
+
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ cairo_scaled_font_t* scaledFont = m_font.scaledFont();
+ const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size();
+
+ cairo_win32_scaled_font_select_font(scaledFont, hdc);
+
+ TEXTMETRIC textMetrics;
+ GetTextMetrics(hdc, &textMetrics);
+ m_ascent = lroundf(textMetrics.tmAscent * metricsMultiplier);
+ m_descent = lroundf(textMetrics.tmDescent * metricsMultiplier);
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts.
+ m_lineGap = lroundf(textMetrics.tmExternalLeading * metricsMultiplier);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ OUTLINETEXTMETRIC metrics;
+ if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) {
+ // This is a TrueType font. We might be able to get an accurate xHeight
GLYPHMETRICS gm;
MAT2 mat = { 1, 0, 0, 1 };
DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
- m_xHeight = gm.gmptGlyphOrigin.y;
-
- m_unitsPerEm = metrics.otmEMSquare;
+ m_xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier;
+ }
- SelectObject(hdc, oldFont);
- ReleaseDC(0, hdc);
+ cairo_win32_scaled_font_done_font(scaledFont);
- return;
- }
+ m_isSystemFont = false;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
- // FIXME: This section should determine font dimensions (see CG implementation).
- notImplemented();
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
}
void SimpleFontData::platformDestroy()
{
- notImplemented();
+ cairo_font_face_destroy(m_font.fontFace());
+ cairo_scaled_font_destroy(m_font.scaledFont());
+
+ DeleteObject(m_font.hfont());
+
+ platformCommonDestroy();
}
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
- if (m_font.useGDI()) {
- HDC hdc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
- int width;
- GetCharWidthI(hdc, glyph, 1, 0, &width);
- SelectObject(hdc, oldFont);
- ReleaseDC(0, hdc);
- return width;
- }
+ if (m_font.useGDI())
+ return widthForGDIGlyph(glyph);
+
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ cairo_scaled_font_t* scaledFont = m_font.scaledFont();
+ cairo_win32_scaled_font_select_font(scaledFont, hdc);
- // FIXME: Flesh out with Cairo/win32 font implementation
- notImplemented();
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
- return 0;
+ cairo_win32_scaled_font_done_font(scaledFont);
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+
+ const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size();
+ return width * metricsMultiplier;
+}
+
+void SimpleFontData::setFont(cairo_t* cr) const
+{
+ ASSERT(cr);
+ m_font.setFont(cr);
}
}
diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
index 344d964..0e9f9fb 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -60,6 +60,42 @@ bool SimpleFontData::shouldApplyMacAscentHack()
return g_shouldApplyMacAscentHack;
}
+void SimpleFontData::initGDIFont()
+{
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+ OUTLINETEXTMETRIC metrics;
+ GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
+ TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
+ m_ascent = textMetrics.tmAscent;
+ m_descent = textMetrics.tmDescent;
+ m_lineGap = textMetrics.tmExternalLeading;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
+
+ GLYPHMETRICS gm;
+ MAT2 mat = { 1, 0, 0, 1 };
+ DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
+ if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
+ m_xHeight = gm.gmptGlyphOrigin.y;
+
+ m_unitsPerEm = metrics.otmEMSquare;
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return;
+}
+
+void SimpleFontData::platformCommonDestroy()
+{
+ // We don't hash this on Win32, so it's effectively owned by us.
+ delete m_smallCapsFontData;
+
+ ScriptFreeCache(&m_scriptCache);
+ delete m_scriptFontProperties;
+}
+
SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
{
if (!m_smallCapsFontData) {
@@ -73,7 +109,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes
GetObject(m_font.hfont(), sizeof(LOGFONT), &winfont);
winfont.lfHeight = -lroundf(smallCapsHeight * (m_font.useGDI() ? 1 : 32));
HFONT hfont = CreateFontIndirect(&winfont);
- m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, fontDescription.bold(), fontDescription.italic(), m_font.useGDI()));
+ m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, m_font.syntheticBold(), m_font.syntheticOblique(), m_font.useGDI()));
}
}
return m_smallCapsFontData;
@@ -137,6 +173,17 @@ void SimpleFontData::determinePitch()
ReleaseDC(0, dc);
}
+float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
+{
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ return width + m_syntheticBoldOffset;
+}
+
SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const
{
if (!m_scriptFontProperties) {
diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp
index 876ff43..371bc51 100644
--- a/WebCore/platform/graphics/win/UniscribeController.cpp
+++ b/WebCore/platform/graphics/win/UniscribeController.cpp
@@ -299,7 +299,9 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S
offsetX = roundf(offsetX);
offsetY = roundf(offsetY);
}
-
+
+ advance += fontData->m_syntheticBoldOffset;
+
// We special case spaces in two ways when applying word rounding.
// First, we round spaces to an adjusted width in all fonts.
// Second, in fixed-pitch fonts we ensure that all glyphs that
@@ -361,7 +363,7 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S
// as well, so that when the time comes to draw those glyphs, we can apply the appropriate
// translation.
if (glyphBuffer) {
- FloatSize size(offsetX, offsetY);
+ FloatSize size(offsetX, -offsetY);
glyphBuffer->add(glyph, fontData, advance, &size);
}
@@ -422,25 +424,9 @@ bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, con
if (FAILED(shapeResult))
return false;
-
- // FIXME: We need to do better than this. Falling back on the entire item is not good enough.
- // We may still have missing glyphs even if we succeeded. We need to treat missing glyphs as
- // a failure so that we will fall back to another font.
- bool containsMissingGlyphs = false;
- SCRIPT_FONTPROPERTIES* fontProperties = fontData->scriptFontProperties();
- for (int i = 0; i < glyphCount; i++) {
- WORD glyph = glyphs[i];
- if (glyph == fontProperties->wgDefault) {
- containsMissingGlyphs = true;
- break;
- }
- }
-
- if (containsMissingGlyphs)
- return false;
- glyphs.resize(glyphCount);
- visualAttributes.resize(glyphCount);
+ glyphs.shrink(glyphCount);
+ visualAttributes.shrink(glyphCount);
return true;
}