summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/win
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/win')
-rw-r--r--WebCore/platform/graphics/win/ColorSafari.cpp71
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp361
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp525
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.cpp235
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.h56
-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/FontDatabase.cpp150
-rw-r--r--WebCore/platform/graphics/win/FontDatabase.h38
-rw-r--r--WebCore/platform/graphics/win/FontPlatformData.h147
-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.cpp92
-rw-r--r--WebCore/platform/graphics/win/FontWin.cpp101
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp59
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp72
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp366
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp124
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp126
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp84
-rw-r--r--WebCore/platform/graphics/win/ImageCGWin.cpp85
-rw-r--r--WebCore/platform/graphics/win/ImageCairoWin.cpp89
-rw-r--r--WebCore/platform/graphics/win/ImageWin.cpp58
-rw-r--r--WebCore/platform/graphics/win/IntPointWin.cpp56
-rw-r--r--WebCore/platform/graphics/win/IntRectWin.cpp43
-rw-r--r--WebCore/platform/graphics/win/IntSizeWin.cpp44
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp483
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h128
-rw-r--r--WebCore/platform/graphics/win/OpenTypeUtilities.cpp387
-rw-r--r--WebCore/platform/graphics/win/OpenTypeUtilities.h41
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.cpp875
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.h97
-rw-r--r--WebCore/platform/graphics/win/QTMovieWinTimer.cpp141
-rw-r--r--WebCore/platform/graphics/win/QTMovieWinTimer.h39
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp141
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp131
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataWin.cpp206
-rw-r--r--WebCore/platform/graphics/win/UniscribeController.cpp434
-rw-r--r--WebCore/platform/graphics/win/UniscribeController.h82
39 files changed, 6500 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/win/ColorSafari.cpp b/WebCore/platform/graphics/win/ColorSafari.cpp
new file mode 100644
index 0000000..a04fd81
--- /dev/null
+++ b/WebCore/platform/graphics/win/ColorSafari.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 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 "Color.h"
+
+#include "NotImplemented.h"
+#include <CoreGraphics/CGColor.h>
+#include <SafariTheme/SafariTheme.h>
+#include <wtf/Assertions.h>
+#include <wtf/RetainPtr.h>
+
+using namespace SafariTheme;
+
+namespace WebCore {
+
+typedef CGColorRef (APIENTRY*stCopyThemeColorPtr)(unsigned, SafariTheme::ThemeControlState);
+static const unsigned stFocusRingColorID = 4;
+
+static const unsigned aquaFocusRingColor = 0xFF7DADD9;
+
+static RGBA32 makeRGBAFromCGColor(CGColorRef c)
+{
+ const CGFloat* components = CGColorGetComponents(c);
+ return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]);
+}
+
+Color focusRingColor()
+{
+ static Color focusRingColor;
+ focusRingColor.isValid();
+
+ if (!focusRingColor.isValid()) {
+ if (HMODULE module = LoadLibrary(SAFARITHEMEDLL))
+ if (stCopyThemeColorPtr stCopyThemeColor = (stCopyThemeColorPtr)GetProcAddress(module, "STCopyThemeColor")) {
+ RetainPtr<CGColorRef> c(AdoptCF, stCopyThemeColor(stFocusRingColorID, SafariTheme::ActiveState));
+ focusRingColor = makeRGBAFromCGColor(c.get());
+ }
+ if (!focusRingColor.isValid())
+ focusRingColor = aquaFocusRingColor;
+ }
+
+ return focusRingColor;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
new file mode 100644
index 0000000..1766cd9
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -0,0 +1,361 @@
+/*
+ * 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.
+ *
+ * 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 "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>
+
+namespace WebCore {
+
+const int syntheticObliqueAngle = 14;
+
+static inline CGFloat toCGFloat(FIXED f)
+{
+ 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;
+
+ 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();
+ 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();
+
+ 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);
+
+ // 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.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);
+ }
+ }
+ 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);
+}
+
+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, WebCoreShouldUseFontSmoothing());
+
+ const FontPlatformData& platformData = font->platformData();
+
+ CGContextSetFont(cgContext, platformData.cgFont());
+
+ CGAffineTransform matrix = CGAffineTransformIdentity;
+ matrix.b = -matrix.b;
+ matrix.d = -matrix.d;
+
+ if (platformData.syntheticOblique()) {
+ 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);
+
+ CGContextSetFontSize(cgContext, platformData.size());
+ 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() + 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
new file mode 100644
index 0000000..49b3d76
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -0,0 +1,525 @@
+/*
+ * 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 <winsock2.h>
+#include "FontCache.h"
+#include "Font.h"
+#include "SimpleFontData.h"
+#include "StringHash.h"
+#include "UnicodeRange.h"
+#include <windows.h>
+#include <mlang.h>
+#if PLATFORM(CG)
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+using std::min;
+
+namespace WebCore
+{
+
+void FontCache::platformInit()
+{
+#if PLATFORM(CG)
+ wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac.
+#endif
+}
+
+IMLangFontLink2* FontCache::getFontLinkInterface()
+{
+ static IMultiLanguage *multiLanguage;
+ if (!multiLanguage) {
+ if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, (void**)&multiLanguage) != S_OK)
+ return 0;
+ }
+
+ static IMLangFontLink2* langFontLink;
+ if (!langFontLink) {
+ if (multiLanguage->QueryInterface(&langFontLink) != S_OK)
+ return 0;
+ }
+
+ return langFontLink;
+}
+
+static int CALLBACK metaFileEnumProc(HDC hdc, HANDLETABLE* table, CONST ENHMETARECORD* record, int tableEntries, LPARAM logFont)
+{
+ if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
+ const EMREXTCREATEFONTINDIRECTW* createFontRecord = reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
+ *reinterpret_cast<LOGFONT*>(logFont) = createFontRecord->elfw.elfLogFont;
+ }
+ return true;
+}
+
+static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM hfont)
+{
+ *reinterpret_cast<HFONT*>(hfont) = CreateFontIndirect(logFont);
+ return false;
+}
+
+static const Vector<String>* getLinkedFonts(String& family)
+{
+ static HashMap<String, Vector<String>*> systemLinkMap;
+ Vector<String>* result = systemLinkMap.get(family);
+ if (result)
+ return result;
+
+ result = new Vector<String>;
+ systemLinkMap.set(family, result);
+ HKEY fontLinkKey;
+ if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", 0, KEY_READ, &fontLinkKey)))
+ return result;
+
+ DWORD linkedFontsBufferSize = 0;
+ RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, NULL, &linkedFontsBufferSize);
+ WCHAR* linkedFonts = reinterpret_cast<WCHAR*>(malloc(linkedFontsBufferSize));
+ if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, reinterpret_cast<BYTE*>(linkedFonts), &linkedFontsBufferSize))) {
+ unsigned i = 0;
+ unsigned length = linkedFontsBufferSize / sizeof(*linkedFonts);
+ while (i < length) {
+ while (i < length && linkedFonts[i] != ',')
+ i++;
+ i++;
+ unsigned j = i;
+ while (j < length && linkedFonts[j])
+ j++;
+ result->append(String(linkedFonts + i, j - i));
+ i = j + 1;
+ }
+ }
+ free(linkedFonts);
+ RegCloseKey(fontLinkKey);
+ return result;
+}
+
+static const Vector<DWORD, 4>& getCJKCodePageMasks()
+{
+ // The default order in which we look for a font for a CJK character. If the user's default code page is
+ // one of these, we will use it first.
+ static const UINT CJKCodePages[] = {
+ 932, /* Japanese */
+ 936, /* Simplified Chinese */
+ 950, /* Traditional Chinese */
+ 949 /* Korean */
+ };
+
+ static Vector<DWORD, 4> codePageMasks;
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+ IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface();
+ if (!langFontLink)
+ return codePageMasks;
+
+ UINT defaultCodePage;
+ DWORD defaultCodePageMask = 0;
+ if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage)))
+ langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask);
+
+ if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3])
+ codePageMasks.append(defaultCodePageMask);
+ for (unsigned i = 0; i < 4; ++i) {
+ if (defaultCodePage != CJKCodePages[i]) {
+ DWORD codePageMask;
+ langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
+ codePageMasks.append(codePageMask);
+ }
+ }
+ }
+ return codePageMasks;
+}
+
+static bool currentFontContainsCharacter(HDC hdc, UChar character)
+{
+ static Vector<char, 512> glyphsetBuffer;
+ glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0));
+ GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data());
+ GetFontUnicodeRanges(hdc, glyphset);
+
+ // FIXME: Change this to a binary search.
+ unsigned i = 0;
+ while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= character)
+ i++;
+
+ return i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs > character;
+}
+
+static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
+{
+ HFONT MLangFont;
+ HFONT hfont = 0;
+ if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &MLangFont)) && MLangFont) {
+ LOGFONT lf;
+ GetObject(MLangFont, sizeof(LOGFONT), &lf);
+ langFontLink->ReleaseFont(MLangFont);
+ hfont = CreateFontIndirect(&lf);
+ }
+ return hfont;
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ UChar character = characters[0];
+ SimpleFontData* fontData = 0;
+ HDC hdc = GetDC(0);
+ HFONT primaryFont = font.primaryFont()->fontDataForCharacter(character)->platformData().hfont();
+ HGDIOBJ oldFont = SelectObject(hdc, primaryFont);
+ HFONT hfont = 0;
+
+ if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
+ // Try MLang font linking first.
+ DWORD codePages = 0;
+ langFontLink->GetCharCodePages(character, &codePages);
+
+ if (codePages && findCharUnicodeRange(character) == cRangeSetCJK) {
+ // The CJK character may belong to multiple code pages. We want to
+ // do font linking against a single one of them, preferring the default
+ // code page for the user's locale.
+ const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
+ unsigned numCodePages = CJKCodePageMasks.size();
+ for (unsigned i = 0; i < numCodePages && !hfont; ++i) {
+ hfont = createMLangFont(langFontLink, hdc, CJKCodePageMasks[i]);
+ if (hfont && !(codePages & CJKCodePageMasks[i])) {
+ // We asked about a code page that is not one of the code pages
+ // returned by MLang, so the font might not contain the character.
+ SelectObject(hdc, hfont);
+ if (!currentFontContainsCharacter(hdc, character)) {
+ DeleteObject(hfont);
+ hfont = 0;
+ }
+ SelectObject(hdc, primaryFont);
+ }
+ }
+ } else
+ hfont = createMLangFont(langFontLink, hdc, codePages, character);
+ }
+
+ // A font returned from MLang is trusted to contain the character.
+ bool containsCharacter = hfont;
+
+ if (!hfont) {
+ // To find out what font Uniscribe would use, we make it draw into a metafile and intercept
+ // calls to CreateFontIndirect().
+ HDC metaFileDc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
+ SelectObject(metaFileDc, primaryFont);
+
+ bool scriptStringOutSucceeded = false;
+ SCRIPT_STRING_ANALYSIS ssa;
+
+ // FIXME: If length is greater than 1, we actually return the font for the last character.
+ // This function should be renamed getFontDataForCharacter and take a single 32-bit character.
+ if (SUCCEEDED(ScriptStringAnalyse(metaFileDc, characters, length, 0, -1, SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
+ 0, NULL, NULL, NULL, NULL, NULL, &ssa))) {
+ scriptStringOutSucceeded = SUCCEEDED(ScriptStringOut(ssa, 0, 0, 0, NULL, 0, 0, FALSE));
+ ScriptStringFree(&ssa);
+ }
+ HENHMETAFILE metaFile = CloseEnhMetaFile(metaFileDc);
+ if (scriptStringOutSucceeded) {
+ LOGFONT logFont;
+ logFont.lfFaceName[0] = 0;
+ EnumEnhMetaFile(0, metaFile, metaFileEnumProc, &logFont, NULL);
+ if (logFont.lfFaceName[0])
+ hfont = CreateFontIndirect(&logFont);
+ }
+ DeleteEnhMetaFile(metaFile);
+ }
+
+ String familyName;
+ const Vector<String>* linkedFonts = 0;
+ unsigned linkedFontIndex = 0;
+ while (hfont) {
+ SelectObject(hdc, hfont);
+ WCHAR name[LF_FACESIZE];
+ GetTextFace(hdc, LF_FACESIZE, name);
+ familyName = name;
+
+ if (containsCharacter || currentFontContainsCharacter(hdc, character))
+ break;
+
+ if (!linkedFonts)
+ linkedFonts = getLinkedFonts(familyName);
+ SelectObject(hdc, oldFont);
+ DeleteObject(hfont);
+ hfont = 0;
+
+ if (linkedFonts->size() <= linkedFontIndex)
+ break;
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ memcpy(logFont.lfFaceName, linkedFonts->at(linkedFontIndex).characters(), linkedFonts->at(linkedFontIndex).length() * sizeof(WCHAR));
+ logFont.lfFaceName[linkedFonts->at(linkedFontIndex).length()] = 0;
+ EnumFontFamiliesEx(hdc, &logFont, linkedFontEnumProc, reinterpret_cast<LPARAM>(&hfont), 0);
+ linkedFontIndex++;
+ }
+
+ if (hfont) {
+ if (!familyName.isEmpty()) {
+ FontPlatformData* result = getCachedFontPlatformData(font.fontDescription(), familyName);
+ if (result)
+ fontData = getCachedFontData(result);
+ }
+
+ SelectObject(hdc, oldFont);
+ DeleteObject(hfont);
+ }
+
+ ReleaseDC(0, hdc);
+ return fontData;
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick
+ // the default that the user would get without changing any prefs.
+ static AtomicString timesStr("Times New Roman");
+ return getCachedFontPlatformData(fontDescription, timesStr);
+}
+
+static LONG toGDIFontWeight(FontWeight fontWeight)
+{
+ 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
+ matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS;
+#endif
+ 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)
+{
+ bool isLucidaGrande = false;
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr))
+ isLucidaGrande = true;
+
+ bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande;
+
+ // 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;
+
+ 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.
+ delete result;
+ DeleteObject(hfont);
+ return 0;
+ }
+
+ return result;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..26fceba
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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
+ * 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 "FontCustomPlatformData.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, FontRenderingMode renderingMode)
+{
+ 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)
+{
+ SharedBuffer* buffer = static_cast<SharedBuffer*>(info);
+ buffer->ref();
+ return (void*)buffer->data();
+}
+
+void releaseData(void* info, const void* data)
+{
+ static_cast<SharedBuffer*>(info)->deref();
+}
+
+size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count)
+{
+ SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
+ size_t availBytes = count;
+ if (offset + count > sharedBuffer->size())
+ availBytes -= (offset + count) - sharedBuffer->size();
+ memcpy(buffer, sharedBuffer->data() + offset, availBytes);
+ 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 };
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirectAccess(buffer, buffer->size(), &callbacks));
+ CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider.get());
+ if (!cgFont)
+ return 0;
+
+ // 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
new file mode 100644
index 0000000..34a9851
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.h
@@ -0,0 +1,56 @@
+/*
+ * 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
+ * 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 FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
+#include <wtf/Noncopyable.h>
+
+typedef struct CGFont* CGFontRef;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ 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, FontRenderingMode = NormalRenderingMode);
+
+ CGFontRef m_cgFont;
+ HANDLE m_fontReference;
+ String m_name;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
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/FontDatabase.cpp b/WebCore/platform/graphics/win/FontDatabase.cpp
new file mode 100644
index 0000000..1308ff0
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontDatabase.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2007 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 "FontDatabase.h"
+
+#include "CString.h"
+#include "FileSystem.h"
+#include "PlatformString.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <shlobj.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+static String systemFontsDirectory()
+{
+ static bool initialized;
+ static String directory;
+
+ if (!initialized) {
+ initialized = true;
+
+ Vector<UChar> buffer(MAX_PATH);
+ if (FAILED(SHGetFolderPath(0, CSIDL_FONTS | CSIDL_FLAG_CREATE, 0, 0, buffer.data())))
+ return directory;
+ buffer.resize(wcslen(buffer.data()));
+
+ directory = String::adopt(buffer);
+ }
+
+ return directory;
+}
+
+static String fontsPlistPath()
+{
+ static String path = pathByAppendingComponent(localUserSpecificStorageDirectory(), "FontsList.plist");
+ return path;
+}
+
+static bool systemHasFontsNewerThanFontsPlist()
+{
+ WIN32_FILE_ATTRIBUTE_DATA plistAttributes = {0};
+ if (!GetFileAttributesEx(fontsPlistPath().charactersWithNullTermination(), GetFileExInfoStandard, &plistAttributes))
+ return true;
+
+ WIN32_FILE_ATTRIBUTE_DATA fontsDirectoryAttributes = {0};
+ if (!GetFileAttributesEx(systemFontsDirectory().charactersWithNullTermination(), GetFileExInfoStandard, &fontsDirectoryAttributes))
+ return true;
+
+ return CompareFileTime(&plistAttributes.ftLastWriteTime, &fontsDirectoryAttributes.ftLastWriteTime) < 0;
+}
+
+static RetainPtr<CFPropertyListRef> readFontPlist()
+{
+ CString plistPath = fontsPlistPath().utf8();
+
+ RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateFromFileSystemRepresentation(0, reinterpret_cast<const UInt8*>(plistPath.data()), plistPath.length(), false));
+ if (!url)
+ return 0;
+
+ RetainPtr<CFReadStreamRef> stream(AdoptCF, CFReadStreamCreateWithFile(0, url.get()));
+ if (!stream)
+ return 0;
+
+ if (!CFReadStreamOpen(stream.get()))
+ return 0;
+
+ CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0 | kCFPropertyListXMLFormat_v1_0;
+ RetainPtr<CFPropertyListRef> plist(AdoptCF, CFPropertyListCreateFromStream(0, stream.get(), 0, kCFPropertyListMutableContainersAndLeaves, &format, 0));
+
+ CFReadStreamClose(stream.get());
+
+ return plist;
+}
+
+static bool populateFontDatabaseFromPlist()
+{
+ RetainPtr<CFPropertyListRef> plist = readFontPlist();
+ if (!plist)
+ return false;
+
+ RetainPtr<CFDataRef> data(AdoptCF, CFPropertyListCreateXMLData(0, plist.get()));
+ if (!data)
+ return false;
+
+ wkAddFontsFromPlistRepresentation(data.get());
+ return true;
+}
+
+static bool populateFontDatabaseFromFileSystem()
+{
+ RetainPtr<CFStringRef> directory(AdoptCF, systemFontsDirectory().createCFString());
+ if (!directory)
+ return false;
+
+ wkAddFontsInDirectory(directory.get());
+ return true;
+}
+
+static void writeFontDatabaseToPlist()
+{
+ RetainPtr<CFDataRef> data(AdoptCF, wkCreateFontsPlistRepresentation());
+ if (!data)
+ return;
+
+ safeCreateFile(fontsPlistPath(), data.get());
+}
+
+void populateFontDatabase()
+{
+ static bool initialized;
+ if (initialized)
+ return;
+ initialized = true;
+
+ if (!systemHasFontsNewerThanFontsPlist())
+ if (populateFontDatabaseFromPlist())
+ return;
+
+ if (populateFontDatabaseFromFileSystem())
+ writeFontDatabaseToPlist();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/FontDatabase.h b/WebCore/platform/graphics/win/FontDatabase.h
new file mode 100644
index 0000000..4f76c9e
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontDatabase.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef FontDatabase_h
+#define FontDatabase_h
+
+namespace WebCore {
+
+ void populateFontDatabase();
+
+} // namespace WebCore
+
+#endif // !defined(FontDatabase_h)
diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h
new file mode 100644
index 0000000..d61afa8
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontPlatformData.h
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef FontPlatformData_H
+#define FontPlatformData_H
+
+#include "StringImpl.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/RefCounted.h>
+
+#if PLATFORM(CAIRO)
+#include <cairo-win32.h>
+#endif
+
+typedef struct HFONT__* HFONT;
+typedef struct CGFont* CGFontRef;
+
+namespace WebCore {
+
+class FontDescription;
+
+class FontPlatformData {
+public:
+ FontPlatformData()
+#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);
+
+#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();
+
+ 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; }
+ bool syntheticBold() const { return m_syntheticBold; }
+ bool syntheticOblique() const { return m_syntheticOblique; }
+ bool useGDI() const { return m_useGDI; }
+
+ unsigned hash() const
+ {
+ return m_font->hash();
+ }
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ 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:
+ 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;
+ bool m_syntheticOblique;
+ bool m_useGDI;
+};
+
+}
+
+#endif
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
new file mode 100644
index 0000000..4b4df5a
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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) 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>
+
+using std::min;
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI)
+ : m_font(RefCountedHFONT::create(font))
+ , m_size(size)
+#if PLATFORM(CG)
+ , m_cgFont(0)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(useGDI)
+{
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ SelectObject(hdc, font);
+ UINT bufferSize = GetOutlineTextMetrics(hdc, 0, NULL);
+
+ ASSERT_WITH_MESSAGE(bufferSize, "Bitmap fonts not supported with CoreGraphics.");
+
+ if (bufferSize) {
+ OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize);
+
+ GetOutlineTextMetricsW(hdc, bufferSize, metrics);
+ WCHAR* faceName = (WCHAR*)((uintptr_t)metrics + (uintptr_t)metrics->otmpFaceName);
+
+ platformDataInit(font, size, hdc, faceName);
+
+ free(metrics);
+ }
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : m_size(size)
+#if PLATFORM(CG)
+ , m_cgFont(0)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(false)
+{
+}
+
+FontPlatformData::~FontPlatformData()
+{
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontWin.cpp b/WebCore/platform/graphics/win/FontWin.cpp
new file mode 100644
index 0000000..5e423e0
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontWin.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ *
+ * 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 "Font.h"
+
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+#include "UniscribeController.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h,
+ int from, int to) const
+{
+ UniscribeController it(this, run);
+ it.advance(from);
+ float beforeWidth = it.runWidthSoFar();
+ it.advance(to);
+ float afterWidth = it.runWidthSoFar();
+
+ // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
+ if (run.rtl()) {
+ it.advance(run.length());
+ float totalWidth = it.runWidthSoFar();
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+ }
+
+ return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point,
+ int from, int to) const
+{
+ // This glyph buffer holds our glyphs + advances + font data for each glyph.
+ GlyphBuffer glyphBuffer;
+
+ float startX = point.x();
+ UniscribeController controller(this, run);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to, &glyphBuffer);
+
+ // We couldn't generate any glyphs for the run. Give up.
+ if (glyphBuffer.isEmpty())
+ return;
+
+ float afterWidth = controller.runWidthSoFar();
+
+ if (run.rtl()) {
+ controller.advance(run.length());
+ startX += controller.runWidthSoFar() - afterWidth;
+ } else
+ startX += beforeWidth;
+
+ // Draw the glyph buffer now at the starting point returned in startX.
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, run, startPoint);
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ UniscribeController controller(this, run);
+ controller.advance(run.length());
+ return controller.runWidthSoFar();
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ UniscribeController controller(this, run);
+ return controller.offsetForPosition(x, includePartialGlyphs);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
new file mode 100644
index 0000000..c11fc1b
--- /dev/null
+++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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"
+#include <WebKitSystemInterface/WebKitSystemInterface.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;
+ CGGlyph localGlyphBuffer[GlyphPage::size];
+ wkGetGlyphs(fontData->platformData().cgFont(), buffer, localGlyphBuffer, bufferLength);
+ 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;
+ }
+ }
+ return haveGlyphs;
+}
+
+}
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
new file mode 100644
index 0000000..5a4279a
--- /dev/null
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 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.
+ *
+ * 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 "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "NotImplemented.h"
+#include "Path.h"
+
+#include <CoreGraphics/CGBitmapContext.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include "GraphicsContextPlatformPrivateCG.h"
+
+using namespace std;
+
+namespace WebCore {
+
+static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha)
+{
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ BITMAP info;
+
+ 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, bitmapInfo);
+ CGColorSpaceRelease(deviceRGB);
+
+ // Flip coords
+ CGContextTranslateCTM(context, 0, info.bmHeight);
+ CGContextScaleCTM(context, 1, -1);
+
+ // Put the HDC In advanced mode so it will honor affine transforms.
+ SetGraphicsMode(hdc, GM_ADVANCED);
+
+ return context;
+}
+
+GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha)))
+{
+ CGContextRelease(m_data->m_cgContext);
+ m_data->m_hdc = hdc;
+ setPaintingDisabled(!m_data->m_cgContext);
+ if (m_data->m_cgContext) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor());
+ setPlatformStrokeColor(strokeColor());
+ }
+}
+
+bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
+
+// 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)
+{
+ // FIXME: Should a bitmap be created also when a shadow is set?
+ if (mayCreateBitmap && inTransparencyLayer()) {
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = dstRect.width();
+ bitmapInfo.bmiHeader.biHeight = dstRect.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;
+
+ void* pixels = 0;
+ HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!bitmap)
+ return 0;
+
+ HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc);
+ ::SelectObject(bitmapDC, bitmap);
+
+ // Fill our buffer with clear if we're going to alpha blend.
+ if (supportAlphaBlend) {
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+ }
+
+ // Make sure we can do world transforms.
+ SetGraphicsMode(bitmapDC, GM_ADVANCED);
+
+ // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -dstRect.x();
+ xform.eDy = -dstRect.y();
+ ::SetWorldTransform(bitmapDC, &xform);
+
+ return bitmapDC;
+ }
+
+ CGContextFlush(platformContext());
+ m_data->save();
+ return m_data->m_hdc;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ if (mayCreateBitmap && hdc && inTransparencyLayer()) {
+ if (dstRect.isEmpty())
+ return;
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+
+ // Need to make a CGImage out of the bitmap's pixel buffer and then draw
+ // it into our context.
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little |
+ (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst));
+ CGColorSpaceRelease(deviceRGB);
+
+ CGImageRef image = CGBitmapContextCreateImage(bitmapContext);
+ CGContextDrawImage(m_data->m_cgContext, dstRect, image);
+
+ // Delete all our junk.
+ CGImageRelease(image);
+ CGContextRelease(bitmapContext);
+ ::DeleteDC(hdc);
+ ::DeleteObject(bitmap);
+
+ return;
+ }
+
+ m_data->restore();
+}
+
+GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
+ : m_hdc(0)
+ , m_size(size)
+{
+ 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;
+
+ m_hdc = CreateCompatibleDC(hdc);
+ SelectObject(m_hdc, m_bitmap);
+
+ BITMAP bmpInfo;
+ GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo);
+ m_bytesPerRow = bmpInfo.bmWidthBytes;
+ m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+
+ SetGraphicsMode(m_hdc, GM_ADVANCED);
+}
+
+GraphicsContext::WindowsBitmap::~WindowsBitmap()
+{
+ if (!m_bitmap)
+ return;
+
+ DeleteDC(m_hdc);
+ DeleteObject(m_bitmap);
+}
+
+GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize size)
+{
+ return new WindowsBitmap(m_data->m_hdc, size);
+}
+
+void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point)
+{
+ 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)
+{
+ if (!m_hdc)
+ return;
+
+ CGAffineTransform mat = transform;
+ XFORM xform;
+ xform.eM11 = mat.a;
+ xform.eM12 = mat.b;
+ xform.eM21 = mat.c;
+ xform.eM22 = mat.d;
+ xform.eDx = mat.tx;
+ xform.eDy = mat.ty;
+
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ float radius = (focusRingWidth() - 1) / 2.0f;
+ int offset = radius + focusRingOffset();
+ CGColorRef colorRef = color.isValid() ? cgColor(color) : 0;
+
+ CGMutablePathRef focusRingPath = CGPathCreateMutable();
+ const Vector<IntRect>& rects = focusRingRects();
+ unsigned rectCount = rects.size();
+ for (unsigned i = 0; i < rectCount; i++)
+ CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset));
+
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+
+ CGContextBeginPath(context);
+ CGContextAddPath(context, focusRingPath);
+
+ wkDrawFocusRing(context, colorRef, radius);
+
+ CGColorRelease(colorRef);
+
+ CGPathRelease(focusRingPath);
+
+ CGContextRestoreGState(context);
+}
+
+// Pulled from GraphicsContextCG
+static void setCGStrokeColor(CGContextRef context, const Color& color)
+{
+ CGFloat red, green, blue, alpha;
+ color.getRGBA(red, green, blue, alpha);
+ CGContextSetRGBStrokeColor(context, red, green, blue, alpha);
+}
+
+static const Color& spellingPatternColor() {
+ static const Color spellingColor(255, 0, 0);
+ return spellingColor;
+}
+
+static const Color& grammarPatternColor() {
+ static const Color grammarColor(0, 128, 0);
+ return grammarColor;
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ // These are the same for misspelling or bad grammar
+ const int patternHeight = 3; // 3 rows
+ ASSERT(cMisspellingLineThickness == patternHeight);
+ const int patternWidth = 4; // 4 pixels
+ ASSERT(patternWidth == cMisspellingLinePatternWidth);
+
+ // Make sure to draw only complete dots.
+ // NOTE: Code here used to shift the underline to the left and increase the width
+ // to make sure everything gets underlined, but that results in drawing out of
+ // bounds (e.g. when at the edge of a view) and could make it appear that the
+ // space between adjacent misspelled words was underlined.
+ // allow slightly more considering that the pattern ends with a transparent pixel
+ int widthMod = width % patternWidth;
+ if (patternWidth - widthMod > cMisspellingLinePatternGapWidth)
+ width -= widthMod;
+
+ // Draw the underline
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+
+ const Color& patternColor = grammar ? grammarPatternColor() : spellingPatternColor();
+ setCGStrokeColor(context, patternColor);
+
+ wkSetPatternPhaseInUserSpace(context, point);
+ CGContextSetBlendMode(context, kCGBlendModeNormal);
+
+ // 3 rows, each offset by half a pixel for blending purposes
+ const CGPoint upperPoints [] = {{point.x(), point.y() + patternHeight - 2.5 }, {point.x() + width, point.y() + patternHeight - 2.5}};
+ const CGPoint middlePoints [] = {{point.x(), point.y() + patternHeight - 1.5 }, {point.x() + width, point.y() + patternHeight - 1.5}};
+ const CGPoint lowerPoints [] = {{point.x(), point.y() + patternHeight - 0.5 }, {point.x() + width, point.y() + patternHeight - 0.5 }};
+
+ // Dash lengths for the top and bottom of the error underline are the same.
+ // These are magic.
+ static const float edge_dash_lengths[] = {2.0f, 2.0f};
+ static const float middle_dash_lengths[] = {2.76f, 1.24f};
+ static const float edge_offset = -(edge_dash_lengths[1] - 1.0f) / 2.0f;
+ static const float middle_offset = -(middle_dash_lengths[1] - 1.0f) / 2.0f;
+
+ // Line opacities. Once again, these are magic.
+ const float upperOpacity = 0.33f;
+ const float middleOpacity = 0.75f;
+ const float lowerOpacity = 0.88f;
+
+ //Top line
+ CGContextSetLineDash(context, edge_offset, edge_dash_lengths,
+ sizeof(edge_dash_lengths) / sizeof(edge_dash_lengths[0]));
+ CGContextSetAlpha(context, upperOpacity);
+ CGContextStrokeLineSegments(context, upperPoints, 2);
+
+ // Middle line
+ CGContextSetLineDash(context, middle_offset, middle_dash_lengths,
+ sizeof(middle_dash_lengths) / sizeof(middle_dash_lengths[0]));
+ CGContextSetAlpha(context, middleOpacity);
+ CGContextStrokeLineSegments(context, middlePoints, 2);
+
+ // Bottom line
+ CGContextSetLineDash(context, edge_offset, edge_dash_lengths,
+ sizeof(edge_dash_lengths) / sizeof(edge_dash_lengths[0]));
+ CGContextSetAlpha(context, lowerOpacity);
+ CGContextStrokeLineSegments(context, lowerPoints, 2);
+
+ CGContextRestoreGState(context);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
new file mode 100644
index 0000000..3dcf6ba
--- /dev/null
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "NotImplemented.h"
+#include "Path.h"
+
+#include <cairo-win32.h>
+#include "GraphicsContextPlatformPrivateCairo.h"
+
+using namespace std;
+
+namespace WebCore {
+
+GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate)
+{
+ if (dc) {
+ cairo_surface_t* surface = cairo_win32_surface_create(dc);
+ m_data->cr = cairo_create(surface);
+ m_data->m_hdc = dc;
+ } else {
+ setPaintingDisabled(true);
+ m_data->cr = 0;
+ m_data->m_hdc = 0;
+ }
+
+ if (m_data->cr) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor());
+ setPlatformStrokeColor(strokeColor());
+ }
+}
+
+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);
+ SaveDC(hdc);
+
+ // FIXME: We need to make sure a clip is really set on the HDC.
+ // Call SetWorldTransform to honor the current Cairo transform.
+ SetGraphicsMode(hdc, GM_ADVANCED); // We need this call for themes to honor world transforms.
+ cairo_matrix_t mat;
+ cairo_get_matrix(platformContext(), &mat);
+ 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;
+ ::SetWorldTransform(hdc, &xform);
+
+ return hdc;
+}
+
+bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
+
+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 GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
+{
+ cairo_surface_t* surface = cairo_get_target(cr);
+ HDC hdc = cairo_win32_surface_get_dc(surface);
+ SaveDC(hdc);
+
+ const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
+
+ XFORM xform;
+ 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
new file mode 100644
index 0000000..dbf9fad
--- /dev/null
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 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.
+ *
+ * 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 "GraphicsContext.h"
+
+#if PLATFORM(CG)
+#include "GraphicsContextPlatformPrivateCG.h"
+#elif PLATFORM(CAIRO)
+#include "GraphicsContextPlatformPrivateCairo.h"
+#endif
+
+#include "AffineTransform.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+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*)
+{
+ // FIXME: This should go in GraphicsContextCG.cpp
+ notImplemented();
+ return 0;
+}
+#endif
+
+}
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
new file mode 100644
index 0000000..c02b56e
--- /dev/null
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -0,0 +1,84 @@
+/*
+* 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
+* 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 "Icon.h"
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include <tchar.h>
+#include <windows.h>
+
+namespace WebCore {
+
+static const int shell32MultipleFileIconIndex = 54;
+
+Icon::Icon(HICON icon)
+ : m_hIcon(icon)
+{
+ ASSERT(icon);
+}
+
+Icon::~Icon()
+{
+ DestroyIcon(m_hIcon);
+}
+
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
+{
+ SHFILEINFO sfi;
+ memset(&sfi, 0, sizeof(sfi));
+
+ String tmpFilename = filename;
+ if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON))
+ return 0;
+
+ 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)
+{
+ if (context->paintingDisabled())
+ return;
+
+ HDC hdc = context->getWindowsContext(r);
+
+ DrawIconEx(hdc, r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL);
+
+ context->releaseWindowsContext(hdc, r);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp
new file mode 100644
index 0000000..752729c
--- /dev/null
+++ b/WebCore/platform/graphics/win/ImageCGWin.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ * 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 "Image.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+#include <windows.h>
+#include "PlatformString.h"
+
+namespace WebCore {
+
+bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
+{
+ ASSERT(bmp);
+
+ BITMAP bmpInfo;
+ GetObject(bmp, sizeof(BITMAP), &bmpInfo);
+
+ ASSERT(bmpInfo.bmBitsPixel == 32);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ CGContextRef cgContext = CGBitmapContextCreate(bmpInfo.bmBits, bmpInfo.bmWidth, bmpInfo.bmHeight,
+ 8, bmpInfo.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
+
+ GraphicsContext gc(cgContext);
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy);
+ else
+ draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy);
+
+ // Do cleanup
+ CGContextRelease(cgContext);
+ CGColorSpaceRelease(deviceRGB);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp)
+{
+ int frames = frameCount();
+ for (int i = 0; i < frames; ++i) {
+ CGImageRef image = frameAtIndex(i);
+ if (CGImageGetHeight(image) == static_cast<size_t>(srcSize.height()) && CGImageGetWidth(image) == static_cast<size_t>(srcSize.width())) {
+ size_t currentFrame = m_currentFrame;
+ m_currentFrame = i;
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp);
+ m_currentFrame = currentFrame;
+ return;
+ }
+ }
+
+ // No image of the correct size was found, fallback to drawing the current frame
+ IntSize imageSize = BitmapImage::size();
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp
new file mode 100644
index 0000000..95bb7bc
--- /dev/null
+++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "Image.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include <cairo.h>
+
+#include <windows.h>
+#include "PlatformString.h"
+
+namespace WebCore {
+
+bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
+{
+ ASSERT(bmp);
+
+ BITMAP bmpInfo;
+ GetObject(bmp, sizeof(BITMAP), &bmpInfo);
+
+ // If this is a 32bpp bitmap, which it always should be, we'll clear it so alpha-wise it will be visible
+ if (bmpInfo.bmBitsPixel == 32) {
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 255, bufferSize);
+ }
+
+ HDC tempDC = CreateCompatibleDC(0);
+ if (!tempDC) {
+ LOG_ERROR("Failed to create in-memory DC for Image::blit()");
+ return false;
+ }
+ SelectObject(tempDC, bmp);
+ GraphicsContext gc(tempDC);
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy);
+ else
+ draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy);
+
+ // Do cleanup
+ DeleteDC(tempDC);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp)
+{
+ int frames = frameCount();
+ for (int i = 0; i < frames; ++i) {
+ cairo_surface_t* image = frameAtIndex(i);
+ if (cairo_image_surface_get_height(image) == static_cast<size_t>(srcSize.height()) && cairo_image_surface_get_width(image) == static_cast<size_t>(srcSize.width())) {
+ size_t currentFrame = m_currentFrame;
+ m_currentFrame = i;
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp);
+ m_currentFrame = currentFrame;
+ return;
+ }
+ }
+
+ // No image of the correct size was found, fallback to drawing the current frame
+ IntSize imageSize = BitmapImage::size();
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/ImageWin.cpp b/WebCore/platform/graphics/win/ImageWin.cpp
new file mode 100644
index 0000000..54c5b41
--- /dev/null
+++ b/WebCore/platform/graphics/win/ImageWin.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ * 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 "Image.h"
+#include "BitmapImage.h"
+
+#include "SharedBuffer.h"
+
+// This function loads resources from WebKit
+PassRefPtr<WebCore::SharedBuffer> loadResourceIntoBuffer(const char*);
+
+namespace WebCore {
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ RefPtr<SharedBuffer> buffer = loadResourceIntoBuffer(name);
+ RefPtr<BitmapImage> img = BitmapImage::create();
+ img->setData(buffer.release(), true);
+ return img.release();
+}
+
+bool BitmapImage::getHBITMAP(HBITMAP bmp)
+{
+ return getHBITMAPOfSize(bmp, 0);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/IntPointWin.cpp b/WebCore/platform/graphics/win/IntPointWin.cpp
new file mode 100644
index 0000000..a6ce0bb
--- /dev/null
+++ b/WebCore/platform/graphics/win/IntPointWin.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "IntPoint.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const POINT& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator POINT() const
+{
+ POINT p = {m_x, m_y};
+ return p;
+}
+
+IntPoint::IntPoint(const POINTS& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator POINTS() const
+{
+ POINTS p = {m_x, m_y};
+ return p;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/IntRectWin.cpp b/WebCore/platform/graphics/win/IntRectWin.cpp
new file mode 100644
index 0000000..6228be8
--- /dev/null
+++ b/WebCore/platform/graphics/win/IntRectWin.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "IntRect.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntRect::IntRect(const RECT& r)
+ : m_location(IntPoint(r.left, r.top)), m_size(IntSize(r.right-r.left, r.bottom-r.top))
+{
+}
+
+IntRect::operator RECT() const
+{
+ RECT rect = { x(), y(), right(), bottom() };
+ return rect;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/IntSizeWin.cpp b/WebCore/platform/graphics/win/IntSizeWin.cpp
new file mode 100644
index 0000000..8a27cdb
--- /dev/null
+++ b/WebCore/platform/graphics/win/IntSizeWin.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "IntSize.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntSize::IntSize(const SIZE& s)
+ : m_width(s.cx)
+ , m_height(s.cy)
+{
+}
+
+IntSize::operator SIZE() const
+{
+ SIZE s = {m_width, m_height};
+ return s;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
new file mode 100644
index 0000000..cef4217
--- /dev/null
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2007 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"
+
+#if ENABLE(VIDEO)
+#include "MediaPlayerPrivateQuickTimeWin.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 {
+
+static const double endPointTimerInterval = 0.020;
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player)
+ , m_seekTo(-1)
+ , m_endTime(numeric_limits<float>::infinity())
+ , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
+ , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::DataUnavailable)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+#if DRAW_FRAME_RATE
+ , m_frameCountWhilePlaying(0)
+ , m_timeStartedPlaying(0)
+ , m_timeStoppedPlaying(0)
+#endif
+{
+}
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+}
+
+void MediaPlayerPrivate::load(const String& url)
+{
+ if (!QTMovieWin::initializeQuickTime()) {
+ m_networkState = MediaPlayer::LoadFailed;
+ m_player->networkStateChanged();
+ return;
+ }
+
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::DataUnavailable) {
+ m_readyState = MediaPlayer::DataUnavailable;
+ m_player->readyStateChanged();
+ }
+ cancelSeek();
+ m_endPointTimer.stop();
+
+ m_qtMovie.set(new QTMovieWin(this));
+ m_qtMovie->load(url.characters(), url.length());
+ m_qtMovie->setVolume(m_player->m_volume);
+ m_qtMovie->setVisible(m_player->m_visible);
+}
+
+void MediaPlayerPrivate::play()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = true;
+#if DRAW_FRAME_RATE
+ m_frameCountWhilePlaying = 0;
+#endif
+
+ m_qtMovie->play();
+ startEndPointTimerIfNeeded();
+}
+
+void MediaPlayerPrivate::pause()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = GetTickCount();
+#endif
+ m_qtMovie->pause();
+ m_endPointTimer.stop();
+}
+
+float MediaPlayerPrivate::duration() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->duration();
+}
+
+float MediaPlayerPrivate::currentTime() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return min(m_qtMovie->currentTime(), m_endTime);
+}
+
+void MediaPlayerPrivate::seek(float time)
+{
+ cancelSeek();
+
+ if (!m_qtMovie)
+ return;
+
+ if (time > duration())
+ time = duration();
+
+ m_seekTo = time;
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else
+ m_seekTimer.start(0, 0.5f);
+}
+
+void MediaPlayerPrivate::doSeek()
+{
+ float oldRate = m_qtMovie->rate();
+ m_qtMovie->setRate(0);
+ m_qtMovie->setCurrentTime(m_seekTo);
+ float timeAfterSeek = currentTime();
+ // restore playback only if not at end, othewise QTMovie will loop
+ if (timeAfterSeek < duration() && timeAfterSeek < m_endTime)
+ m_qtMovie->setRate(oldRate);
+ cancelSeek();
+}
+
+void MediaPlayerPrivate::cancelSeek()
+{
+ m_seekTo = -1;
+ m_seekTimer.stop();
+}
+
+void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
+{
+ if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ return;
+ }
+
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else {
+ MediaPlayer::NetworkState state = networkState();
+ if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ }
+ }
+}
+
+void MediaPlayerPrivate::setEndTime(float time)
+{
+ m_endTime = time;
+ startEndPointTimerIfNeeded();
+}
+
+void MediaPlayerPrivate::startEndPointTimerIfNeeded()
+{
+ if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive())
+ m_endPointTimer.startRepeating(endPointTimerInterval);
+}
+
+void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
+{
+ float time = currentTime();
+ if (time >= m_endTime) {
+ pause();
+ didEnd();
+ }
+}
+
+bool MediaPlayerPrivate::paused() const
+{
+ if (!m_qtMovie)
+ return true;
+ return m_qtMovie->rate() == 0.0f;
+}
+
+bool MediaPlayerPrivate::seeking() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_seekTo >= 0;
+}
+
+IntSize MediaPlayerPrivate::naturalSize() const
+{
+ if (!m_qtMovie)
+ return IntSize();
+ int width;
+ int height;
+ m_qtMovie->getNaturalSize(width, height);
+ return IntSize(width, height);
+}
+
+bool MediaPlayerPrivate::hasVideo() const
+{
+ // This is not used at the moment
+ return true;
+}
+
+void MediaPlayerPrivate::setVolume(float volume)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setVolume(volume);
+}
+
+void MediaPlayerPrivate::setRate(float rate)
+{
+ if (!m_qtMovie)
+ return;
+ if (!paused())
+ m_qtMovie->setRate(rate);
+}
+
+int MediaPlayerPrivate::dataRate() const
+{
+ // This is not used at the moment
+ return 0;
+}
+
+float MediaPlayerPrivate::maxTimeBuffered() const
+{
+ // rtsp streams are not buffered
+ return m_isStreaming ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeSeekable() const
+{
+ // infinite duration means live stream
+ return !isfinite(duration()) ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeLoaded() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->maxTimeLoaded();
+}
+
+unsigned MediaPlayerPrivate::bytesLoaded() const
+{
+ if (!m_qtMovie)
+ return 0;
+ float dur = duration();
+ float maxTime = maxTimeLoaded();
+ if (!dur)
+ return 0;
+ return totalBytes() * maxTime / dur;
+}
+
+bool MediaPlayerPrivate::totalBytesKnown() const
+{
+ return totalBytes() > 0;
+}
+
+unsigned MediaPlayerPrivate::totalBytes() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->dataSize();
+}
+
+void MediaPlayerPrivate::cancelLoad()
+{
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ // Cancel the load by destroying the movie.
+ m_qtMovie.clear();
+
+ updateStates();
+}
+
+void MediaPlayerPrivate::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;
+
+ 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>
+ if (!enabledTrackCount)
+ loadState = QTMovieLoadStateError;
+ }
+
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
+ if (m_networkState < MediaPlayer::Loaded)
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::CanPlayThrough;
+ } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
+ if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
+ m_networkState = MediaPlayer::LoadedFirstFrame;
+ m_readyState = MediaPlayer::CanPlayThrough;
+ } else if (loadState >= QTMovieLoadStatePlayable) {
+ if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
+ m_networkState = MediaPlayer::LoadedFirstFrame;
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable;
+ } else if (loadState >= QTMovieLoadStateLoaded) {
+ if (m_networkState < MediaPlayer::LoadedMetaData)
+ m_networkState = MediaPlayer::LoadedMetaData;
+ m_readyState = MediaPlayer::DataUnavailable;
+ } else if (loadState > QTMovieLoadStateError) {
+ if (m_networkState < MediaPlayer::Loading)
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::DataUnavailable;
+ } else {
+ m_networkState = MediaPlayer::LoadFailed;
+ m_readyState = MediaPlayer::DataUnavailable;
+ }
+
+ if (seeking())
+ m_readyState = MediaPlayer::DataUnavailable;
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+}
+
+
+void MediaPlayerPrivate::didEnd()
+{
+ m_endPointTimer.stop();
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = GetTickCount();
+#endif
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::setRect(const IntRect& r)
+{
+ if (m_qtMovie)
+ m_qtMovie->setSize(r.width(), r.height());
+}
+
+void MediaPlayerPrivate::setVisible(bool b)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setVisible(b);
+}
+
+void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
+{
+ if (p->paintingDisabled() || !m_qtMovie)
+ return;
+ 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)
+{
+ unsigned count = QTMovieWin::countSupportedTypes();
+ for (unsigned n = 0; n < count; n++) {
+ const UChar* character;
+ unsigned len;
+ QTMovieWin::getSupportedType(n, character, len);
+ if (len)
+ types.add(String(character, len));
+ }
+}
+
+bool MediaPlayerPrivate::isAvailable()
+{
+ return QTMovieWin::initializeQuickTime();
+}
+
+void MediaPlayerPrivate::movieEnded(QTMovieWin* movie)
+{
+ ASSERT(m_qtMovie.get() == movie);
+ didEnd();
+}
+
+void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie)
+{
+ ASSERT(m_qtMovie.get() == movie);
+ updateStates();
+}
+
+void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie)
+{
+ ASSERT(m_qtMovie.get() == movie);
+ updateStates();
+ m_player->timeChanged();
+}
+
+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();
+}
+
+}
+
+#endif
+
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
new file mode 100644
index 0000000..c4c893c
--- /dev/null
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef MediaPlayerPrivateQTKit_h
+#define MediaPlayerPrivateQTKit_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayer.h"
+#include "Timer.h"
+#include <QTMovieWin.h>
+#include <wtf/OwnPtr.h>
+
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntSize;
+class IntRect;
+class String;
+
+class MediaPlayerPrivate : QTMovieWinClient, Noncopyable {
+public:
+ MediaPlayerPrivate(MediaPlayer*);
+ ~MediaPlayerPrivate();
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+
+ void load(const String& url);
+ void cancelLoad();
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+ void setEndTime(float);
+
+ void setRate(float);
+ void setVolume(float);
+
+ int dataRate() const;
+
+ MediaPlayer::NetworkState networkState() const { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ float maxTimeBuffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ bool totalBytesKnown() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setRect(const IntRect&);
+
+ void loadStateChanged();
+ void didEnd();
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ static void getSupportedTypes(HashSet<String>& types);
+ static bool isAvailable();
+
+private:
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivate>*);
+ void endPointTimerFired(Timer<MediaPlayerPrivate>*);
+ float maxTimeLoaded() const;
+ void startEndPointTimerIfNeeded();
+
+ virtual void movieEnded(QTMovieWin*);
+ virtual void movieLoadStateChanged(QTMovieWin*);
+ virtual void movieTimeChanged(QTMovieWin*);
+ virtual void movieNewImageAvailable(QTMovieWin*);
+
+ MediaPlayer* m_player;
+ OwnPtr<QTMovieWin> m_qtMovie;
+ float m_seekTo;
+ float m_endTime;
+ Timer<MediaPlayerPrivate> m_seekTimer;
+ Timer<MediaPlayerPrivate> m_endPointTimer;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+#if DRAW_FRAME_RATE
+ int m_frameCountWhilePlaying;
+ int m_timeStartedPlaying;
+ int m_timeStoppedPlaying;
+#endif
+};
+
+}
+
+#endif
+#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/OpenTypeUtilities.h b/WebCore/platform/graphics/win/OpenTypeUtilities.h
new file mode 100644
index 0000000..ab35551
--- /dev/null
+++ b/WebCore/platform/graphics/win/OpenTypeUtilities.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef OpenTypeUtilities_h
+#define OpenTypeUtilities_h
+
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+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
new file mode 100644
index 0000000..8eee41b
--- /dev/null
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -0,0 +1,875 @@
+/*
+ * Copyright (C) 2007 Apple Computer, 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 <windows.h>
+
+#include "QTMovieWin.h"
+
+// Put Movies.h first so build failures here point clearly to QuickTime
+#include <Movies.h>
+#include <QuickTimeComponents.h>
+#include <GXMath.h>
+#include <QTML.h>
+
+#include "QTMovieWinTimer.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+static const long minimumQuickTimeVersion = 0x07300000; // 7.3
+
+// Resizing GWorlds is slow, give them a minimum size so size of small
+// videos can be animated smoothly
+static const int cGWorldMinWidth = 640;
+static const int cGWorldMinHeight = 360;
+
+static const float cNonContinuousTimeChange = 0.2f;
+
+union UppParam {
+ long longValue;
+ void* ptr;
+};
+
+static MovieDrawingCompleteUPP gMovieDrawingCompleteUPP = 0;
+static HashSet<QTMovieWinPrivate*>* gTaskList;
+static Vector<CFStringRef>* gSupportedTypes = 0;
+static SInt32 quickTimeVersion = 0;
+
+static void updateTaskTimer(int maxInterval = 1000)
+{
+ if (!gTaskList->size()) {
+ stopSharedTimer();
+ return;
+ }
+
+ long intervalInMS;
+ QTGetTimeUntilNextTask(&intervalInMS, 1000);
+ if (intervalInMS > maxInterval)
+ intervalInMS = maxInterval;
+ setSharedTimerFireDelay(static_cast<float>(intervalInMS) / 1000);
+}
+
+class QTMovieWinPrivate : Noncopyable {
+public:
+ QTMovieWinPrivate();
+ ~QTMovieWinPrivate();
+ void task();
+ 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;
+ bool m_ended;
+ bool m_seeking;
+ float m_lastMediaTime;
+ double m_lastLoadStateCheckTime;
+ int m_width;
+ int m_height;
+ bool m_visible;
+ GWorldPtr m_gWorld;
+ int m_gWorldWidth;
+ int m_gWorldHeight;
+ GWorldPtr m_savedGWorld;
+ long m_loadError;
+};
+
+QTMovieWinPrivate::QTMovieWinPrivate()
+ : m_movieWin(0)
+ , m_movie(0)
+ , m_movieController(0)
+ , m_tasking(false)
+ , m_client(0)
+ , m_loadState(0)
+ , m_ended(false)
+ , m_seeking(false)
+ , m_lastMediaTime(0)
+ , m_lastLoadStateCheckTime(0)
+ , m_width(0)
+ , m_height(0)
+ , m_visible(false)
+ , m_gWorld(0)
+ , m_gWorldWidth(0)
+ , m_gWorldHeight(0)
+ , m_savedGWorld(0)
+ , m_loadError(0)
+{
+}
+
+QTMovieWinPrivate::~QTMovieWinPrivate()
+{
+ endTask();
+ if (m_gWorld)
+ deleteGWorld();
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
+ if (m_movie)
+ DisposeMovie(m_movie);
+}
+
+static void taskTimerFired()
+{
+ // The hash content might change during task()
+ Vector<QTMovieWinPrivate*> tasks;
+ copyToVector(*gTaskList, tasks);
+ size_t count = tasks.size();
+ for (unsigned n = 0; n < count; ++n)
+ tasks[n]->task();
+
+ updateTaskTimer();
+}
+
+void QTMovieWinPrivate::startTask()
+{
+ if (m_tasking)
+ return;
+ if (!gTaskList)
+ gTaskList = new HashSet<QTMovieWinPrivate*>;
+ gTaskList->add(this);
+ m_tasking = true;
+ updateTaskTimer();
+}
+
+void QTMovieWinPrivate::endTask()
+{
+ if (!m_tasking)
+ return;
+ gTaskList->remove(this);
+ m_tasking = false;
+ updateTaskTimer();
+}
+
+void QTMovieWinPrivate::task()
+{
+ ASSERT(m_tasking);
+
+ 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) {
+ // If load fails QT's load state is kMovieLoadStateComplete.
+ // 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();
+ }
+
+ bool ended = !!IsMovieDone(m_movie);
+ if (ended != m_ended) {
+ m_ended = ended;
+ if (m_client && ended)
+ m_client->movieEnded(m_movieWin);
+ }
+
+ float time = m_movieWin->currentTime();
+ if (time < m_lastMediaTime || time >= m_lastMediaTime + cNonContinuousTimeChange || m_seeking) {
+ m_seeking = false;
+ if (m_client)
+ m_client->movieTimeChanged(m_movieWin);
+ }
+ m_lastMediaTime = time;
+
+ if (m_loadError)
+ 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;
+ param.ptr = this;
+ SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, gMovieDrawingCompleteUPP, param.longValue);
+}
+
+void QTMovieWinPrivate::drawingComplete()
+{
+ if (!m_gWorld || m_loadState < kMovieLoadStateLoaded)
+ return;
+ m_client->movieNewImageAvailable(m_movieWin);
+}
+
+void QTMovieWinPrivate::updateGWorld()
+{
+ bool shouldBeVisible = m_visible;
+ if (!m_height || !m_width)
+ shouldBeVisible = false;
+
+ if (shouldBeVisible && !m_gWorld)
+ createGWorld();
+ else if (!shouldBeVisible && m_gWorld)
+ deleteGWorld();
+ else if (m_gWorld && (m_width > m_gWorldWidth || m_height > m_gWorldHeight)) {
+ // need a bigger, better gWorld
+ deleteGWorld();
+ createGWorld();
+ }
+}
+
+void QTMovieWinPrivate::createGWorld()
+{
+ ASSERT(!m_gWorld);
+ if (!m_movie)
+ return;
+
+ m_gWorldWidth = max(cGWorldMinWidth, m_width);
+ m_gWorldHeight = max(cGWorldMinHeight, m_height);
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = m_gWorldWidth;
+ bounds.bottom = m_gWorldHeight;
+ OSErr err = QTNewGWorld(&m_gWorld, k32BGRAPixelFormat, &bounds, NULL, NULL, NULL);
+ 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)
+ return;
+ m_width = width;
+ m_height = height;
+ if (!m_movie)
+ return;
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = width;
+ bounds.bottom = height;
+ if (m_movieController)
+ MCSetControllerBoundsRect(m_movieController, &bounds);
+ SetMovieBox(m_movie, &bounds);
+ updateGWorld();
+}
+
+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;
+ DisposeGWorld(m_gWorld);
+ m_gWorld = 0;
+ m_gWorldWidth = 0;
+ m_gWorldHeight = 0;
+}
+
+
+QTMovieWin::QTMovieWin(QTMovieWinClient* client)
+ : m_private(new QTMovieWinPrivate())
+{
+ m_private->m_movieWin = this;
+ m_private->m_client = client;
+ initializeQuickTime();
+}
+
+QTMovieWin::~QTMovieWin()
+{
+ delete m_private;
+}
+
+void QTMovieWin::play()
+{
+ 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()
+{
+ 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)
+{
+ 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();
+}
+
+float QTMovieWin::duration() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val = GetMovieDuration(m_private->m_movie);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+float QTMovieWin::currentTime() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val = GetMovieTime(m_private->m_movie, 0);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+void QTMovieWin::setCurrentTime(float time) const
+{
+ if (!m_private->m_movie)
+ return;
+ m_private->m_seeking = true;
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ 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
+{
+ if (!m_private->m_movie)
+ return 0;
+ return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie));
+}
+
+float QTMovieWin::maxTimeLoaded() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val;
+ GetMaxLoadedTimeInMovie(m_private->m_movie, &val);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+long QTMovieWin::loadState() const
+{
+ return m_private->m_loadState;
+}
+
+void QTMovieWin::getNaturalSize(int& width, int& height)
+{
+ Rect rect = { 0, };
+
+ if (m_private->m_movie)
+ GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
+ width = rect.right;
+ height = rect.bottom;
+}
+
+void QTMovieWin::setSize(int width, int height)
+{
+ m_private->setSize(width, height);
+ updateTaskTimer(0);
+}
+
+void QTMovieWin::setVisible(bool b)
+{
+ m_private->m_visible = b;
+ m_private->updateGWorld();
+}
+
+void QTMovieWin::paint(HDC hdc, int x, int y)
+{
+ if (!m_private->m_gWorld)
+ return;
+
+ HDC hdcSrc = static_cast<HDC>(GetPortHDC(reinterpret_cast<GrafPtr>(m_private->m_gWorld)));
+ if (!hdcSrc)
+ return;
+
+ // FIXME: If we could determine the movie has no alpha, we could use BitBlt for those cases, which might be faster.
+ BLENDFUNCTION blendFunction;
+ blendFunction.BlendOp = AC_SRC_OVER;
+ blendFunction.BlendFlags = 0;
+ blendFunction.SourceConstantAlpha = 255;
+ blendFunction.AlphaFormat = AC_SRC_ALPHA;
+ AlphaBlend(hdc, x, y, m_private->m_width, m_private->m_height, hdcSrc,
+ 0, 0, m_private->m_width, m_private->m_height, blendFunction);
+}
+
+void QTMovieWin::load(const UChar* url, int len)
+{
+ if (m_private->m_movie) {
+ 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;
+ }
+
+ // Define a property array for NewMovieFromProperties. 8 should be enough for our needs.
+ QTNewMoviePropertyElement movieProps[8];
+ ItemCount moviePropCount = 0;
+
+ bool boolTrue = true;
+
+ // Create a URL data reference of type CFURL
+ CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len);
+
+ // Disable streaming support for now.
+ if (CFStringHasPrefix(urlStringRef, CFSTR("rtsp:"))) {
+ m_private->m_loadError = noMovieFound;
+ goto end;
+ }
+
+ CFURLRef urlRef = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0);
+
+ // Add the movie data location to the property array
+ movieProps[moviePropCount].propClass = kQTPropertyClass_DataLocation;
+ movieProps[moviePropCount].propID = kQTDataLocationPropertyID_CFURL;
+ movieProps[moviePropCount].propValueSize = sizeof(urlRef);
+ movieProps[moviePropCount].propValueAddress = &urlRef;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_DontAskUnresolvedDataRefs;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_AsyncOK;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty;
+ movieProps[moviePropCount].propID = kQTNewMoviePropertyID_Active;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty;
+ movieProps[moviePropCount].propID = kQTNewMoviePropertyID_DontInteractWithUser;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = '!url';
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = 'site';
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, NULL, &m_private->m_movie);
+
+ CFRelease(urlRef);
+end:
+ m_private->startTask();
+ // get the load fail callback quickly
+ if (m_private->m_loadError)
+ updateTaskTimer(0);
+ else
+ m_private->registerDrawingCallback();
+
+ CFRelease(urlStringRef);
+}
+
+void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount)
+{
+ if (!m_private->m_movie) {
+ enabledTrackCount = 0;
+ return;
+ }
+
+ static HashSet<OSType>* allowedTrackTypes = 0;
+ if (!allowedTrackTypes) {
+ allowedTrackTypes = new HashSet<OSType>;
+ allowedTrackTypes->add(VideoMediaType);
+ allowedTrackTypes->add(SoundMediaType);
+ allowedTrackTypes->add(TextMediaType);
+ allowedTrackTypes->add(BaseMediaType);
+ allowedTrackTypes->add('clcp'); // Closed caption
+ allowedTrackTypes->add('sbtl'); // Subtitle
+ }
+
+ long trackCount = GetMovieTrackCount(m_private->m_movie);
+ enabledTrackCount = trackCount;
+
+ // Track indexes are 1-based. yuck. These things must descend from old-
+ // school mac resources or something.
+ for (long trackIndex = 1; trackIndex <= trackCount; trackIndex++) {
+ // Grab the track at the current index. If there isn't one there, then
+ // we can move onto the next one.
+ Track currentTrack = GetMovieIndTrack(m_private->m_movie, trackIndex);
+ if (!currentTrack)
+ continue;
+
+ // Check to see if the track is disabled already, we should move along.
+ // We don't need to re-disable it.
+ if (!GetTrackEnabled(currentTrack))
+ continue;
+
+ // Grab the track's media. We're going to check to see if we need to
+ // disable the tracks. They could be unsupported.
+ Media trackMedia = GetTrackMedia(currentTrack);
+ if (!trackMedia)
+ continue;
+
+ // Grab the media type for this track. Make sure that we don't
+ // get an error in doing so. If we do, then something really funky is
+ // wrong.
+ OSType mediaType;
+ GetMediaHandlerDescription(trackMedia, &mediaType, nil, nil);
+ OSErr mediaErr = GetMoviesError();
+ if (mediaErr != noErr)
+ continue;
+
+ if (!allowedTrackTypes->contains(mediaType)) {
+ SetTrackEnabled(currentTrack, false);
+ --enabledTrackCount;
+ }
+
+ // Grab the track reference count for chapters. This will tell us if it
+ // has chapter tracks in it. If there aren't any references, then we
+ // can move on the next track.
+ long referenceCount = GetTrackReferenceCount(currentTrack, kTrackReferenceChapterList);
+ if (referenceCount <= 0)
+ continue;
+
+ long referenceIndex = 0;
+ while (1) {
+ // If we get nothing here, we've overstepped our bounds and can stop
+ // looking. Chapter indices here are 1-based as well - hence, the
+ // pre-increment.
+ referenceIndex++;
+ Track chapterTrack = GetTrackReference(currentTrack, kTrackReferenceChapterList, referenceIndex);
+ if (!chapterTrack)
+ break;
+
+ // Try to grab the media for the track.
+ Media chapterMedia = GetTrackMedia(chapterTrack);
+ if (!chapterMedia)
+ continue;
+
+ // Grab the media type for this track. Make sure that we don't
+ // get an error in doing so. If we do, then something really
+ // funky is wrong.
+ OSType mediaType;
+ GetMediaHandlerDescription(chapterMedia, &mediaType, nil, nil);
+ OSErr mediaErr = GetMoviesError();
+ if (mediaErr != noErr)
+ continue;
+
+ // Check to see if the track is a video track. We don't care about
+ // other non-video tracks.
+ if (mediaType != VideoMediaType)
+ continue;
+
+ // Check to see if the track is already disabled. If it is, we
+ // should move along.
+ if (!GetTrackEnabled(chapterTrack))
+ continue;
+
+ // Disabled the evil, evil track.
+ SetTrackEnabled(chapterTrack, false);
+ --enabledTrackCount;
+ }
+ }
+}
+
+pascal OSErr movieDrawingCompleteProc(Movie movie, long data)
+{
+ UppParam param;
+ param.longValue = data;
+ QTMovieWinPrivate* mp = static_cast<QTMovieWinPrivate*>(param.ptr);
+ if (mp)
+ mp->drawingComplete();
+ return 0;
+}
+
+static void initializeSupportedTypes()
+{
+ if (gSupportedTypes)
+ return;
+
+ gSupportedTypes = new Vector<CFStringRef>;
+ 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"));
+
+ 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()
+{
+ initializeSupportedTypes();
+ return static_cast<unsigned>(gSupportedTypes->size());
+}
+
+void QTMovieWin::getSupportedType(unsigned index, const UChar*& str, unsigned& len)
+{
+ initializeSupportedTypes();
+ ASSERT(index < gSupportedTypes->size());
+
+ // Allocate sufficient buffer to hold any MIME type
+ static UniChar* staticBuffer = 0;
+ if (!staticBuffer)
+ staticBuffer = new UniChar[32];
+
+ CFStringRef cfstr = gSupportedTypes->at(index);
+ len = CFStringGetLength(cfstr);
+ CFRange range = { 0, len };
+ CFStringGetCharacters(cfstr, range, staticBuffer);
+ str = reinterpret_cast<const UChar*>(staticBuffer);
+
+}
+
+bool QTMovieWin::initializeQuickTime()
+{
+ static bool initialized = false;
+ static bool initializationSucceeded = false;
+ if (!initialized) {
+ initialized = true;
+ // Initialize and check QuickTime version
+ OSErr result = InitializeQTML(0);
+ if (result == noErr)
+ result = Gestalt(gestaltQuickTime, &quickTimeVersion);
+ if (result != noErr) {
+ LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support.");
+ return false;
+ }
+ if (quickTimeVersion < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", quickTimeVersion, minimumQuickTimeVersion);
+ return false;
+ }
+ EnterMovies();
+ setSharedTimerFiredFunction(taskTimerFired);
+ gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc);
+ initializationSucceeded = true;
+ }
+ return initializationSucceeded;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ setSharedTimerInstanceHandle(hinstDLL);
+ return TRUE;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ return FALSE;
+ }
+ ASSERT_NOT_REACHED();
+ return FALSE;
+}
diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h
new file mode 100644
index 0000000..e31780a
--- /dev/null
+++ b/WebCore/platform/graphics/win/QTMovieWin.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 Apple Computer, 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.
+ */
+
+#ifndef QTMovieWin_h
+#define QTMovieWin_h
+
+#include <Unicode.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTMovieWin;
+class QTMovieWinPrivate;
+
+class QTMovieWinClient {
+public:
+ virtual void movieEnded(QTMovieWin*) = 0;
+ virtual void movieLoadStateChanged(QTMovieWin*) = 0;
+ virtual void movieTimeChanged(QTMovieWin*) = 0;
+ virtual void movieNewImageAvailable(QTMovieWin*) = 0;
+};
+
+enum {
+ QTMovieLoadStateError = -1L,
+ QTMovieLoadStateLoaded = 2000L,
+ QTMovieLoadStatePlayable = 10000L,
+ QTMovieLoadStatePlaythroughOK = 20000L,
+ QTMovieLoadStateComplete = 100000L
+};
+
+class QTMOVIEWIN_API QTMovieWin {
+public:
+ static bool initializeQuickTime();
+
+ QTMovieWin(QTMovieWinClient*);
+ ~QTMovieWin();
+
+ void load(const UChar* url, int len);
+ long loadState() const;
+ float maxTimeLoaded() const;
+
+ void play();
+ void pause();
+
+ float rate() const;
+ void setRate(float);
+
+ float duration() const;
+ float currentTime() const;
+ void setCurrentTime(float) const;
+
+ void setVolume(float);
+
+ unsigned dataSize() const;
+
+ void getNaturalSize(int& width, int& height);
+ void setSize(int width, int height);
+
+ void setVisible(bool);
+ void paint(HDC, int x, int y);
+
+ void disableUnsupportedTracks(unsigned& enabledTrackCount);
+
+ static unsigned countSupportedTypes();
+ static void getSupportedType(unsigned index, const UChar*& str, unsigned& len);
+
+private:
+ QTMovieWinPrivate* m_private;
+ friend class QTMovieWinPrivate;
+};
+
+#endif
diff --git a/WebCore/platform/graphics/win/QTMovieWinTimer.cpp b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
new file mode 100644
index 0000000..d0aa3e6
--- /dev/null
+++ b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, 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 <windows.h>
+
+#include "QTMovieWinTimer.h"
+
+#include <wtf/Assertions.h>
+
+// This file is used by the QuickTime access DLL. It copies some WebCore code
+// which can't be used directly due to dependency issues.
+
+// FIXME: Find a way to do timers that can manage <10ms resolution properly too.
+
+static UINT_PTR timerID;
+static void (*sharedTimerFiredFunction)();
+
+static HINSTANCE instanceHandle = 0;
+
+static HWND timerWindowHandle = 0;
+static UINT timerFiredMessage = 0;
+static const LPCWSTR kTimerWindowClassName = L"TimerWindowClass";
+static bool processingCustomTimerMessage = false;
+
+static LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == timerFiredMessage) {
+ processingCustomTimerMessage = true;
+ sharedTimerFiredFunction();
+ processingCustomTimerMessage = false;
+ } else
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ return 0;
+}
+
+static void initializeOffScreenTimerWindow()
+{
+ if (timerWindowHandle)
+ return;
+
+ WNDCLASSEX wcex;
+ memset(&wcex, 0, sizeof(WNDCLASSEX));
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = TimerWindowWndProc;
+ wcex.hInstance = instanceHandle;
+ wcex.lpszClassName = kTimerWindowClassName;
+ RegisterClassEx(&wcex);
+
+ timerWindowHandle = CreateWindow(kTimerWindowClassName, 0, 0,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, instanceHandle, 0);
+ timerFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.TimerFired");
+}
+
+void setSharedTimerFiredFunction(void (*f)())
+{
+ sharedTimerFiredFunction = f;
+}
+
+static void CALLBACK timerFired(HWND, UINT, UINT_PTR, DWORD)
+{
+ sharedTimerFiredFunction();
+}
+
+void setSharedTimerFireDelay(double interval)
+{
+ ASSERT(sharedTimerFiredFunction);
+
+ unsigned intervalInMS;
+ if (interval < 0)
+ intervalInMS = 0;
+ else {
+ interval *= 1000;
+ if (interval > USER_TIMER_MAXIMUM)
+ intervalInMS = USER_TIMER_MAXIMUM;
+ else
+ intervalInMS = (unsigned)interval;
+ }
+
+ if (timerID) {
+ KillTimer(0, timerID);
+ timerID = 0;
+ }
+
+ // We don't allow nested PostMessages, since the custom messages will effectively starve
+ // painting and user input. (Win32 has a tri-level queue with application messages >
+ // user input > WM_PAINT/WM_TIMER.)
+ // In addition, if the queue contains input events that have been there since the last call to
+ // GetQueueStatus, PeekMessage or GetMessage we favor timers.
+ if (intervalInMS < USER_TIMER_MINIMUM && processingCustomTimerMessage &&
+ !LOWORD(::GetQueueStatus(QS_ALLINPUT))) {
+ // Windows SetTimer does not allow timeouts smaller than 10ms (USER_TIMER_MINIMUM)
+ initializeOffScreenTimerWindow();
+ PostMessage(timerWindowHandle, timerFiredMessage, 0, 0);
+ } else
+ timerID = SetTimer(0, 0, intervalInMS, timerFired);
+}
+
+void stopSharedTimer()
+{
+ if (timerID) {
+ KillTimer(0, timerID);
+ timerID = 0;
+ }
+}
+
+void setSharedTimerInstanceHandle(HINSTANCE handle)
+{
+ instanceHandle = handle;
+}
+
+double systemTime()
+{
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ ULARGE_INTEGER t;
+ memcpy(&t, &ft, sizeof(t));
+ return t.QuadPart * 0.0000001 - 11644473600.0;
+}
diff --git a/WebCore/platform/graphics/win/QTMovieWinTimer.h b/WebCore/platform/graphics/win/QTMovieWinTimer.h
new file mode 100644
index 0000000..3e3c2bc
--- /dev/null
+++ b/WebCore/platform/graphics/win/QTMovieWinTimer.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, 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.
+ */
+
+#ifndef QTMovieViewTimer_h
+#define QTMovieViewTimer_h
+
+// This header should not be included from WebCore.
+// It is used by the QuickTime access DLL. It copies some WebCore code
+// which can't be used directly due to dependency issues.
+
+void setSharedTimerFiredFunction(void (*)());
+void setSharedTimerFireDelay(double delay);
+void stopSharedTimer();
+void setSharedTimerInstanceHandle(HINSTANCE handle);
+double systemTime();
+
+#endif
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
new file mode 100644
index 0000000..8b5ab87
--- /dev/null
+++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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 "SimpleFontData.h"
+
+#include <winsock2.h>
+#include "Font.h"
+#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>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <mlang.h>
+#include <tchar.h>
+
+namespace WebCore {
+
+using std::max;
+
+static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return unitsPerEm ? x / static_cast<float>(unitsPerEm) : x; }
+
+void SimpleFontData::platformInit()
+{
+ m_syntheticBoldOffset = m_font.syntheticBold() ? 1.0f : 0.f;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+
+ if (m_font.useGDI())
+ return initGDIFont();
+
+ CGFontRef font = m_font.cgFont();
+ int iAscent = CGFontGetAscent(font);
+ int iDescent = CGFontGetDescent(font);
+ int iLineGap = CGFontGetLeading(font);
+ m_unitsPerEm = CGFontGetUnitsPerEm(font);
+ float pointSize = m_font.size();
+ float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize;
+ float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize;
+ float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize;
+
+ if (!isCustomFont()) {
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_font.hfont());
+ int faceLength = GetTextFace(dc, 0, 0);
+ Vector<TCHAR> faceName(faceLength);
+ GetTextFace(dc, faceLength, faceName.data());
+ m_isSystemFont = !_tcscmp(faceName.data(), _T("Lucida Grande"));
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ if (shouldApplyMacAscentHack()) {
+ // This code comes from FontDataMac.mm. We only ever do this when running regression tests so that our metrics will match Mac.
+
+ // We need to adjust Times, Helvetica, and Courier to closely match the
+ // vertical metrics of their Microsoft counterparts that are the de facto
+ // web standard. The AppKit adjustment of 20% is too big and is
+ // incorrectly added to line spacing, so we use a 15% adjustment instead
+ // and add it to the ascent.
+ if (!_tcscmp(faceName.data(), _T("Times")) || !_tcscmp(faceName.data(), _T("Helvetica")) || !_tcscmp(faceName.data(), _T("Courier")))
+ fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f);
+ }
+ }
+
+ m_ascent = lroundf(fAscent);
+ m_descent = lroundf(fDescent);
+ m_lineGap = lroundf(fLineGap);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font.
+ // Unfortunately, NSFont will round this for us so we don't quite get the right value.
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+ Glyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0;
+ if (xGlyph) {
+ CGRect xBox;
+ CGFontGetGlyphBBoxes(font, &xGlyph, 1, &xBox);
+ // Use the maximum of either width or height because "x" is nearly square
+ // and web pages that foolishly use this metric for width will be laid out
+ // poorly if we return an accurate height. Classic case is Times 13 point,
+ // which has an "x" that is 7x6 pixels.
+ m_xHeight = scaleEmToUnits(max(CGRectGetMaxX(xBox), CGRectGetMaxY(xBox)), m_unitsPerEm) * pointSize;
+ } else {
+ int iXHeight = CGFontGetXHeight(font);
+ m_xHeight = scaleEmToUnits(iXHeight, m_unitsPerEm) * pointSize;
+ }
+}
+
+void SimpleFontData::platformDestroy()
+{
+ platformCommonDestroy();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_font.useGDI())
+ return widthForGDIGlyph(glyph);
+
+ CGFontRef font = m_font.cgFont();
+ float pointSize = m_font.size();
+ CGSize advance;
+ CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
+
+ // FIXME: Need to add real support for printer fonts.
+ bool isPrinterFont = false;
+ wkGetGlyphAdvances(font, m, m_isSystemFont, isPrinterFont, glyph, advance);
+
+ return advance.width + m_syntheticBoldOffset;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
new file mode 100644
index 0000000..07d5305
--- /dev/null
+++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ * 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 "SimpleFontData.h"
+
+#include <windows.h>
+
+#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>
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+ 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 * metricsMultiplier;
+ }
+
+ cairo_win32_scaled_font_done_font(scaledFont);
+
+ m_isSystemFont = false;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+}
+
+void SimpleFontData::platformDestroy()
+{
+ 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())
+ 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);
+
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
+
+ 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
new file mode 100644
index 0000000..0e9f9fb
--- /dev/null
+++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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 "SimpleFontData.h"
+
+#include <winsock2.h>
+#include "Font.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include <wtf/MathExtras.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <mlang.h>
+#include <tchar.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+
+namespace WebCore {
+
+using std::max;
+
+const float cSmallCapsFontSizeMultiplier = 0.7f;
+
+static bool g_shouldApplyMacAscentHack;
+
+void SimpleFontData::setShouldApplyMacAscentHack(bool b)
+{
+ g_shouldApplyMacAscentHack = b;
+}
+
+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) {
+ float smallCapsHeight = cSmallCapsFontSizeMultiplier * m_font.size();
+ if (isCustomFont()) {
+ FontPlatformData smallCapsFontData(m_font);
+ smallCapsFontData.setSize(smallCapsHeight);
+ m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false);
+ } else {
+ LOGFONT winfont;
+ 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, m_font.syntheticBold(), m_font.syntheticOblique(), m_font.useGDI()));
+ }
+ }
+ return m_smallCapsFontData;
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ // FIXME: Support custom fonts.
+ if (isCustomFont())
+ return false;
+
+ // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC
+ // merely by testing code page intersection. This seems suspect though. Can't a font only partially
+ // cover a given code page?
+ IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface();
+ if (!langFontLink)
+ return false;
+
+ HDC dc = GetDC(0);
+
+ DWORD acpCodePages;
+ langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
+
+ DWORD fontCodePages;
+ langFontLink->GetFontCodePages(dc, m_font.hfont(), &fontCodePages);
+
+ DWORD actualCodePages;
+ long numCharactersProcessed;
+ long offset = 0;
+ while (offset < length) {
+ langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed);
+ if ((actualCodePages & fontCodePages) == 0)
+ return false;
+ offset += numCharactersProcessed;
+ }
+
+ ReleaseDC(0, dc);
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ if (isCustomFont()) {
+ m_treatAsFixedPitch = false;
+ return;
+ }
+
+ // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ SelectObject(dc, m_font.hfont());
+
+ // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
+ // is *not* fixed pitch. Unbelievable but true.
+ TEXTMETRIC tm;
+ GetTextMetrics(dc, &tm);
+ m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
+
+ RestoreDC(dc, -1);
+ 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) {
+ m_scriptFontProperties = new SCRIPT_FONTPROPERTIES;
+ memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES));
+ m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
+ HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties);
+ if (result == E_PENDING) {
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ SelectObject(dc, m_font.hfont());
+ ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties);
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+ }
+ }
+ return m_scriptFontProperties;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp
new file mode 100644
index 0000000..371bc51
--- /dev/null
+++ b/WebCore/platform/graphics/win/UniscribeController.cpp
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2007 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 "UniscribeController.h"
+#include "Font.h"
+#include "SimpleFontData.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+// FIXME: Rearchitect this to be more like WidthIterator in Font.cpp. Have an advance() method
+// that does stuff in that method instead of doing everything in the constructor. Have advance()
+// take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when
+// measuring.
+UniscribeController::UniscribeController(const Font* font, const TextRun& run)
+: m_font(*font)
+, m_run(run)
+, m_end(run.length())
+, m_currentCharacter(0)
+, m_runWidthSoFar(0)
+, m_computingOffsetPosition(false)
+, m_includePartialGlyphs(false)
+, m_offsetX(0)
+, m_offsetPosition(0)
+{
+ m_padding = m_run.padding();
+ if (!m_padding)
+ m_padPerSpace = 0;
+ else {
+ float numSpaces = 0;
+ for (int s = 0; s < m_run.length(); s++)
+ if (Font::treatAsSpace(m_run[s]))
+ numSpaces++;
+
+ if (numSpaces == 0)
+ m_padPerSpace = 0;
+ else
+ m_padPerSpace = ceilf(m_run.padding() / numSpaces);
+ }
+
+ // Null out our uniscribe structs
+ resetControlAndState();
+}
+
+int UniscribeController::offsetForPosition(int x, bool includePartialGlyphs)
+{
+ m_computingOffsetPosition = true;
+ m_includePartialGlyphs = includePartialGlyphs;
+ m_offsetX = x;
+ m_offsetPosition = 0;
+ advance(m_run.length());
+ if (m_computingOffsetPosition) {
+ // The point is to the left or to the right of the entire run.
+ if (m_offsetX >= m_runWidthSoFar && m_run.ltr() || m_offsetX < 0 && m_run.rtl())
+ m_offsetPosition = m_end;
+ }
+ m_computingOffsetPosition = false;
+ return m_offsetPosition;
+}
+
+void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
+{
+ // FIXME: We really want to be using a newer version of Uniscribe that supports the new OpenType
+ // functions. Those functions would allow us to turn off kerning and ligatures. Without being able
+ // to do that, we will have buggy line breaking and metrics when simple and complex text are close
+ // together (the complex code path will narrow the text because of kerning and ligatures and then
+ // when bidi processing splits into multiple runs, the simple portions will get wider and cause us to
+ // spill off the edge of a line).
+ if (static_cast<int>(offset) > m_end)
+ offset = m_end;
+
+ // Itemize the string.
+ const UChar* cp = m_run.data(m_currentCharacter);
+ int length = offset - m_currentCharacter;
+ if (length <= 0)
+ return;
+
+ unsigned baseCharacter = m_currentCharacter;
+
+ // We break up itemization of the string by fontData and (if needed) the use of small caps.
+
+ // FIXME: It's inconsistent that we use logical order when itemizing, since this
+ // does not match normal RTL.
+
+ // FIXME: This function should decode surrogate pairs. Currently it makes little difference that
+ // it does not because the font cache on Windows does not support non-BMP characters.
+ Vector<UChar, 256> smallCapsBuffer;
+ if (m_font.isSmallCaps())
+ smallCapsBuffer.resize(length);
+
+ unsigned indexOfFontTransition = m_run.rtl() ? length - 1 : 0;
+ const UChar* curr = m_run.rtl() ? cp + length - 1 : cp;
+ const UChar* end = m_run.rtl() ? cp - 1 : cp + length;
+
+ const SimpleFontData* fontData;
+ const SimpleFontData* nextFontData = m_font.glyphDataForCharacter(*curr, false).fontData;
+
+ UChar newC = 0;
+
+ bool isSmallCaps;
+ bool nextIsSmallCaps = m_font.isSmallCaps() && !(U_GET_GC_MASK(*curr) & U_GC_M_MASK) && (newC = u_toupper(*curr)) != *curr;
+
+ if (nextIsSmallCaps)
+ smallCapsBuffer[curr - cp] = newC;
+
+ while (true) {
+ curr = m_run.rtl() ? curr - 1 : curr + 1;
+ if (curr == end)
+ break;
+
+ fontData = nextFontData;
+ isSmallCaps = nextIsSmallCaps;
+ int index = curr - cp;
+ UChar c = *curr;
+
+ bool forceSmallCaps = isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK);
+ nextFontData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps).fontData;
+ if (m_font.isSmallCaps()) {
+ nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c;
+ if (nextIsSmallCaps)
+ smallCapsBuffer[index] = forceSmallCaps ? c : newC;
+ }
+
+ if (nextFontData != fontData || nextIsSmallCaps != isSmallCaps) {
+ int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition;
+ int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition;
+ m_currentCharacter = baseCharacter + itemStart;
+ itemizeShapeAndPlace((isSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, fontData, glyphBuffer);
+ indexOfFontTransition = index;
+ }
+ }
+
+ int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : length - indexOfFontTransition;
+ if (itemLength) {
+ int itemStart = m_run.rtl() ? 0 : indexOfFontTransition;
+ m_currentCharacter = baseCharacter + itemStart;
+ itemizeShapeAndPlace((nextIsSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, nextFontData, glyphBuffer);
+ }
+
+ m_currentCharacter = baseCharacter + length;
+}
+
+void UniscribeController::itemizeShapeAndPlace(const UChar* cp, unsigned length, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer)
+{
+ // ScriptItemize (in Windows XP versions prior to SP2) can overflow by 1. This is why there is an extra empty item
+ // hanging out at the end of the array
+ m_items.resize(6);
+ int numItems = 0;
+ while (ScriptItemize(cp, length, m_items.size() - 1, &m_control, &m_state, m_items.data(), &numItems) == E_OUTOFMEMORY) {
+ m_items.resize(m_items.size() * 2);
+ resetControlAndState();
+ }
+ m_items.resize(numItems + 1);
+
+ if (m_run.rtl()) {
+ for (int i = m_items.size() - 2; i >= 0; i--) {
+ if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer))
+ return;
+ }
+ } else {
+ for (unsigned i = 0; i < m_items.size() - 1; i++) {
+ if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer))
+ return;
+ }
+ }
+}
+
+void UniscribeController::resetControlAndState()
+{
+ memset(&m_control, 0, sizeof(SCRIPT_CONTROL));
+ memset(&m_state, 0, sizeof(SCRIPT_STATE));
+
+ // Set up the correct direction for the run.
+ m_state.uBidiLevel = m_run.rtl();
+
+ // Lock the correct directional override.
+ m_state.fOverrideDirection = m_run.directionalOverride();
+}
+
+bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer)
+{
+ // Determine the string for this item.
+ const UChar* str = cp + m_items[i].iCharPos;
+ int len = m_items[i+1].iCharPos - m_items[i].iCharPos;
+ SCRIPT_ITEM item = m_items[i];
+
+ // Set up buffers to hold the results of shaping the item.
+ Vector<WORD> glyphs;
+ Vector<WORD> clusters;
+ Vector<SCRIPT_VISATTR> visualAttributes;
+ clusters.resize(len);
+
+ // Shape the item.
+ // The recommended size for the glyph buffer is 1.5 * the character length + 16 in the uniscribe docs.
+ // Apparently this is a good size to avoid having to make repeated calls to ScriptShape.
+ glyphs.resize(1.5 * len + 16);
+ visualAttributes.resize(glyphs.size());
+
+ if (!shape(str, len, item, fontData, glyphs, clusters, visualAttributes))
+ return true;
+
+ // We now have a collection of glyphs.
+ Vector<GOFFSET> offsets;
+ Vector<int> advances;
+ offsets.resize(glyphs.size());
+ advances.resize(glyphs.size());
+ int glyphCount = 0;
+ HRESULT placeResult = ScriptPlace(0, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(),
+ &item.a, advances.data(), offsets.data(), 0);
+ if (placeResult == E_PENDING) {
+ // The script cache isn't primed with enough info yet. We need to select our HFONT into
+ // a DC and pass the DC in to ScriptPlace.
+ HDC hdc = GetDC(0);
+ HFONT hfont = fontData->platformData().hfont();
+ HFONT oldFont = (HFONT)SelectObject(hdc, hfont);
+ placeResult = ScriptPlace(hdc, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(),
+ &item.a, advances.data(), offsets.data(), 0);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ }
+
+ if (FAILED(placeResult) || glyphs.isEmpty())
+ return true;
+
+ // Convert all chars that should be treated as spaces to use the space glyph.
+ // We also create a map that allows us to quickly go from space glyphs or rounding
+ // hack glyphs back to their corresponding characters.
+ Vector<int> spaceCharacters(glyphs.size());
+ spaceCharacters.fill(-1);
+ Vector<int> roundingHackCharacters(glyphs.size());
+ roundingHackCharacters.fill(-1);
+ Vector<int> roundingHackWordBoundaries(glyphs.size());
+ roundingHackWordBoundaries.fill(-1);
+
+ const float cLogicalScale = fontData->m_font.useGDI() ? 1.0f : 32.0f;
+ unsigned logicalSpaceWidth = fontData->m_spaceWidth * cLogicalScale;
+ float roundedSpaceWidth = roundf(fontData->m_spaceWidth);
+
+ for (int k = 0; k < len; k++) {
+ UChar ch = *(str + k);
+ if (Font::treatAsSpace(ch)) {
+ // Substitute in the space glyph at the appropriate place in the glyphs
+ // array.
+ glyphs[clusters[k]] = fontData->m_spaceGlyph;
+ advances[clusters[k]] = logicalSpaceWidth;
+ spaceCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos;
+ }
+
+ if (Font::isRoundingHackCharacter(ch))
+ roundingHackCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos;
+
+ int boundary = k + m_currentCharacter + item.iCharPos;
+ if (boundary < m_run.length() &&
+ Font::isRoundingHackCharacter(*(str + k + 1)))
+ roundingHackWordBoundaries[clusters[k]] = boundary;
+ }
+
+ // Populate our glyph buffer with this information.
+ bool hasExtraSpacing = m_font.letterSpacing() || m_font.wordSpacing() || m_padding;
+
+ float leftEdge = m_runWidthSoFar;
+
+ for (unsigned k = 0; k < glyphs.size(); k++) {
+ Glyph glyph = glyphs[k];
+ float advance = advances[k] / cLogicalScale;
+ float offsetX = offsets[k].du / cLogicalScale;
+ float offsetY = offsets[k].dv / cLogicalScale;
+
+ // Match AppKit's rules for the integer vs. non-integer rendering modes.
+ float roundedAdvance = roundf(advance);
+ if (!m_font.isPrinterFont() && !fontData->isSystemFont()) {
+ advance = roundedAdvance;
+ 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
+ // match the width of the space glyph have the same width as the space glyph.
+ if (roundedAdvance == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) &&
+ m_run.applyWordRounding())
+ advance = fontData->m_adjustedSpaceWidth;
+
+ if (hasExtraSpacing) {
+ // If we're a glyph with an advance, go ahead and add in letter-spacing.
+ // That way we weed out zero width lurkers. This behavior matches the fast text code path.
+ if (advance && m_font.letterSpacing())
+ advance += m_font.letterSpacing();
+
+ // Handle justification and word-spacing.
+ if (glyph == fontData->m_spaceGlyph) {
+ // Account for padding. WebCore uses space padding to justify text.
+ // We distribute the specified padding over the available spaces in the run.
+ if (m_padding) {
+ // Use leftover padding if not evenly divisible by number of spaces.
+ if (m_padding < m_padPerSpace) {
+ advance += m_padding;
+ m_padding = 0;
+ } else {
+ advance += m_padPerSpace;
+ m_padding -= m_padPerSpace;
+ }
+ }
+
+ // Account for word-spacing.
+ int characterIndex = spaceCharacters[k];
+ if (characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing())
+ advance += m_font.wordSpacing();
+ }
+ }
+
+ // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters
+ // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
+ // We adjust the width of the last character of a "word" to ensure an integer width.
+ // Force characters that are used to determine word boundaries for the rounding hack
+ // to be integer width, so the following words will start on an integer boundary.
+ int roundingHackIndex = roundingHackCharacters[k];
+ if (m_run.applyWordRounding() && roundingHackIndex != -1)
+ advance = ceilf(advance);
+
+ // Check to see if the next character is a "rounding hack character", if so, adjust the
+ // width so that the total run width will be on an integer boundary.
+ int position = m_currentCharacter + len;
+ bool lastGlyph = (k == glyphs.size() - 1) && (m_run.rtl() ? i == 0 : i == m_items.size() - 2) && (position >= m_end);
+ if ((m_run.applyWordRounding() && roundingHackWordBoundaries[k] != -1) ||
+ (m_run.applyRunRounding() && lastGlyph)) {
+ float totalWidth = m_runWidthSoFar + advance;
+ advance += ceilf(totalWidth) - totalWidth;
+ }
+
+ m_runWidthSoFar += advance;
+
+ // FIXME: We need to take the GOFFSETS for combining glyphs and store them in the glyph buffer
+ // as well, so that when the time comes to draw those glyphs, we can apply the appropriate
+ // translation.
+ if (glyphBuffer) {
+ FloatSize size(offsetX, -offsetY);
+ glyphBuffer->add(glyph, fontData, advance, &size);
+ }
+
+ // Mutate the glyph array to contain our altered advances.
+ if (m_computingOffsetPosition)
+ advances[k] = advance;
+ }
+
+ while (m_computingOffsetPosition && m_offsetX >= leftEdge && m_offsetX < m_runWidthSoFar) {
+ // The position is somewhere inside this run.
+ int trailing = 0;
+ ScriptXtoCP(m_offsetX - leftEdge, clusters.size(), glyphs.size(), clusters.data(), visualAttributes.data(),
+ advances.data(), &item.a, &m_offsetPosition, &trailing);
+ if (trailing && m_includePartialGlyphs && m_offsetPosition < len - 1) {
+ m_offsetPosition += m_currentCharacter + m_items[i].iCharPos;
+ m_offsetX += m_run.rtl() ? -trailing : trailing;
+ } else {
+ m_computingOffsetPosition = false;
+ m_offsetPosition += m_currentCharacter + m_items[i].iCharPos;
+ if (trailing && m_includePartialGlyphs)
+ m_offsetPosition++;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, const SimpleFontData* fontData,
+ Vector<WORD>& glyphs, Vector<WORD>& clusters,
+ Vector<SCRIPT_VISATTR>& visualAttributes)
+{
+ HDC hdc = 0;
+ HFONT oldFont = 0;
+ HRESULT shapeResult = E_PENDING;
+ int glyphCount = 0;
+ do {
+ shapeResult = ScriptShape(hdc, fontData->scriptCache(), str, len, glyphs.size(), &item.a,
+ glyphs.data(), clusters.data(), visualAttributes.data(), &glyphCount);
+ if (shapeResult == E_PENDING) {
+ // The script cache isn't primed with enough info yet. We need to select our HFONT into
+ // a DC and pass the DC in to ScriptShape.
+ ASSERT(!hdc);
+ hdc = GetDC(0);
+ HFONT hfont = fontData->platformData().hfont();
+ oldFont = (HFONT)SelectObject(hdc, hfont);
+ } else if (shapeResult == E_OUTOFMEMORY) {
+ // Need to resize our buffers.
+ glyphs.resize(glyphs.size() * 2);
+ visualAttributes.resize(glyphs.size());
+ }
+ } while (shapeResult == E_PENDING || shapeResult == E_OUTOFMEMORY);
+
+ if (hdc) {
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ }
+
+ if (FAILED(shapeResult))
+ return false;
+
+ glyphs.shrink(glyphCount);
+ visualAttributes.shrink(glyphCount);
+
+ return true;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/UniscribeController.h b/WebCore/platform/graphics/win/UniscribeController.h
new file mode 100644
index 0000000..6ea45e1
--- /dev/null
+++ b/WebCore/platform/graphics/win/UniscribeController.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef UniscribeController_h
+#define UniscribeController_h
+
+#include <usp10.h>
+#include "Font.h"
+#include "GlyphBuffer.h"
+#include "Vector.h"
+
+namespace WebCore {
+
+class UniscribeController {
+public:
+ UniscribeController(const Font*, const TextRun&);
+
+ // Advance and measure/place up to the specified character.
+ void advance(unsigned to, GlyphBuffer* = 0);
+
+ // Compute the character offset for a given x coordinate.
+ int offsetForPosition(int x, bool includePartialGlyphs);
+
+ // Returns the width of everything we've consumed so far.
+ float runWidthSoFar() const { return m_runWidthSoFar; }
+
+private:
+ void resetControlAndState();
+
+ void itemizeShapeAndPlace(const UChar*, unsigned length, const SimpleFontData*, GlyphBuffer*);
+ bool shapeAndPlaceItem(const UChar*, unsigned index, const SimpleFontData*, GlyphBuffer*);
+ bool shape(const UChar* str, int len, SCRIPT_ITEM item, const SimpleFontData* fontData,
+ Vector<WORD>& glyphs, Vector<WORD>& clusters,
+ Vector<SCRIPT_VISATTR>& visualAttributes);
+
+ const Font& m_font;
+ const TextRun& m_run;
+
+ SCRIPT_CONTROL m_control;
+ SCRIPT_STATE m_state;
+ Vector<SCRIPT_ITEM> m_items;
+
+ unsigned m_currentCharacter;
+ int m_end;
+
+ float m_runWidthSoFar;
+ float m_padding;
+ float m_padPerSpace;
+
+ bool m_computingOffsetPosition;
+ bool m_includePartialGlyphs;
+ float m_offsetX;
+ int m_offsetPosition;
+};
+
+}
+#endif