summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/win
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/graphics/win
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/graphics/win')
-rw-r--r--Source/WebCore/platform/graphics/win/FontCGWin.cpp392
-rw-r--r--Source/WebCore/platform/graphics/win/FontCacheWin.cpp603
-rw-r--r--Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp219
-rw-r--r--Source/WebCore/platform/graphics/win/FontCustomPlatformData.h58
-rw-r--r--Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp66
-rw-r--r--Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h54
-rw-r--r--Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp131
-rw-r--r--Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp143
-rw-r--r--Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp95
-rw-r--r--Source/WebCore/platform/graphics/win/FontWin.cpp142
-rw-r--r--Source/WebCore/platform/graphics/win/GDIExtras.cpp43
-rw-r--r--Source/WebCore/platform/graphics/win/GDIExtras.h65
-rw-r--r--Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp59
-rw-r--r--Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp72
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp261
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp169
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp200
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp757
-rw-r--r--Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h139
-rw-r--r--Source/WebCore/platform/graphics/win/IconWin.cpp99
-rw-r--r--Source/WebCore/platform/graphics/win/ImageCGWin.cpp108
-rw-r--r--Source/WebCore/platform/graphics/win/ImageCairoWin.cpp114
-rw-r--r--Source/WebCore/platform/graphics/win/ImageWin.cpp58
-rw-r--r--Source/WebCore/platform/graphics/win/IntPointWin.cpp57
-rw-r--r--Source/WebCore/platform/graphics/win/IntRectWin.cpp45
-rw-r--r--Source/WebCore/platform/graphics/win/IntSizeWin.cpp45
-rw-r--r--Source/WebCore/platform/graphics/win/LocalWindowsContext.h61
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp183
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h82
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp1252
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h211
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp933
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h193
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp65
-rw-r--r--Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h48
-rw-r--r--Source/WebCore/platform/graphics/win/QTCFDictionary.cpp61
-rw-r--r--Source/WebCore/platform/graphics/win/QTCFDictionary.h44
-rw-r--r--Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp170
-rw-r--r--Source/WebCore/platform/graphics/win/QTDecompressionSession.h64
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovie.cpp942
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovie.h125
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp465
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieGWorld.h84
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieTask.cpp105
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieTask.h69
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp223
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieVisualContext.h79
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp137
-rw-r--r--Source/WebCore/platform/graphics/win/QTMovieWinTimer.h39
-rw-r--r--Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp256
-rw-r--r--Source/WebCore/platform/graphics/win/QTPixelBuffer.h100
-rw-r--r--Source/WebCore/platform/graphics/win/QTTrack.cpp119
-rw-r--r--Source/WebCore/platform/graphics/win/QTTrack.h66
-rw-r--r--Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h70
-rw-r--r--Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp161
-rw-r--r--Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp130
-rw-r--r--Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp259
-rw-r--r--Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp46
-rw-r--r--Source/WebCore/platform/graphics/win/UniscribeController.cpp465
-rw-r--r--Source/WebCore/platform/graphics/win/UniscribeController.h90
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp79
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h60
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFLayer.cpp572
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFLayer.h299
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp614
-rw-r--r--Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h129
-rw-r--r--Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp104
-rw-r--r--Source/WebCore/platform/graphics/win/WKCAImageQueue.h92
-rw-r--r--Source/WebCore/platform/graphics/win/WebLayer.cpp143
-rw-r--r--Source/WebCore/platform/graphics/win/WebLayer.h62
-rw-r--r--Source/WebCore/platform/graphics/win/WebTiledLayer.cpp303
-rw-r--r--Source/WebCore/platform/graphics/win/WebTiledLayer.h85
-rw-r--r--Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h114
73 files changed, 14247 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/win/FontCGWin.cpp b/Source/WebCore/platform/graphics/win/FontCGWin.cpp
new file mode 100644
index 0000000..8012722
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 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;
+ TextDrawingModeFlags drawingMode = graphicsContext->textDrawingMode();
+ if (drawingMode == TextModeFill) {
+ if (!fillColor.alpha())
+ return;
+
+ drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer();
+ if (!drawIntoBitmap) {
+ FloatSize offset;
+ float blur;
+ Color color;
+ ColorSpace shadowColorSpace;
+
+ graphicsContext->getShadow(offset, blur, color, shadowColorSpace);
+ drawIntoBitmap = offset.width() || offset.height() || 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->platformData().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 == TextModeFill) {
+ 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->syntheticBoldOffset()) {
+ xform.eM21 = 0;
+ xform.eDx = font->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 {
+ 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;
+ 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()));
+
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
+ CGContextSaveGState(cgContext);
+ CGContextConcatCTM(cgContext, initialGlyphTransform);
+
+ if (drawingMode & TextModeFill) {
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextFillPath(cgContext);
+ if (font->syntheticBoldOffset()) {
+ CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0);
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextFillPath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0);
+ }
+ }
+ if (drawingMode & TextModeStroke) {
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextStrokePath(cgContext);
+ if (font->syntheticBoldOffset()) {
+ CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0);
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextStrokePath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0);
+ }
+ }
+
+ CGContextRestoreGState(cgContext);
+ CGContextTranslateCTM(cgContext, gdiAdvances[i], 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
+{
+ CGContextRef cgContext = graphicsContext->platformContext();
+ bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();
+
+ switch(fontDescription().fontSmoothing()) {
+ case Antialiased: {
+ graphicsContext->setShouldAntialias(true);
+ shouldUseFontSmoothing = false;
+ break;
+ }
+ case SubpixelAntialiased: {
+ graphicsContext->setShouldAntialias(true);
+ shouldUseFontSmoothing = true;
+ break;
+ }
+ case NoSmoothing: {
+ graphicsContext->setShouldAntialias(false);
+ shouldUseFontSmoothing = false;
+ break;
+ }
+ case AutoSmoothing: {
+ // For the AutoSmooth case, don't do anything! Keep the default settings.
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ if (font->platformData().useGDI() && !shouldUseFontSmoothing) {
+ drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
+ return;
+ }
+
+ uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing);
+
+ 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, font->platformData().useGDI());
+
+ FloatSize shadowOffset;
+ float shadowBlur;
+ Color shadowColor;
+ ColorSpace shadowColorSpace;
+ graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+
+ bool hasSimpleShadow = graphicsContext->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && (!graphicsContext->shadowsIgnoreTransforms() || graphicsContext->getCTM().isIdentityOrTranslationOrFlipped());
+ 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, ColorSpaceDeviceRGB);
+ float shadowTextX = point.x() + translation.width() + shadowOffset.width();
+ // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative.
+ float shadowTextY = point.y() + translation.height() + shadowOffset.height() * (graphicsContext->shadowsIgnoreTransforms() ? -1 : 1);
+ CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY);
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->syntheticBoldOffset()) {
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowOffset.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+ graphicsContext->setFillColor(fillColor, ColorSpaceDeviceRGB);
+ }
+
+ CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->syntheticBoldOffset()) {
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+
+ if (hasSimpleShadow)
+ graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB);
+
+ wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp
new file mode 100644
index 0000000..e800245
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -0,0 +1,603 @@
+/*
+ * 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 "UnicodeRange.h"
+#include <mlang.h>
+#include <windows.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.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;
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+static SimpleFontData* fontDataFromDescriptionAndLogFont(FontCache* fontCache, const FontDescription& fontDescription, const LOGFONT& font, AtomicString& outFontFamilyName)
+{
+ AtomicString familyName = String(font.lfFaceName, wcsnlen(font.lfFaceName, LF_FACESIZE));
+ SimpleFontData* fontData = fontCache->getCachedFontData(fontDescription, familyName);
+ if (fontData)
+ outFontFamilyName = familyName;
+ return fontData;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ DEFINE_STATIC_LOCAL(AtomicString, fallbackFontName, ());
+ if (!fallbackFontName.isEmpty())
+ return getCachedFontData(fontDescription, fallbackFontName);
+
+ // 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.
+
+ // Search all typical Windows-installed full Unicode fonts.
+ // Sorted by most to least glyphs according to http://en.wikipedia.org/wiki/Unicode_typefaces
+ // Start with Times New Roman also since it is the default if the user doesn't change prefs.
+ static AtomicString fallbackFonts[] = {
+ AtomicString("Times New Roman"),
+ AtomicString("Microsoft Sans Serif"),
+ AtomicString("Tahoma"),
+ AtomicString("Lucida Sans Unicode"),
+ AtomicString("Arial")
+ };
+ SimpleFontData* simpleFont;
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(fallbackFonts); ++i) {
+ if (simpleFont = getCachedFontData(fontDescription, fallbackFonts[i])) {
+ fallbackFontName = fallbackFonts[i];
+ return simpleFont;
+ }
+ }
+
+ // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available.
+ if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) {
+ LOGFONT defaultGUILogFont;
+ GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont);
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, defaultGUILogFont, fallbackFontName))
+ return simpleFont;
+ }
+
+ // Fall back to Non-client metrics fonts.
+ NONCLIENTMETRICS nonClientMetrics = {0};
+ nonClientMetrics.cbSize = sizeof(nonClientMetrics);
+ if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) {
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfMessageFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfMenuFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfStatusFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfCaptionFont, fallbackFontName))
+ return simpleFont;
+ if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfSmCaptionFont, fallbackFontName))
+ return simpleFont;
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+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, bool synthesizeItalic)
+{
+ 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;
+
+ if (desiredItalic && !matchData.m_chosen.lfItalic && synthesizeItalic)
+ matchData.m_chosen.lfItalic = 1;
+
+ HFONT result = CreateFontIndirect(&matchData.m_chosen);
+ if (!result)
+ return 0;
+
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ SelectObject(dc, result);
+ WCHAR actualName[LF_FACESIZE];
+ GetTextFace(dc, LF_FACESIZE, actualName);
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+
+ if (wcsicmp(matchData.m_chosen.lfFaceName, actualName)) {
+ DeleteObject(result);
+ result = 0;
+ }
+
+ return result;
+}
+
+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), useGDI);
+
+ 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/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..9cae99b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "WOFFFileFormat.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.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()
+{
+ 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, FontOrientation, FontRenderingMode renderingMode)
+{
+ ASSERT(m_fontReference);
+ ASSERT(T2embedLibrary());
+
+ LOGFONT& logFont = *static_cast<LOGFONT*>(malloc(sizeof(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);
+
+ RetainPtr<CGFontRef> cgFont(AdoptCF, CGFontCreateWithPlatformFont(&logFont));
+ return FontPlatformData(hfont, cgFont.get(), size, bold, italic, renderingMode == AlternateRenderingMode);
+}
+
+// Streams the concatenation of a header and font data.
+class EOTStream {
+public:
+ EOTStream(const EOTHeader& 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 EOTHeader& 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());
+
+ RefPtr<SharedBuffer> sfntBuffer;
+ if (isWOFF(buffer)) {
+ Vector<char> sfnt;
+ if (!convertWOFFToSfnt(buffer, sfnt))
+ return 0;
+
+ sfntBuffer = SharedBuffer::adoptVector(sfnt);
+ buffer = sfntBuffer.get();
+ }
+
+ // 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.
+ EOTHeader eotHeader;
+ size_t overlayDst;
+ size_t overlaySrc;
+ size_t overlayLength;
+ if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength))
+ 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)
+ return 0;
+ }
+
+ return new FontCustomPlatformData(fontReference, fontName);
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype") || equalIgnoringCase(format, "woff");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h
new file mode 100644
index 0000000..1bdf270
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformData.h
@@ -0,0 +1,58 @@
+/*
+ * 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 "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+typedef struct CGFont* CGFontRef;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(HANDLE fontReference, const String& name)
+ : m_fontReference(fontReference)
+ , m_name(name)
+ {
+ }
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+
+ static bool supportsFormat(const String&);
+
+ HANDLE m_fontReference;
+ String m_name;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
new file mode 100644
index 0000000..c3decbf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation)
+{
+ return FontPlatformData(m_fontFace, size, bold, italic);
+}
+
+static void releaseData(void* data)
+{
+ static_cast<SharedBuffer*>(data)->deref();
+}
+
+FontCustomPlatformData* 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 FontCustomPlatformData(fontFace);
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
new file mode 100644
index 0000000..3ab52b8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ * Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org>
+ *
+ * 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 "FontDescription.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+#include <cairo.h>
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(cairo_font_face_t* fontFace)
+ : m_fontFace(fontFace)
+ {
+ }
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal);
+
+ static bool supportsFormat(const String&);
+
+ cairo_font_face_t* m_fontFace;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
new file mode 100644
index 0000000..9234229
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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, 2009 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 <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.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)
+{
+ LOGFONT logfont;
+ GetObject(font, sizeof(logfont), &logfont);
+ m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&logfont));
+}
+
+FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI)
+ : m_font(RefCountedGDIHandle<HFONT>::create(hfont))
+ , m_size(size)
+ , m_cgFont(font)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(useGDI)
+{
+}
+
+FontPlatformData::~FontPlatformData()
+{
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
new file mode 100644
index 0000000..0f5c365
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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, 2010 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 <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+#include <cairo-win32.h>
+
+using namespace std;
+
+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);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& source)
+ : m_font(source.m_font)
+ , m_size(source.m_size)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+ , m_syntheticBold(source.m_syntheticBold)
+ , m_syntheticOblique(source.m_syntheticOblique)
+ , m_useGDI(source.m_useGDI)
+{
+ if (source.m_fontFace)
+ m_fontFace = cairo_font_face_reference(source.m_fontFace);
+
+ if (source.m_scaledFont)
+ m_scaledFont = cairo_scaled_font_reference(source.m_scaledFont);
+}
+
+
+FontPlatformData::~FontPlatformData()
+{
+ cairo_scaled_font_destroy(m_scaledFont);
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_font = other.m_font;
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+ m_useGDI = other.m_useGDI;
+
+ if (other.m_fontFace)
+ cairo_font_face_reference(other.m_fontFace);
+ if (m_fontFace)
+ cairo_font_face_destroy(m_fontFace);
+ m_fontFace = other.m_fontFace;
+
+ if (other.m_scaledFont)
+ cairo_scaled_font_reference(other.m_scaledFont);
+ if (m_scaledFont)
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = other.m_scaledFont;
+
+ return *this;
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& other) const
+{
+ return m_font == other.m_font
+ && m_fontFace == other.m_fontFace
+ && m_scaledFont == other.m_scaledFont
+ && m_size == other.m_size
+ && m_syntheticBold == other.m_syntheticBold
+ && m_syntheticOblique == other.m_syntheticOblique
+ && m_useGDI == other.m_useGDI;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
new file mode 100644
index 0000000..09ed4a6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+using std::min;
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI)
+ : m_font(RefCountedGDIHandle<HFONT>::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)
+{
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/win/FontWin.cpp b/Source/WebCore/platform/graphics/win/FontWin.cpp
new file mode 100644
index 0000000..2170954
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/FontWin.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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 "Logging.h"
+#include "SimpleFontData.h"
+#include "UniscribeController.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return true;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& 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);
+}
+
+float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
+{
+ if (forTextEmphasis) {
+ // FIXME: Add forTextEmphasis paremeter to UniscribeController and use it.
+ LOG_ERROR("Not implemented for text emphasis.");
+ return 0;
+ }
+
+ UniscribeController controller(this, run);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to, &glyphBuffer);
+
+ if (glyphBuffer.isEmpty())
+ return 0;
+
+ float afterWidth = controller.runWidthSoFar();
+
+ if (run.rtl()) {
+ controller.advance(run.length());
+ return controller.runWidthSoFar() - afterWidth;
+ }
+ return beforeWidth;
+}
+
+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() + getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer);
+
+ // We couldn't generate any glyphs for the run. Give up.
+ if (glyphBuffer.isEmpty())
+ return;
+
+ // Draw the glyph buffer now at the starting point returned in startX.
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, startPoint);
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
+{
+ GlyphBuffer glyphBuffer;
+ float initialAdvance = getGlyphsAndAdvancesForComplexText(run, from, to, glyphBuffer, ForTextEmphasis);
+
+ if (glyphBuffer.isEmpty())
+ return;
+
+ drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+ UniscribeController controller(this, run, fallbackFonts);
+ controller.advance(run.length());
+ if (glyphOverflow) {
+ glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent());
+ glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent());
+ glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX()));
+ glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.runWidthSoFar()));
+ }
+ return controller.runWidthSoFar();
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const
+{
+ // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
+ // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
+ int x = static_cast<int>(xFloat);
+
+ UniscribeController controller(this, run);
+ return controller.offsetForPosition(x, includePartialGlyphs);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GDIExtras.cpp b/Source/WebCore/platform/graphics/win/GDIExtras.cpp
new file mode 100644
index 0000000..4bd95da
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GDIExtras.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * 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 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 "GDIExtras.h"
+
+#include "SoftLinking.h"
+
+namespace WebCore {
+
+#if OS(WINCE)
+SOFT_LINK_LIBRARY(coredll)
+SOFT_LINK_OPTIONAL(coredll, AlphaBlend, BOOL, APIENTRY, (HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc,
+ int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction))
+
+AlphaBlendPointerType AlphaBlendPointer()
+{
+ return AlphaBlendPtr();
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/win/GDIExtras.h b/Source/WebCore/platform/graphics/win/GDIExtras.h
new file mode 100644
index 0000000..0166124
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GDIExtras.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
+ *
+ * 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 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 GDIExtras_h
+#define GDIExtras_h
+
+#include <windows.h>
+
+namespace WebCore {
+
+typedef BOOL (APIENTRY *AlphaBlendPointerType) (HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc,
+ int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction);
+
+#if OS(WINCE)
+AlphaBlendPointerType AlphaBlendPointer();
+#endif
+
+inline bool hasAlphaBlendSupport()
+{
+#if OS(WINCE)
+ return AlphaBlendPointer();
+#else
+ return true;
+#endif
+}
+
+inline bool alphaBlendIfSupported(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc,
+ int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction)
+{
+#if OS(WINCE)
+ AlphaBlendPointerType alphaBlendPointer = AlphaBlendPointer();
+ if (!alphaBlendPointer)
+ return false;
+
+ alphaBlendPointer(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, blendFunction);
+#else
+ AlphaBlend(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, blendFunction);
+#endif
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // GDIExtras_h
diff --git a/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp b/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
new file mode 100644
index 0000000..c11fc1b
--- /dev/null
+++ b/Source/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/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp b/Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
new file mode 100644
index 0000000..b679ced
--- /dev/null
+++ b/Source/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/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
new file mode 100644
index 0000000..d3c6b58
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010 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 "GraphicsContextCG.h"
+
+#include "AffineTransform.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));
+ BITMAP info;
+
+ GetObject(bitmap, sizeof(info), &info);
+
+ // FIXME: We can get here because we asked for a bitmap that is too big
+ // when we have a tiled layer and we're compositing. In that case
+ // bmBitsPixel will be 0. This seems to be benign, so for now we will
+ // exit gracefully and look at it later:
+ // https://bugs.webkit.org/show_bug.cgi?id=52041
+ // ASSERT(info.bmBitsPixel == 32);
+ if (info.bmBitsPixel != 32)
+ return 0;
+
+ CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | (hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst);
+ CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, deviceRGBColorSpaceRef(), bitmapInfo);
+
+ // 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_updatingControlTints(false)
+{
+ platformInit(hdc, hasAlpha);
+}
+
+void GraphicsContext::platformInit(HDC hdc, bool hasAlpha)
+{
+ m_data = new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha));
+ CGContextRelease(m_data->m_cgContext.get());
+ 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(), ColorSpaceDeviceRGB);
+ setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB);
+ }
+}
+
+// FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into a single API
+// suitable for all clients?
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer());
+ if (!createdBitmap) {
+ m_data->restore();
+ return;
+ }
+
+ 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);
+
+ CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little |
+ (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst));
+
+ CGImageRef image = CGBitmapContextCreateImage(bitmapContext);
+ CGContextDrawImage(m_data->m_cgContext.get(), dstRect, image);
+
+ // Delete all our junk.
+ CGImageRelease(image);
+ CGContextRelease(bitmapContext);
+ ::DeleteDC(hdc);
+ ::DeleteObject(bitmap);
+}
+
+void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point)
+{
+ // FIXME: Creating CFData is non-optimal, but needed to avoid crashing when printing. Ideally we should
+ // make a custom CGDataProvider that controls the WindowsBitmap lifetime. see <rdar://6394455>
+ RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreate(kCFAllocatorDefault, image->buffer(), image->bufferLength()));
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(imageData.get()));
+ RetainPtr<CGImageRef> cgImage(AdoptCF, CGImageCreate(image->size().width(), image->size().height(), 8, 32, image->bytesPerRow(), deviceRGBColorSpaceRef(),
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst, dataProvider.get(), 0, true, kCGRenderingIntentDefault));
+ CGContextDrawImage(m_data->m_cgContext.get(), CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get());
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+// FIXME: This is nearly identical to the GraphicsContext::drawFocusRing function in GraphicsContextMac.mm.
+// The code could move to GraphicsContextCG.cpp and be shared.
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ float radius = (width - 1) / 2.0f;
+ offset += radius;
+ CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0;
+
+ CGMutablePathRef focusRingPath = CGPathCreateMutable();
+ 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);
+
+ 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::drawLineForTextChecking(const IntPoint& point, int width, TextCheckingLineStyle style)
+{
+ if (paintingDisabled())
+ return;
+
+ if (style != TextCheckingSpellingLineStyle && style != TextCheckingGrammarLineStyle)
+ 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 = style == TextCheckingGrammarLineStyle ? 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, WTF_ARRAY_LENGTH(edge_dash_lengths));
+ CGContextSetAlpha(context, upperOpacity);
+ CGContextStrokeLineSegments(context, upperPoints, 2);
+
+ // Middle line
+ CGContextSetLineDash(context, middle_offset, middle_dash_lengths, WTF_ARRAY_LENGTH(middle_dash_lengths));
+ CGContextSetAlpha(context, middleOpacity);
+ CGContextStrokeLineSegments(context, middlePoints, 2);
+
+ // Bottom line
+ CGContextSetLineDash(context, edge_offset, edge_dash_lengths, WTF_ARRAY_LENGTH(edge_dash_lengths));
+ CGContextSetAlpha(context, lowerOpacity);
+ CGContextStrokeLineSegments(context, lowerPoints, 2);
+
+ CGContextRestoreGState(context);
+}
+
+void GraphicsContextPlatformPrivate::flush()
+{
+ CGContextFlush(m_cgContext.get());
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
new file mode 100644
index 0000000..b2c702f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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 "Path.h"
+
+#include <cairo-win32.h>
+#include "GraphicsContextPlatformPrivateCairo.h"
+
+using namespace std;
+
+namespace WebCore {
+
+static cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha)
+{
+ // Put the HDC In advanced mode so it will honor affine transforms.
+ SetGraphicsMode(hdc, GM_ADVANCED);
+
+ cairo_surface_t* surface = 0;
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+
+ BITMAP info;
+ if (!GetObject(bitmap, sizeof(info), &info))
+ surface = cairo_win32_surface_create(hdc);
+ else {
+ ASSERT(info.bmBitsPixel == 32);
+
+ surface = cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
+ CAIRO_FORMAT_ARGB32,
+ info.bmWidth,
+ info.bmHeight,
+ info.bmWidthBytes);
+ }
+
+ cairo_t* context = cairo_create(surface);
+ cairo_surface_destroy(surface);
+
+ return context;
+}
+
+GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
+ : m_updatingControlTints(false)
+{
+ platformInit(dc, hasAlpha);
+}
+
+void GraphicsContext::platformInit(HDC dc, bool hasAlpha)
+{
+ m_data = new GraphicsContextPlatformPrivate;
+
+ if (dc) {
+ m_data->cr = createCairoContextWithHDC(dc, hasAlpha);
+ 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(), fillColorSpace());
+ setPlatformStrokeColor(strokeColor(), strokeColorSpace());
+ }
+}
+
+static void setRGBABitmapAlpha(unsigned char* bytes, size_t length, unsigned char level)
+{
+ for (size_t i = 0; i < length; i += 4)
+ bytes[i + 3] = level;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer());
+ if (!hdc || !createdBitmap) {
+ m_data->restore();
+ return;
+ }
+
+ if (dstRect.isEmpty())
+ return;
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ // If this context does not support alpha blending, then it may have
+ // been drawn with GDI functions which always set the alpha channel
+ // to zero. We need to manually set the bitmap to be fully opaque.
+ unsigned char* bytes = reinterpret_cast<unsigned char*>(info.bmBits);
+ if (!supportAlphaBlend)
+ setRGBABitmapAlpha(bytes, info.bmHeight * info.bmWidthBytes, 255);
+
+ // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw
+ // it into our context.
+ cairo_surface_t* image = cairo_image_surface_create_for_data(bytes,
+ CAIRO_FORMAT_ARGB32,
+ info.bmWidth,
+ info.bmHeight,
+ info.bmWidthBytes);
+
+ // Scale the target surface to the new image size, and flip it
+ // so that when we set the srcImage as the surface it will draw
+ // right-side-up.
+ cairo_save(m_data->cr);
+ cairo_translate(m_data->cr, dstRect.x(), dstRect.height() + dstRect.y());
+ cairo_scale(m_data->cr, 1.0, -1.0);
+ cairo_set_source_surface(m_data->cr, image, 0, 0);
+
+ if (m_data->layers.size())
+ cairo_paint_with_alpha(m_data->cr, m_data->layers.last());
+ else
+ cairo_paint(m_data->cr);
+
+ // Delete all our junk.
+ cairo_surface_destroy(image);
+ ::DeleteDC(hdc);
+ ::DeleteObject(bitmap);
+ cairo_restore(m_data->cr);
+}
+
+void GraphicsContextPlatformPrivate::syncContext(PlatformGraphicsContext* cr)
+{
+ if (!cr)
+ return;
+
+ cairo_surface_t* surface = cairo_get_target(cr);
+ m_hdc = cairo_win32_surface_get_dc(surface);
+
+ SetGraphicsMode(m_hdc, GM_ADVANCED); // We need this call for themes to honor world transforms.
+}
+
+void GraphicsContextPlatformPrivate::flush()
+{
+ cairo_surface_t* surface = cairo_win32_surface_create(m_hdc);
+ cairo_surface_flush(surface);
+ cairo_surface_destroy(surface);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp
new file mode 100644
index 0000000..f1953e4
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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 "BitmapInfo.h"
+#include "TransformationMatrix.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+static void fillWithClearColor(HBITMAP bitmap)
+{
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+}
+
+bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
+
+void GraphicsContext::setShouldIncludeChildWindows(bool include)
+{
+ m_data->m_shouldIncludeChildWindows = include;
+}
+
+bool GraphicsContext::shouldIncludeChildWindows() const
+{
+ return m_data->m_shouldIncludeChildWindows;
+}
+
+GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
+ : m_hdc(0)
+ , m_size(size)
+{
+ BitmapInfo bitmapInfo = BitmapInfo::create(m_size);
+
+ 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);
+}
+
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // FIXME: Should a bitmap be created also when a shadow is set?
+ if (mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer())) {
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BitmapInfo bitmapInfo = BitmapInfo::create(dstRect.size());
+
+ 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)
+ fillWithClearColor(bitmap);
+
+ // 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 = TransformationMatrix().translate(-dstRect.x(), -dstRect.y());
+
+ ::SetWorldTransform(bitmapDC, &xform);
+
+ return bitmapDC;
+ }
+
+ m_data->flush();
+ m_data->save();
+ return m_data->m_hdc;
+}
+
+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 = TransformationMatrix().scaleNonUniform(size.width(), size.height());
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
+{
+ XFORM xform = TransformationMatrix().rotate(degreesAngle);
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContextPlatformPrivate::translate(float x , float y)
+{
+ if (!m_hdc)
+ return;
+
+ XFORM xform = TransformationMatrix().translate(x, y);
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
+{
+ if (!m_hdc)
+ return;
+
+ XFORM xform = transform.toTransformationMatrix();
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
new file mode 100644
index 0000000..984fd3f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
@@ -0,0 +1,757 @@
+/*
+ * Copyright (C) 2009 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 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 USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayerCACF.h"
+
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "Font.h"
+#include "FontSelector.h"
+#include "Image.h"
+#include "PlatformString.h"
+#include "SystemTime.h"
+#include "WebLayer.h"
+#include "WebTiledLayer.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/StringExtras.h>
+#include <wtf/text/CString.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// The threshold width or height above which a tiled layer will be used. This should be
+// large enough to avoid tiled layers for most GraphicsLayers, but less than the D3D
+// texture size limit on all supported hardware.
+static const int cMaxPixelDimension = 2000;
+
+// The width and height of a single tile in a tiled layer. Should be large enough to
+// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
+// to keep the overall tile cost low.
+static const int cTiledLayerTileSize = 512;
+
+static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t)
+{
+ toT3D.m11 = narrowPrecisionToFloat(t.m11());
+ toT3D.m12 = narrowPrecisionToFloat(t.m12());
+ toT3D.m13 = narrowPrecisionToFloat(t.m13());
+ toT3D.m14 = narrowPrecisionToFloat(t.m14());
+ toT3D.m21 = narrowPrecisionToFloat(t.m21());
+ toT3D.m22 = narrowPrecisionToFloat(t.m22());
+ toT3D.m23 = narrowPrecisionToFloat(t.m23());
+ toT3D.m24 = narrowPrecisionToFloat(t.m24());
+ toT3D.m31 = narrowPrecisionToFloat(t.m31());
+ toT3D.m32 = narrowPrecisionToFloat(t.m32());
+ toT3D.m33 = narrowPrecisionToFloat(t.m33());
+ toT3D.m34 = narrowPrecisionToFloat(t.m34());
+ toT3D.m41 = narrowPrecisionToFloat(t.m41());
+ toT3D.m42 = narrowPrecisionToFloat(t.m42());
+ toT3D.m43 = narrowPrecisionToFloat(t.m43());
+ toT3D.m44 = narrowPrecisionToFloat(t.m44());
+}
+
+TransformationMatrix CAToTransform3D(const CATransform3D& fromT3D)
+{
+ return TransformationMatrix(
+ fromT3D.m11,
+ fromT3D.m12,
+ fromT3D.m13,
+ fromT3D.m14,
+ fromT3D.m21,
+ fromT3D.m22,
+ fromT3D.m23,
+ fromT3D.m24,
+ fromT3D.m31,
+ fromT3D.m32,
+ fromT3D.m33,
+ fromT3D.m34,
+ fromT3D.m41,
+ fromT3D.m42,
+ fromT3D.m43,
+ fromT3D.m44);
+}
+
+static void setLayerBorderColor(WKCACFLayer* layer, const Color& color)
+{
+ layer->setBorderColor(cachedCGColor(color, ColorSpaceDeviceRGB));
+}
+
+static void clearBorderColor(WKCACFLayer* layer)
+{
+ layer->setBorderColor(0);
+}
+
+static void setLayerBackgroundColor(WKCACFLayer* layer, const Color& color)
+{
+ layer->setBackgroundColor(cachedCGColor(color, ColorSpaceDeviceRGB));
+}
+
+static void clearLayerBackgroundColor(WKCACFLayer* layer)
+{
+ layer->setBackgroundColor(0);
+}
+
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerCACF(client);
+}
+
+GraphicsLayerCACF::GraphicsLayerCACF(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_contentsLayerPurpose(NoContentsLayer)
+ , m_contentsLayerHasBackgroundColor(false)
+{
+ m_layer = WebLayer::create(WKCACFLayer::Layer, this);
+
+ updateDebugIndicators();
+}
+
+GraphicsLayerCACF::~GraphicsLayerCACF()
+{
+ // clean up the WK layer
+ if (m_layer)
+ m_layer->removeFromSuperlayer();
+
+ if (m_contentsLayer)
+ m_contentsLayer->removeFromSuperlayer();
+
+ if (m_transformLayer)
+ m_transformLayer->removeFromSuperlayer();
+}
+
+void GraphicsLayerCACF::setName(const String& name)
+{
+ String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
+ GraphicsLayer::setName(longName);
+
+ m_layer->setName(longName);
+}
+
+bool GraphicsLayerCACF::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ bool childrenChanged = GraphicsLayer::setChildren(children);
+ // FIXME: GraphicsLayer::setChildren calls addChild() for each sublayer, which
+ // will end up calling updateSublayerList() N times.
+ if (childrenChanged)
+ updateSublayerList();
+
+ return childrenChanged;
+}
+
+void GraphicsLayerCACF::addChild(GraphicsLayer* childLayer)
+{
+ GraphicsLayer::addChild(childLayer);
+ updateSublayerList();
+}
+
+void GraphicsLayerCACF::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ GraphicsLayer::addChildAtIndex(childLayer, index);
+ updateSublayerList();
+}
+
+void GraphicsLayerCACF::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildBelow(childLayer, sibling);
+ updateSublayerList();
+}
+
+void GraphicsLayerCACF::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer *sibling)
+{
+ GraphicsLayer::addChildAbove(childLayer, sibling);
+ updateSublayerList();
+}
+
+bool GraphicsLayerCACF::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ updateSublayerList();
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayerCACF::removeFromParent()
+{
+ GraphicsLayer::removeFromParent();
+ layerForSuperlayer()->removeFromSuperlayer();
+}
+
+void GraphicsLayerCACF::setPosition(const FloatPoint& point)
+{
+ GraphicsLayer::setPosition(point);
+ updateLayerPosition();
+}
+
+void GraphicsLayerCACF::setAnchorPoint(const FloatPoint3D& point)
+{
+ if (point == m_anchorPoint)
+ return;
+
+ GraphicsLayer::setAnchorPoint(point);
+ updateAnchorPoint();
+}
+
+void GraphicsLayerCACF::setSize(const FloatSize& size)
+{
+ if (size == m_size)
+ return;
+
+ GraphicsLayer::setSize(size);
+ updateLayerSize();
+}
+
+void GraphicsLayerCACF::setTransform(const TransformationMatrix& t)
+{
+ if (t == m_transform)
+ return;
+
+ GraphicsLayer::setTransform(t);
+ updateTransform();
+}
+
+void GraphicsLayerCACF::setChildrenTransform(const TransformationMatrix& t)
+{
+ if (t == m_childrenTransform)
+ return;
+
+ GraphicsLayer::setChildrenTransform(t);
+ updateChildrenTransform();
+}
+
+void GraphicsLayerCACF::setPreserves3D(bool preserves3D)
+{
+ if (preserves3D == m_preserves3D)
+ return;
+
+ GraphicsLayer::setPreserves3D(preserves3D);
+ updateLayerPreserves3D();
+}
+
+void GraphicsLayerCACF::setMasksToBounds(bool masksToBounds)
+{
+ if (masksToBounds == m_masksToBounds)
+ return;
+
+ GraphicsLayer::setMasksToBounds(masksToBounds);
+ updateMasksToBounds();
+}
+
+void GraphicsLayerCACF::setDrawsContent(bool drawsContent)
+{
+ if (drawsContent == m_drawsContent)
+ return;
+
+ GraphicsLayer::setDrawsContent(drawsContent);
+ updateLayerDrawsContent();
+}
+
+void GraphicsLayerCACF::setBackgroundColor(const Color& color)
+{
+ if (m_backgroundColorSet && m_backgroundColor == color)
+ return;
+
+ GraphicsLayer::setBackgroundColor(color);
+
+ m_contentsLayerHasBackgroundColor = true;
+ updateLayerBackgroundColor();
+}
+
+void GraphicsLayerCACF::clearBackgroundColor()
+{
+ if (!m_backgroundColorSet)
+ return;
+
+ GraphicsLayer::clearBackgroundColor();
+ clearLayerBackgroundColor(m_contentsLayer.get());
+}
+
+void GraphicsLayerCACF::setContentsOpaque(bool opaque)
+{
+ if (m_contentsOpaque == opaque)
+ return;
+
+ GraphicsLayer::setContentsOpaque(opaque);
+ updateContentsOpaque();
+}
+
+void GraphicsLayerCACF::setBackfaceVisibility(bool visible)
+{
+ if (m_backfaceVisibility == visible)
+ return;
+
+ GraphicsLayer::setBackfaceVisibility(visible);
+ updateBackfaceVisibility();
+}
+
+void GraphicsLayerCACF::setOpacity(float opacity)
+{
+ float clampedOpacity = max(min(opacity, 1.0f), 0.0f);
+
+ if (m_opacity == clampedOpacity)
+ return;
+
+ GraphicsLayer::setOpacity(clampedOpacity);
+ primaryLayer()->setOpacity(opacity);
+}
+
+void GraphicsLayerCACF::setNeedsDisplay()
+{
+ if (drawsContent())
+ m_layer->setNeedsDisplay();
+}
+
+void GraphicsLayerCACF::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ if (drawsContent()) {
+ CGRect cgRect = rect;
+ m_layer->setNeedsDisplay(&cgRect);
+ }
+}
+
+void GraphicsLayerCACF::setContentsRect(const IntRect& rect)
+{
+ if (rect == m_contentsRect)
+ return;
+
+ GraphicsLayer::setContentsRect(rect);
+ updateContentsRect();
+}
+
+void GraphicsLayerCACF::setContentsToImage(Image* image)
+{
+ bool childrenChanged = false;
+
+ if (image) {
+ m_pendingContentsImage = image->nativeImageForCurrentFrame();
+ m_contentsLayerPurpose = ContentsLayerForImage;
+ if (!m_contentsLayer)
+ childrenChanged = true;
+ } else {
+ m_pendingContentsImage = 0;
+ m_contentsLayerPurpose = NoContentsLayer;
+ if (m_contentsLayer)
+ childrenChanged = true;
+ }
+
+ updateContentsImage();
+
+ // This has to happen after updateContentsImage
+ if (childrenChanged)
+ updateSublayerList();
+}
+
+void GraphicsLayerCACF::setContentsToMedia(PlatformLayer* mediaLayer)
+{
+ if (mediaLayer == m_contentsLayer)
+ return;
+
+ m_contentsLayer = mediaLayer;
+ m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer;
+
+ updateContentsMedia();
+
+ // This has to happen after updateContentsMedia
+ updateSublayerList();
+}
+
+PlatformLayer* GraphicsLayerCACF::hostLayerForSublayers() const
+{
+ return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerCACF::layerForSuperlayer() const
+{
+ return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerCACF::platformLayer() const
+{
+ return primaryLayer();
+}
+
+void GraphicsLayerCACF::setDebugBackgroundColor(const Color& color)
+{
+ if (color.isValid())
+ setLayerBackgroundColor(m_layer.get(), color);
+ else
+ clearLayerBackgroundColor(m_layer.get());
+}
+
+void GraphicsLayerCACF::setDebugBorder(const Color& color, float borderWidth)
+{
+ if (color.isValid()) {
+ setLayerBorderColor(m_layer.get(), color);
+ m_layer->setBorderWidth(borderWidth);
+ } else {
+ clearBorderColor(m_layer.get());
+ m_layer->setBorderWidth(0);
+ }
+}
+
+bool GraphicsLayerCACF::requiresTiledLayer(const FloatSize& size) const
+{
+ if (!m_drawsContent)
+ return false;
+
+ // FIXME: catch zero-size height or width here (or earlier)?
+ return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
+}
+
+void GraphicsLayerCACF::swapFromOrToTiledLayer(bool useTiledLayer)
+{
+ if (useTiledLayer == m_usingTiledLayer)
+ return;
+
+ CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
+
+ RefPtr<WKCACFLayer> oldLayer = m_layer;
+ if (useTiledLayer)
+ m_layer = WebTiledLayer::create(tileSize, this);
+ else
+ m_layer = WebLayer::create(WKCACFLayer::Layer, this);
+
+ m_usingTiledLayer = useTiledLayer;
+
+ m_layer->adoptSublayers(oldLayer.get());
+ if (oldLayer->superlayer())
+ oldLayer->superlayer()->replaceSublayer(oldLayer.get(), m_layer.get());
+
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+ updateMasksToBounds();
+ updateContentsOpaque();
+ updateBackfaceVisibility();
+ updateLayerBackgroundColor();
+
+ updateOpacityOnLayer();
+
+#ifndef NDEBUG
+ String name = String::format("CALayer(%p) GraphicsLayer(%p) %s", m_layer.get(), this, m_usingTiledLayer ? "[Tiled Layer] " : "") + m_name;
+ m_layer->setName(name);
+#endif
+
+ // need to tell new layer to draw itself
+ setNeedsDisplay();
+
+ updateDebugIndicators();
+}
+
+GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCACF::defaultContentsOrientation() const
+{
+ return CompositingCoordinatesTopDown;
+}
+
+void GraphicsLayerCACF::updateSublayerList()
+{
+ Vector<RefPtr<WKCACFLayer> > newSublayers;
+
+ if (m_transformLayer) {
+ // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind.
+ newSublayers.append(m_layer.get());
+ } else if (m_contentsLayer) {
+ // FIXME: add the contents layer in the correct order with negative z-order children.
+ // This does not cause visible rendering issues because currently contents layers are only used
+ // for replaced elements that don't have children.
+ newSublayers.append(m_contentsLayer.get());
+ }
+
+ const Vector<GraphicsLayer*>& childLayers = children();
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCACF* curChild = static_cast<GraphicsLayerCACF*>(childLayers[i]);
+
+ WKCACFLayer* childLayer = curChild->layerForSuperlayer();
+ newSublayers.append(childLayer);
+ }
+
+ for (int i = 0; i < newSublayers.size(); ++i)
+ newSublayers[i]->removeFromSuperlayer();
+
+ if (m_transformLayer) {
+ m_transformLayer->setSublayers(newSublayers);
+
+ if (m_contentsLayer) {
+ // If we have a transform layer, then the contents layer is parented in the
+ // primary layer (which is itself a child of the transform layer).
+ m_layer->removeAllSublayers();
+ m_layer->addSublayer(m_contentsLayer);
+ }
+ } else
+ m_layer->setSublayers(newSublayers);
+}
+
+void GraphicsLayerCACF::updateLayerPosition()
+{
+ // Position is offset on the layer by the layer anchor point.
+ CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
+ m_position.y() + m_anchorPoint.y() * m_size.height());
+
+ primaryLayer()->setPosition(posPoint);
+}
+
+void GraphicsLayerCACF::updateLayerSize()
+{
+ CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height());
+ if (m_transformLayer) {
+ m_transformLayer->setBounds(rect);
+ // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
+ CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ m_layer->setPosition(centerPoint);
+ }
+
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ m_layer->setBounds(rect);
+
+ // Note that we don't resize m_contentsLayer. It's up the caller to do that.
+
+ // if we've changed the bounds, we need to recalculate the position
+ // of the layer, taking anchor point into account.
+ updateLayerPosition();
+}
+
+void GraphicsLayerCACF::updateAnchorPoint()
+{
+ primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y()));
+ primaryLayer()->setAnchorPointZ(m_anchorPoint.z());
+ updateLayerPosition();
+}
+
+void GraphicsLayerCACF::updateTransform()
+{
+ CATransform3D transform;
+ copyTransform(transform, m_transform);
+ primaryLayer()->setTransform(transform);
+}
+
+void GraphicsLayerCACF::updateChildrenTransform()
+{
+ CATransform3D transform;
+ copyTransform(transform, m_childrenTransform);
+ primaryLayer()->setSublayerTransform(transform);
+}
+
+void GraphicsLayerCACF::updateMasksToBounds()
+{
+ m_layer->setMasksToBounds(m_masksToBounds);
+ updateDebugIndicators();
+}
+
+void GraphicsLayerCACF::updateContentsOpaque()
+{
+ m_layer->setOpaque(m_contentsOpaque);
+}
+
+void GraphicsLayerCACF::updateBackfaceVisibility()
+{
+ m_layer->setDoubleSided(m_backfaceVisibility);
+}
+
+void GraphicsLayerCACF::updateLayerPreserves3D()
+{
+ if (m_preserves3D && !m_transformLayer) {
+ // Create the transform layer.
+ m_transformLayer = WebLayer::create(WKCACFLayer::TransformLayer, this);
+
+#ifndef NDEBUG
+ m_transformLayer->setName(String().format("Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this));
+#endif
+ // Copy the position from this layer.
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ m_layer->setPosition(point);
+
+ m_layer->setAnchorPoint(CGPointMake(0.5f, 0.5f));
+ m_layer->setTransform(CATransform3DIdentity);
+
+ // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
+ m_layer->setOpacity(1);
+
+ // Move this layer to be a child of the transform layer.
+ if (m_layer->superlayer())
+ m_layer->superlayer()->replaceSublayer(m_layer.get(), m_transformLayer.get());
+ m_transformLayer->addSublayer(m_layer.get());
+
+ updateSublayerList();
+ } else if (!m_preserves3D && m_transformLayer) {
+ // Relace the transformLayer in the parent with this layer.
+ m_layer->removeFromSuperlayer();
+ m_transformLayer->superlayer()->replaceSublayer(m_transformLayer.get(), m_layer.get());
+
+ // Release the transform layer.
+ m_transformLayer = 0;
+
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ updateSublayerList();
+ }
+
+ updateOpacityOnLayer();
+}
+
+void GraphicsLayerCACF::updateLayerDrawsContent()
+{
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ if (m_drawsContent)
+ m_layer->setNeedsDisplay();
+ else
+ m_layer->setContents(0);
+
+ updateDebugIndicators();
+}
+
+void GraphicsLayerCACF::updateLayerBackgroundColor()
+{
+ if (!m_contentsLayer)
+ return;
+
+ // We never create the contents layer just for background color yet.
+ if (m_backgroundColorSet)
+ setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
+ else
+ clearLayerBackgroundColor(m_contentsLayer.get());
+}
+
+void GraphicsLayerCACF::updateContentsImage()
+{
+ if (m_pendingContentsImage) {
+ if (!m_contentsLayer.get()) {
+ RefPtr<WKCACFLayer> imageLayer = WebLayer::create(WKCACFLayer::Layer, this);
+#ifndef NDEBUG
+ imageLayer->setName("Image Layer");
+#endif
+ setupContentsLayer(imageLayer.get());
+ m_contentsLayer = imageLayer;
+ // m_contentsLayer will be parented by updateSublayerList
+ }
+
+ // FIXME: maybe only do trilinear if the image is being scaled down,
+ // but then what if the layer size changes?
+ m_contentsLayer->setMinificationFilter(WKCACFLayer::Trilinear);
+ m_contentsLayer->setContents(m_pendingContentsImage.get());
+ m_pendingContentsImage = 0;
+
+ updateContentsRect();
+ } else {
+ // No image.
+ // m_contentsLayer will be removed via updateSublayerList.
+ m_contentsLayer = 0;
+ }
+}
+
+void GraphicsLayerCACF::updateContentsMedia()
+{
+ // Media layer was set as m_contentsLayer, and will get parented in updateSublayerList().
+ if (m_contentsLayer) {
+ setupContentsLayer(m_contentsLayer.get());
+ updateContentsRect();
+ }
+}
+
+void GraphicsLayerCACF::updateContentsRect()
+{
+ if (!m_contentsLayer)
+ return;
+
+ CGPoint point = CGPointMake(m_contentsRect.x(),
+ m_contentsRect.y());
+ CGRect rect = CGRectMake(0.0f,
+ 0.0f,
+ m_contentsRect.width(),
+ m_contentsRect.height());
+
+ m_contentsLayer->setPosition(point);
+ m_contentsLayer->setBounds(rect);
+}
+
+void GraphicsLayerCACF::setupContentsLayer(WKCACFLayer* contentsLayer)
+{
+ if (contentsLayer == m_contentsLayer)
+ return;
+
+ if (m_contentsLayer) {
+ m_contentsLayer->removeFromSuperlayer();
+ m_contentsLayer = 0;
+ }
+
+ if (contentsLayer) {
+ m_contentsLayer = contentsLayer;
+
+ if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) {
+ CATransform3D flipper = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f};
+ m_contentsLayer->setTransform(flipper);
+ m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 1.0f));
+ } else
+ m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 0.0f));
+
+ // Insert the content layer first. Video elements require this, because they have
+ // shadow content that must display in front of the video.
+ m_layer->insertSublayer(m_contentsLayer.get(), 0);
+
+ updateContentsRect();
+
+ if (showDebugBorders()) {
+ setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180));
+ m_contentsLayer->setBorderWidth(1.0f);
+ }
+ }
+ updateDebugIndicators();
+}
+
+// This function simply mimics the operation of GraphicsLayerCA
+void GraphicsLayerCACF::updateOpacityOnLayer()
+{
+ primaryLayer()->setOpacity(m_opacity);
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h b/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h
new file mode 100644
index 0000000..23f36b2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2009 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 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 GraphicsLayerCACF_h
+#define GraphicsLayerCACF_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayer.h"
+#include "GraphicsContext.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+class WKCACFLayer;
+
+class GraphicsLayerCACF : public GraphicsLayer {
+public:
+
+ GraphicsLayerCACF(GraphicsLayerClient*);
+ virtual ~GraphicsLayerCACF();
+
+ virtual void setName(const String& inName);
+
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+ virtual void addChild(GraphicsLayer *layer);
+ virtual void addChildAtIndex(GraphicsLayer *layer, int index);
+ virtual void addChildAbove(GraphicsLayer *layer, GraphicsLayer *sibling);
+ virtual void addChildBelow(GraphicsLayer *layer, GraphicsLayer *sibling);
+ virtual bool replaceChild(GraphicsLayer *oldChild, GraphicsLayer *newChild);
+
+ virtual void removeFromParent();
+
+ virtual void setPosition(const FloatPoint& inPoint);
+ virtual void setAnchorPoint(const FloatPoint3D& inPoint);
+ virtual void setSize(const FloatSize& inSize);
+
+ virtual void setTransform(const TransformationMatrix&);
+
+ virtual void setChildrenTransform(const TransformationMatrix&);
+
+ virtual void setPreserves3D(bool);
+ virtual void setMasksToBounds(bool);
+ virtual void setDrawsContent(bool);
+
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+
+ virtual void setContentsOpaque(bool);
+ virtual void setBackfaceVisibility(bool);
+
+ virtual void setOpacity(float opacity);
+
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+
+ virtual void setContentsRect(const IntRect&);
+
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsToMedia(PlatformLayer*);
+
+ virtual PlatformLayer* platformLayer() const;
+
+ virtual void setDebugBackgroundColor(const Color&);
+ virtual void setDebugBorder(const Color&, float borderWidth);
+
+private:
+ void updateOpacityOnLayer();
+
+ WKCACFLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
+ WKCACFLayer* hostLayerForSublayers() const;
+ WKCACFLayer* layerForSuperlayer() const;
+
+ bool requiresTiledLayer(const FloatSize&) const;
+ void swapFromOrToTiledLayer(bool useTiledLayer);
+
+ CompositingCoordinatesOrientation defaultContentsOrientation() const;
+ void updateSublayerList();
+ void updateLayerPosition();
+ void updateLayerSize();
+ void updateAnchorPoint();
+ void updateTransform();
+ void updateChildrenTransform();
+ void updateMasksToBounds();
+ void updateContentsOpaque();
+ void updateBackfaceVisibility();
+ void updateLayerPreserves3D();
+ void updateLayerDrawsContent();
+ void updateLayerBackgroundColor();
+
+ void updateContentsImage();
+ void updateContentsMedia();
+ void updateContentsRect();
+
+ void setupContentsLayer(WKCACFLayer*);
+ WKCACFLayer* contentsLayer() const { return m_contentsLayer.get(); }
+
+ RefPtr<WKCACFLayer> m_layer;
+ RefPtr<WKCACFLayer> m_transformLayer;
+ RefPtr<WKCACFLayer> m_contentsLayer;
+
+ enum ContentsLayerPurpose {
+ NoContentsLayer = 0,
+ ContentsLayerForImage,
+ ContentsLayerForMedia
+ };
+
+ ContentsLayerPurpose m_contentsLayerPurpose;
+ bool m_contentsLayerHasBackgroundColor : 1;
+ RetainPtr<CGImageRef> m_pendingContentsImage;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerCACF_h
diff --git a/Source/WebCore/platform/graphics/win/IconWin.cpp b/Source/WebCore/platform/graphics/win/IconWin.cpp
new file mode 100644
index 0000000..4d4d219
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/IconWin.cpp
@@ -0,0 +1,99 @@
+/*
+* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+* Copyright (C) 2007-2009 Torch Mobile, 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 "Icon.h"
+
+#include "GraphicsContext.h"
+#include "LocalWindowsContext.h"
+#include "PlatformString.h"
+#include <tchar.h>
+#include <windows.h>
+
+#if OS(WINCE)
+// SHGFI_SHELLICONSIZE is not available on WINCE
+#define SHGFI_SHELLICONSIZE 0
+#endif
+
+namespace WebCore {
+
+static const int shell32MultipleFileIconIndex = 54;
+
+Icon::Icon(HICON icon)
+ : m_hIcon(icon)
+{
+ ASSERT(icon);
+}
+
+Icon::~Icon()
+{
+ DestroyIcon(m_hIcon);
+}
+
+// FIXME: Move the code to ChromeClient::iconForFiles().
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ if (filenames.isEmpty())
+ return 0;
+
+ if (filenames.size() == 1) {
+ SHFILEINFO sfi;
+ memset(&sfi, 0, sizeof(sfi));
+
+ String tmpFilename = filenames[0];
+ if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON))
+ return 0;
+
+ return adoptRef(new Icon(sfi.hIcon));
+ }
+
+#if OS(WINCE)
+ return 0;
+#else
+ TCHAR buffer[MAX_PATH];
+ UINT length = ::GetSystemDirectory(buffer, WTF_ARRAY_LENGTH(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));
+#endif
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& r)
+{
+ if (context->paintingDisabled())
+ return;
+
+#if OS(WINCE)
+ context->drawIcon(m_hIcon, r, DI_NORMAL);
+#else
+ LocalWindowsContext windowContext(context, r);
+ DrawIconEx(windowContext.hdc(), r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL);
+#endif
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/ImageCGWin.cpp b/Source/WebCore/platform/graphics/win/ImageCGWin.cpp
new file mode 100644
index 0000000..6cc5d6d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/ImageCGWin.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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 "BitmapInfo.h"
+#include "GraphicsContextCG.h"
+#include "PlatformString.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <windows.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
+{
+ DIBSECTION dibSection;
+ if (!GetObject(hBitmap, sizeof(DIBSECTION), &dibSection))
+ return 0;
+
+ ASSERT(dibSection.dsBm.bmBitsPixel == 32);
+ if (dibSection.dsBm.bmBitsPixel != 32)
+ return 0;
+
+ ASSERT(dibSection.dsBm.bmBits);
+ if (!dibSection.dsBm.bmBits)
+ return 0;
+
+ RetainPtr<CGContextRef> bitmapContext(AdoptCF, CGBitmapContextCreate(dibSection.dsBm.bmBits, dibSection.dsBm.bmWidth, dibSection.dsBm.bmHeight, 8,
+ dibSection.dsBm.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
+
+ // The BitmapImage takes ownership of this.
+ CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext.get());
+
+ return adoptRef(new BitmapImage(cgImage));
+}
+
+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;
+
+ CGContextRef cgContext = CGBitmapContextCreate(bmpInfo.bmBits, bmpInfo.bmWidth, bmpInfo.bmHeight,
+ 8, bmpInfo.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
+
+ GraphicsContext gc(cgContext);
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy);
+ else
+ draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy);
+
+ // Do cleanup
+ CGContextRelease(cgContext);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ size_t frames = frameCount();
+ for (size_t 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()), styleColorSpace, 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()), styleColorSpace, compositeOp);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/win/ImageCairoWin.cpp b/Source/WebCore/platform/graphics/win/ImageCairoWin.cpp
new file mode 100644
index 0000000..70b132e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/ImageCairoWin.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 <cairo-win32.h>
+
+#include <windows.h>
+#include "PlatformString.h"
+
+namespace WebCore {
+
+PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
+{
+ DIBSECTION dibSection;
+ if (!GetObject(hBitmap, sizeof(DIBSECTION), &dibSection))
+ return 0;
+
+ ASSERT(dibSection.dsBm.bmBitsPixel == 32);
+ if (dibSection.dsBm.bmBitsPixel != 32)
+ return 0;
+
+ ASSERT(dibSection.dsBm.bmBits);
+ if (!dibSection.dsBm.bmBits)
+ return 0;
+
+ cairo_surface_t* image = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, dibSection.dsBm.bmWidth, dibSection.dsBm.bmHeight);
+
+ // The BitmapImage object takes over ownership of the cairo_surface_t*, so no need to destroy here.
+ return adoptRef(new BitmapImage(image));
+}
+
+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);
+ }
+
+ cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)bmpInfo.bmBits,
+ CAIRO_FORMAT_ARGB32,
+ bmpInfo.bmWidth,
+ bmpInfo.bmHeight,
+ bmpInfo.bmWidthBytes);
+
+
+ cairo_t* targetRef = cairo_create(image);
+ cairo_surface_destroy(image);
+
+ GraphicsContext gc(targetRef);
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy);
+ else
+ draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy);
+
+ // Do cleanup
+ cairo_destroy(targetRef);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp)
+{
+ size_t frames = frameCount();
+ for (size_t 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()), ColorSpaceDeviceRGB, 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()), ColorSpaceDeviceRGB, compositeOp);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/win/ImageWin.cpp b/Source/WebCore/platform/graphics/win/ImageWin.cpp
new file mode 100644
index 0000000..54c5b41
--- /dev/null
+++ b/Source/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/Source/WebCore/platform/graphics/win/IntPointWin.cpp b/Source/WebCore/platform/graphics/win/IntPointWin.cpp
new file mode 100644
index 0000000..73db199
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/IntPointWin.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "config.h"
+#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/Source/WebCore/platform/graphics/win/IntRectWin.cpp b/Source/WebCore/platform/graphics/win/IntRectWin.cpp
new file mode 100644
index 0000000..fe25a7f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/IntRectWin.cpp
@@ -0,0 +1,45 @@
+
+/*
+ * 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 "config.h"
+#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/Source/WebCore/platform/graphics/win/IntSizeWin.cpp b/Source/WebCore/platform/graphics/win/IntSizeWin.cpp
new file mode 100644
index 0000000..26e68da
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/IntSizeWin.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 "config.h"
+#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/Source/WebCore/platform/graphics/win/LocalWindowsContext.h b/Source/WebCore/platform/graphics/win/LocalWindowsContext.h
new file mode 100644
index 0000000..c216140
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/LocalWindowsContext.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 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 LocalWindowsContext_h
+#define LocalWindowsContext_h
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+class LocalWindowsContext : public Noncopyable {
+public:
+ LocalWindowsContext(GraphicsContext* graphicsContext, const IntRect& rect, bool supportAlphaBlend = true, bool mayCreateBitmap = true)
+ : m_graphicsContext(graphicsContext)
+ , m_rect(rect)
+ , m_supportAlphaBlend(supportAlphaBlend)
+ , m_mayCreateBitmap(mayCreateBitmap)
+ {
+ m_hdc = m_graphicsContext->getWindowsContext(m_rect, m_supportAlphaBlend, m_mayCreateBitmap);
+ }
+
+ ~LocalWindowsContext()
+ {
+ m_graphicsContext->releaseWindowsContext(m_hdc, m_rect, m_supportAlphaBlend, m_mayCreateBitmap);
+ }
+
+ HDC hdc() const { return m_hdc; }
+
+private:
+ GraphicsContext* m_graphicsContext;
+ HDC m_hdc;
+ IntRect m_rect;
+ bool m_supportAlphaBlend;
+ bool m_mayCreateBitmap;
+};
+
+} // namespace WebCore
+#endif // LocalWindowsContext_h
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp
new file mode 100644
index 0000000..cbe38aa
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2010 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 INC. 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 INC. 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 "MediaPlayerPrivateFullscreenWindow.h"
+
+#include "IntRect.h"
+#include "WebCoreInstanceHandle.h"
+#include <windows.h>
+
+#if PLATFORM(CG)
+#include <CoreGraphics/CGColor.h>
+#endif
+
+namespace WebCore {
+
+MediaPlayerPrivateFullscreenWindow::MediaPlayerPrivateFullscreenWindow(MediaPlayerPrivateFullscreenClient* client)
+ : m_client(client)
+ , m_hwnd(0)
+#if USE(ACCELERATED_COMPOSITING)
+ , m_layerRenderer(WKCACFLayerRenderer::create(0))
+#endif
+{
+}
+
+MediaPlayerPrivateFullscreenWindow::~MediaPlayerPrivateFullscreenWindow()
+{
+ if (m_hwnd)
+ close();
+}
+
+void MediaPlayerPrivateFullscreenWindow::createWindow(HWND parentHwnd)
+{
+ static ATOM windowAtom;
+ static LPCWSTR windowClassName = L"MediaPlayerPrivateFullscreenWindowClass";
+ if (!windowAtom) {
+ WNDCLASSEX wcex = {0};
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = staticWndProc;
+ wcex.hInstance = instanceHandle();
+ wcex.lpszClassName = windowClassName;
+ windowAtom = ::RegisterClassEx(&wcex);
+ }
+
+ if (m_hwnd)
+ close();
+
+ MONITORINFO mi = {0};
+ mi.cbSize = sizeof(MONITORINFO);
+ if (!GetMonitorInfo(MonitorFromWindow(parentHwnd, MONITOR_DEFAULTTONEAREST), &mi))
+ return;
+
+ IntRect monitorRect = mi.rcMonitor;
+
+ ::CreateWindowExW(WS_EX_TOOLWINDOW, windowClassName, L"", WS_POPUP | WS_VISIBLE,
+ monitorRect.x(), monitorRect.y(), monitorRect.width(), monitorRect.height(),
+ parentHwnd, 0, WebCore::instanceHandle(), this);
+ ASSERT(IsWindow(m_hwnd));
+
+ ::SetFocus(m_hwnd);
+}
+
+void MediaPlayerPrivateFullscreenWindow::close()
+{
+ ::DestroyWindow(m_hwnd);
+ ASSERT(!m_hwnd);
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+void MediaPlayerPrivateFullscreenWindow::setRootChildLayer(PassRefPtr<PlatformCALayer> rootChild)
+{
+ if (m_rootChild == rootChild)
+ return;
+
+ if (m_rootChild)
+ m_rootChild->removeFromSuperlayer();
+
+ m_rootChild = rootChild;
+
+ if (!m_rootChild)
+ return;
+
+ m_layerRenderer->setRootChildLayer(m_rootChild.get());
+ PlatformCALayer* rootLayer = m_rootChild->rootLayer();
+ CGRect rootBounds = m_rootChild->rootLayer()->bounds();
+ m_rootChild->setFrame(rootBounds);
+ m_rootChild->setBackgroundColor(CGColorGetConstantColor(kCGColorBlack));
+#ifndef NDEBUG
+ RetainPtr<CGColorRef> redColor(AdoptCF, CGColorCreateGenericRGB(1, 0, 0, 1));
+ rootLayer->setBackgroundColor(redColor.get());
+#else
+ rootLayer->setBackgroundColor(CGColorGetConstantColor(kCGColorBlack));
+#endif
+}
+#endif
+
+LRESULT MediaPlayerPrivateFullscreenWindow::staticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LONG_PTR longPtr = GetWindowLongPtr(hWnd, GWLP_USERDATA);
+
+ if (!longPtr && message == WM_CREATE) {
+ LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
+ longPtr = reinterpret_cast<LONG_PTR>(lpcs->lpCreateParams);
+ ::SetWindowLongPtr(hWnd, GWLP_USERDATA, longPtr);
+ }
+
+ if (MediaPlayerPrivateFullscreenWindow* window = reinterpret_cast<MediaPlayerPrivateFullscreenWindow*>(longPtr))
+ return window->wndProc(hWnd, message, wParam, lParam);
+
+ return ::DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+LRESULT MediaPlayerPrivateFullscreenWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT lResult = 0;
+ switch (message) {
+ case WM_CREATE:
+ m_hwnd = hWnd;
+#if USE(ACCELERATED_COMPOSITING)
+ m_layerRenderer->setHostWindow(m_hwnd);
+ m_layerRenderer->createRenderer();
+ if (m_rootChild)
+ m_layerRenderer->setNeedsDisplay();
+#endif
+ break;
+ case WM_DESTROY:
+ m_hwnd = 0;
+#if USE(ACCELERATED_COMPOSITING)
+ m_layerRenderer->destroyRenderer();
+ m_layerRenderer->setHostWindow(0);
+#endif
+ break;
+ case WM_WINDOWPOSCHANGED:
+ {
+ LPWINDOWPOS wp = reinterpret_cast<LPWINDOWPOS>(lParam);
+ if (wp->flags & SWP_NOSIZE)
+ break;
+#if USE(ACCELERATED_COMPOSITING)
+ m_layerRenderer->resize();
+ PlatformCALayer* rootLayer = m_rootChild->rootLayer();
+ CGRect rootBounds = m_rootChild->rootLayer()->bounds();
+ m_rootChild->setFrame(rootBounds);
+ m_rootChild->setNeedsLayout();
+#endif
+ }
+ break;
+ case WM_PAINT:
+#if USE(ACCELERATED_COMPOSITING)
+ m_layerRenderer->renderSoon();
+#endif
+ break;
+ }
+
+ if (m_client)
+ lResult = m_client->fullscreenClientWndProc(hWnd, message, wParam, lParam);
+
+ return lResult;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h
new file mode 100644
index 0000000..a18f0cc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 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 INC. 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 INC. 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 MediaPlayerPrivateFullscreenWindow_h
+#define MediaPlayerPrivateFullscreenWindow_h
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "PlatformCALayer.h"
+#include "WKCACFLayerRenderer.h"
+#endif
+#include <wtf/OwnPtr.h>
+
+typedef unsigned WPARAM;
+typedef long LPARAM;
+typedef struct HWND__* HWND;
+typedef _W64 long LONG_PTR;
+typedef LONG_PTR LRESULT;
+typedef unsigned int UINT;
+
+namespace WebCore {
+
+class MediaPlayerPrivateFullscreenClient {
+public:
+ virtual LRESULT fullscreenClientWndProc(HWND, UINT message, WPARAM, LPARAM) = 0;
+protected:
+ virtual ~MediaPlayerPrivateFullscreenClient() {}
+};
+
+class MediaPlayerPrivateFullscreenWindow {
+public:
+ MediaPlayerPrivateFullscreenWindow(MediaPlayerPrivateFullscreenClient*);
+ ~MediaPlayerPrivateFullscreenWindow();
+
+ void createWindow(HWND ownerWindow);
+ void close();
+
+ HWND hwnd() const { return m_hwnd; }
+
+#if USE(ACCELERATED_COMPOSITING)
+ WKCACFLayerRenderer* layerRenderer() const { return m_layerRenderer.get(); }
+
+ PlatformCALayer* rootChildLayer() const { return m_rootChild.get(); }
+ void setRootChildLayer(PassRefPtr<PlatformCALayer>);
+#endif
+
+private:
+ static LRESULT __stdcall staticWndProc(HWND, UINT message, WPARAM, LPARAM);
+ LRESULT wndProc(HWND, UINT message, WPARAM, LPARAM);
+
+ MediaPlayerPrivateFullscreenClient* m_client;
+#if USE(ACCELERATED_COMPOSITING)
+ OwnPtr<WKCACFLayerRenderer> m_layerRenderer;
+ RefPtr<PlatformCALayer> m_rootChild;
+#endif
+ HWND m_hwnd;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp
new file mode 100644
index 0000000..0b91455
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp
@@ -0,0 +1,1252 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "MediaPlayerPrivateQuickTimeVisualContext.h"
+
+#include "Cookie.h"
+#include "CookieJar.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "KURL.h"
+#include "MediaPlayerPrivateTaskTimer.h"
+#include "QTCFDictionary.h"
+#include "QTDecompressionSession.h"
+#include "QTMovie.h"
+#include "QTMovieTask.h"
+#include "QTMovieVisualContext.h"
+#include "ScrollView.h"
+#include "Settings.h"
+#include "SoftLinking.h"
+#include "TimeRanges.h"
+#include "Timer.h"
+#include <AssertMacros.h>
+#include <CoreGraphics/CGContext.h>
+#include <Wininet.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/HashSet.h>
+#include <wtf/MainThread.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "PlatformCALayer.h"
+#include "WKCAImageQueue.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer);
+static bool requiredDllsAvailable();
+
+SOFT_LINK_LIBRARY(Wininet)
+SOFT_LINK(Wininet, InternetSetCookieExW, DWORD, WINAPI, (LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData, DWORD dwFlags, DWORD_PTR dwReserved), (lpszUrl, lpszCookieName, lpszCookieData, dwFlags, dwReserved))
+
+// Interface declaration for MediaPlayerPrivateQuickTimeVisualContext's QTMovieClient aggregate
+class MediaPlayerPrivateQuickTimeVisualContext::MovieClient : public QTMovieClient {
+public:
+ MovieClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
+ virtual ~MovieClient() { m_parent = 0; }
+ virtual void movieEnded(QTMovie*);
+ virtual void movieLoadStateChanged(QTMovie*);
+ virtual void movieTimeChanged(QTMovie*);
+private:
+ MediaPlayerPrivateQuickTimeVisualContext* m_parent;
+};
+
+#if USE(ACCELERATED_COMPOSITING)
+class MediaPlayerPrivateQuickTimeVisualContext::LayerClient : public PlatformCALayerClient {
+public:
+ LayerClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
+ virtual ~LayerClient() { m_parent = 0; }
+
+private:
+ virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*);
+ virtual bool platformCALayerRespondsToLayoutChanges() const { return true; }
+
+ virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) { }
+ virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesBottomUp; }
+ virtual void platformCALayerPaintContents(GraphicsContext&, const IntRect& inClip) { }
+ virtual bool platformCALayerShowDebugBorders() const { return false; }
+ virtual bool platformCALayerShowRepaintCounter() const { return false; }
+ virtual int platformCALayerIncrementRepaintCount() { return 0; }
+
+ virtual bool platformCALayerContentsOpaque() const { return false; }
+ virtual bool platformCALayerDrawsContent() const { return false; }
+ virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { }
+
+ MediaPlayerPrivateQuickTimeVisualContext* m_parent;
+};
+
+void MediaPlayerPrivateQuickTimeVisualContext::LayerClient::platformCALayerLayoutSublayersOfLayer(PlatformCALayer* layer)
+{
+ ASSERT(m_parent);
+ ASSERT(m_parent->m_transformLayer == layer);
+
+ FloatSize parentSize = layer->bounds().size();
+ FloatSize naturalSize = m_parent->naturalSize();
+
+ // Calculate the ratio of these two sizes and use that ratio to scale the qtVideoLayer:
+ FloatSize ratio(parentSize.width() / naturalSize.width(), parentSize.height() / naturalSize.height());
+
+ int videoWidth = 0;
+ int videoHeight = 0;
+ m_parent->m_movie->getNaturalSize(videoWidth, videoHeight);
+ FloatRect videoBounds(0, 0, videoWidth * ratio.width(), videoHeight * ratio.height());
+ FloatPoint3D videoAnchor = m_parent->m_qtVideoLayer->anchorPoint();
+
+ // Calculate the new position based on the parent's size:
+ FloatPoint position(parentSize.width() * 0.5 - videoBounds.width() * (0.5 - videoAnchor.x()),
+ parentSize.height() * 0.5 - videoBounds.height() * (0.5 - videoAnchor.y()));
+
+ m_parent->m_qtVideoLayer->setBounds(videoBounds);
+ m_parent->m_qtVideoLayer->setPosition(position);
+}
+#endif
+
+class MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient : public QTMovieVisualContextClient {
+public:
+ VisualContextClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
+ virtual ~VisualContextClient() { m_parent = 0; }
+ void imageAvailableForTime(const QTCVTimeStamp*);
+ static void retrieveCurrentImageProc(void*);
+private:
+ MediaPlayerPrivateQuickTimeVisualContext* m_parent;
+};
+
+MediaPlayerPrivateInterface* MediaPlayerPrivateQuickTimeVisualContext::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivateQuickTimeVisualContext(player);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+MediaPlayerPrivateQuickTimeVisualContext::MediaPlayerPrivateQuickTimeVisualContext(MediaPlayer* player)
+ : m_player(player)
+ , m_seekTo(-1)
+ , m_seekTimer(this, &MediaPlayerPrivateQuickTimeVisualContext::seekTimerFired)
+ , m_visualContextTimer(this, &MediaPlayerPrivateQuickTimeVisualContext::visualContextTimerFired)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_enabledTrackCount(0)
+ , m_totalTrackCount(0)
+ , m_hasUnsupportedTracks(false)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+ , m_visible(false)
+ , m_newFrameAvailable(false)
+ , m_movieClient(new MediaPlayerPrivateQuickTimeVisualContext::MovieClient(this))
+#if USE(ACCELERATED_COMPOSITING)
+ , m_layerClient(new MediaPlayerPrivateQuickTimeVisualContext::LayerClient(this))
+ , m_movieTransform(CGAffineTransformIdentity)
+#endif
+ , m_visualContextClient(new MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient(this))
+ , m_delayingLoad(false)
+ , m_preload(MediaPlayer::Auto)
+{
+}
+
+MediaPlayerPrivateQuickTimeVisualContext::~MediaPlayerPrivateQuickTimeVisualContext()
+{
+ tearDownVideoRendering();
+ cancelCallOnMainThread(&VisualContextClient::retrieveCurrentImageProc, this);
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::supportsFullscreen() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ Document* document = m_player->mediaPlayerClient()->mediaPlayerOwningDocument();
+ if (document && document->settings())
+ return document->settings()->acceleratedCompositingEnabled();
+#endif
+ return false;
+}
+
+PlatformMedia MediaPlayerPrivateQuickTimeVisualContext::platformMedia() const
+{
+ PlatformMedia p;
+ p.type = PlatformMedia::QTMovieVisualContextType;
+ p.media.qtMovieVisualContext = m_visualContext.get();
+ return p;
+}
+#if USE(ACCELERATED_COMPOSITING)
+
+PlatformLayer* MediaPlayerPrivateQuickTimeVisualContext::platformLayer() const
+{
+ return m_transformLayer ? m_transformLayer->platformLayer() : 0;
+}
+#endif
+
+String MediaPlayerPrivateQuickTimeVisualContext::rfc2616DateStringFromTime(CFAbsoluteTime time)
+{
+ static const char* const dayStrings[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ static const char* const monthStrings[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ static const CFStringRef dateFormatString = CFSTR("%s, %02d %s %04d %02d:%02d:%02d GMT");
+ static CFTimeZoneRef gmtTimeZone;
+ if (!gmtTimeZone)
+ gmtTimeZone = CFTimeZoneCopyDefault();
+
+ CFGregorianDate dateValue = CFAbsoluteTimeGetGregorianDate(time, gmtTimeZone);
+ if (!CFGregorianDateIsValid(dateValue, kCFGregorianAllUnits))
+ return String();
+
+ time = CFGregorianDateGetAbsoluteTime(dateValue, gmtTimeZone);
+ SInt32 day = CFAbsoluteTimeGetDayOfWeek(time, 0);
+
+ RetainPtr<CFStringRef> dateCFString(AdoptCF, CFStringCreateWithFormat(0, 0, dateFormatString, dayStrings[day - 1], dateValue.day,
+ monthStrings[dateValue.month - 1], dateValue.year, dateValue.hour, dateValue.minute, (int)dateValue.second));
+ return dateCFString.get();
+}
+
+static void addCookieParam(StringBuilder& cookieBuilder, const String& name, const String& value)
+{
+ if (name.isEmpty())
+ return;
+
+ // If this isn't the first parameter added, terminate the previous one.
+ if (cookieBuilder.length())
+ cookieBuilder.append("; ");
+
+ // Add parameter name, and value if there is one.
+ cookieBuilder.append(name);
+ if (!value.isEmpty()) {
+ cookieBuilder.append('=');
+ cookieBuilder.append(value);
+ }
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime(const String& url)
+{
+ // WebCore loaded the page with the movie URL with CFNetwork but QuickTime will
+ // use WinINet to download the movie, so we need to copy any cookies needed to
+ // download the movie into WinInet before asking QuickTime to open it.
+ Document* document = m_player->mediaPlayerClient()->mediaPlayerOwningDocument();
+ Frame* frame = document ? document->frame() : 0;
+ if (!frame || !frame->page() || !frame->page()->cookieEnabled())
+ return;
+
+ KURL movieURL = KURL(KURL(), url);
+ Vector<Cookie> documentCookies;
+ if (!getRawCookies(frame->document(), movieURL, documentCookies))
+ return;
+
+ for (size_t ndx = 0; ndx < documentCookies.size(); ndx++) {
+ const Cookie& cookie = documentCookies[ndx];
+
+ if (cookie.name.isEmpty())
+ continue;
+
+ // Build up the cookie string with as much information as we can get so WinINet
+ // knows what to do with it.
+ StringBuilder cookieBuilder;
+ addCookieParam(cookieBuilder, cookie.name, cookie.value);
+ addCookieParam(cookieBuilder, "path", cookie.path);
+ if (cookie.expires)
+ addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires));
+ if (cookie.httpOnly)
+ addCookieParam(cookieBuilder, "httpOnly", String());
+ cookieBuilder.append(';');
+
+ String cookieURL;
+ if (!cookie.domain.isEmpty()) {
+ StringBuilder urlBuilder;
+
+ urlBuilder.append(movieURL.protocol());
+ urlBuilder.append("://");
+ if (cookie.domain[0] == '.')
+ urlBuilder.append(cookie.domain.substring(1));
+ else
+ urlBuilder.append(cookie.domain);
+ if (cookie.path.length() > 1)
+ urlBuilder.append(cookie.path);
+
+ cookieURL = urlBuilder.toString();
+ } else
+ cookieURL = movieURL;
+
+ InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0);
+ }
+}
+
+static void disableComponentsOnce()
+{
+ static bool sComponentsDisabled = false;
+ if (sComponentsDisabled)
+ return;
+ sComponentsDisabled = true;
+
+ uint32_t componentsToDisable[][5] = {
+ {'eat ', 'TEXT', 'text', 0, 0},
+ {'eat ', 'TXT ', 'text', 0, 0},
+ {'eat ', 'utxt', 'text', 0, 0},
+ {'eat ', 'TEXT', 'tx3g', 0, 0},
+ };
+
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(componentsToDisable); ++i)
+ QTMovie::disableComponent(componentsToDisable[i]);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::resumeLoad()
+{
+ m_delayingLoad = false;
+
+ if (!m_movieURL.isEmpty())
+ loadInternal(m_movieURL);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::load(const String& url)
+{
+ m_movieURL = url;
+
+ if (m_preload == MediaPlayer::None) {
+ m_delayingLoad = true;
+ return;
+ }
+
+ loadInternal(url);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::loadInternal(const String& url)
+{
+ if (!QTMovie::initializeQuickTime()) {
+ // FIXME: is this the right error to return?
+ m_networkState = MediaPlayer::DecodeError;
+ m_player->networkStateChanged();
+ return;
+ }
+
+ disableComponentsOnce();
+
+ // Initialize the task timer.
+ MediaPlayerPrivateTaskTimer::initialize();
+
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+ }
+ cancelSeek();
+
+ setUpCookiesForQuickTime(url);
+
+ m_movie = adoptRef(new QTMovie(m_movieClient.get()));
+ m_movie->load(url.characters(), url.length(), m_player->preservesPitch());
+ m_movie->setVolume(m_player->volume());
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::prepareToPlay()
+{
+ if (!m_movie || m_delayingLoad)
+ resumeLoad();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::play()
+{
+ if (!m_movie)
+ return;
+ m_startedPlaying = true;
+
+ m_movie->play();
+ m_visualContextTimer.startRepeating(1.0 / 30);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::pause()
+{
+ if (!m_movie)
+ return;
+ m_startedPlaying = false;
+
+ m_movie->pause();
+ m_visualContextTimer.stop();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::duration() const
+{
+ if (!m_movie)
+ return 0;
+ return m_movie->duration();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::currentTime() const
+{
+ if (!m_movie)
+ return 0;
+ return m_movie->currentTime();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::seek(float time)
+{
+ cancelSeek();
+
+ if (!m_movie)
+ return;
+
+ if (time > duration())
+ time = duration();
+
+ m_seekTo = time;
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else
+ m_seekTimer.start(0, 0.5f);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::doSeek()
+{
+ float oldRate = m_movie->rate();
+ if (oldRate)
+ m_movie->setRate(0);
+ m_movie->setCurrentTime(m_seekTo);
+ float timeAfterSeek = currentTime();
+ // restore playback only if not at end, othewise QTMovie will loop
+ if (oldRate && timeAfterSeek < duration())
+ m_movie->setRate(oldRate);
+ cancelSeek();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::cancelSeek()
+{
+ m_seekTo = -1;
+ m_seekTimer.stop();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::seekTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*)
+{
+ if (!m_movie || !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();
+ }
+ }
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::paused() const
+{
+ if (!m_movie)
+ return true;
+ return (!m_movie->rate());
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::seeking() const
+{
+ if (!m_movie)
+ return false;
+ return m_seekTo >= 0;
+}
+
+IntSize MediaPlayerPrivateQuickTimeVisualContext::naturalSize() const
+{
+ if (!m_movie)
+ return IntSize();
+ int width;
+ int height;
+ m_movie->getNaturalSize(width, height);
+#if USE(ACCELERATED_COMPOSITING)
+ CGSize originalSize = {width, height};
+ CGSize transformedSize = CGSizeApplyAffineTransform(originalSize, m_movieTransform);
+ return IntSize(abs(transformedSize.width), abs(transformedSize.height));
+#else
+ return IntSize(width, height);
+#endif
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasVideo() const
+{
+ if (!m_movie)
+ return false;
+ return m_movie->hasVideo();
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasAudio() const
+{
+ if (!m_movie)
+ return false;
+ return m_movie->hasAudio();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setVolume(float volume)
+{
+ if (!m_movie)
+ return;
+ m_movie->setVolume(volume);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setRate(float rate)
+{
+ if (!m_movie)
+ return;
+
+ // Do not call setRate(...) unless we have started playing; otherwise
+ // QuickTime's VisualContext can get wedged waiting for a rate change
+ // call which will never come.
+ if (m_startedPlaying)
+ m_movie->setRate(rate);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_movie)
+ return;
+ m_movie->setPreservesPitch(preservesPitch);
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasClosedCaptions() const
+{
+ if (!m_movie)
+ return false;
+ return m_movie->hasClosedCaptions();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setClosedCaptionsVisible(bool visible)
+{
+ if (!m_movie)
+ return;
+ m_movie->setClosedCaptionsVisible(visible);
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivateQuickTimeVisualContext::buffered() const
+{
+ RefPtr<TimeRanges> timeRanges = TimeRanges::create();
+ float loaded = maxTimeLoaded();
+ // rtsp streams are not buffered
+ if (!m_isStreaming && loaded > 0)
+ timeRanges->add(0, loaded);
+ return timeRanges.release();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::maxTimeSeekable() const
+{
+ // infinite duration means live stream
+ return !isfinite(duration()) ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::maxTimeLoaded() const
+{
+ if (!m_movie)
+ return 0;
+ return m_movie->maxTimeLoaded();
+}
+
+unsigned MediaPlayerPrivateQuickTimeVisualContext::bytesLoaded() const
+{
+ if (!m_movie)
+ return 0;
+ float dur = duration();
+ float maxTime = maxTimeLoaded();
+ if (!dur)
+ return 0;
+ return totalBytes() * maxTime / dur;
+}
+
+unsigned MediaPlayerPrivateQuickTimeVisualContext::totalBytes() const
+{
+ if (!m_movie)
+ return 0;
+ return m_movie->dataSize();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::cancelLoad()
+{
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ tearDownVideoRendering();
+
+ // Cancel the load by destroying the movie.
+ m_movie.clear();
+
+ updateStates();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ long loadState = m_movie ? m_movie->loadState() : QTMovieLoadStateError;
+
+ if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) {
+ m_movie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount);
+ if (m_player->inMediaDocument()) {
+ if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) {
+ // This is a type of media that we do not handle directly with a <video>
+ // element, eg. QuickTime VR, a movie with a sprite track, etc. Tell the
+ // MediaPlayerClient that we won't support it.
+ sawUnsupportedTracks();
+ return;
+ }
+ } else if (!m_enabledTrackCount)
+ loadState = QTMovieLoadStateError;
+ }
+
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlayable) {
+ // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+ } else if (loadState >= QTMovieLoadStateLoaded) {
+ m_readyState = MediaPlayer::HaveMetadata;
+ } else if (loadState > QTMovieLoadStateError) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveNothing;
+ } else {
+ if (m_player->inMediaDocument()) {
+ // Something went wrong in the loading of media within a standalone file.
+ // This can occur with chained ref movies that eventually resolve to a
+ // file we don't support.
+ sawUnsupportedTracks();
+ return;
+ }
+
+ float loaded = maxTimeLoaded();
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
+ }
+
+ if (isReadyForRendering() && !hasSetUpVideoRendering())
+ setUpVideoRendering();
+
+ if (seeking())
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::isReadyForRendering() const
+{
+ return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::sawUnsupportedTracks()
+{
+ m_movie->setDisabled(true);
+ m_hasUnsupportedTracks = true;
+ m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::didEnd()
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ m_startedPlaying = false;
+
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setSize(const IntSize& size)
+{
+ if (m_hasUnsupportedTracks || !m_movie || m_size == size)
+ return;
+ m_size = size;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setVisible(bool visible)
+{
+ if (m_hasUnsupportedTracks || !m_movie || m_visible == visible)
+ return;
+
+ m_visible = visible;
+ if (m_visible) {
+ if (isReadyForRendering())
+ setUpVideoRendering();
+ } else
+ tearDownVideoRendering();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::paint(GraphicsContext* p, const IntRect& r)
+{
+ MediaRenderingMode currentMode = currentRenderingMode();
+
+ if (currentMode == MediaRenderingNone)
+ return;
+
+ if (currentMode == MediaRenderingSoftwareRenderer && !m_visualContext)
+ return;
+
+ QTPixelBuffer buffer = m_visualContext->imageForTime(0);
+ if (buffer.pixelBufferRef()) {
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer) {
+ // We are probably being asked to render the video into a canvas, but
+ // there's a good chance the QTPixelBuffer is not ARGB and thus can't be
+ // drawn using CG. If so, fire up an ICMDecompressionSession and convert
+ // the current frame into something which can be rendered by CG.
+ if (!buffer.pixelFormatIs32ARGB() && !buffer.pixelFormatIs32BGRA()) {
+ // The decompression session will only decompress a specific pixelFormat
+ // at a specific width and height; if these differ, the session must be
+ // recreated with the new parameters.
+ if (!m_decompressionSession || !m_decompressionSession->canDecompress(buffer))
+ m_decompressionSession = QTDecompressionSession::create(buffer.pixelFormatType(), buffer.width(), buffer.height());
+ buffer = m_decompressionSession->decompress(buffer);
+ }
+ }
+#endif
+ CGImageRef image = CreateCGImageFromPixelBuffer(buffer);
+
+ CGContextRef context = p->platformContext();
+ CGContextSaveGState(context);
+ CGContextTranslateCTM(context, r.x(), r.y());
+ CGContextTranslateCTM(context, 0, r.height());
+ CGContextScaleCTM(context, 1, -1);
+ CGContextDrawImage(context, CGRectMake(0, 0, r.width(), r.height()), image);
+ CGContextRestoreGState(context);
+
+ CGImageRelease(image);
+ }
+ paintCompleted(*p, r);
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::paintCompleted(GraphicsContext& context, const IntRect& rect)
+{
+ m_newFrameAvailable = false;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::retrieveCurrentImageProc(void* refcon)
+{
+ static_cast<MediaPlayerPrivateQuickTimeVisualContext*>(refcon)->retrieveCurrentImage();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::imageAvailableForTime(const QTCVTimeStamp* timeStamp)
+{
+ // This call may come in on another thread, so marshall to the main thread first:
+ callOnMainThread(&retrieveCurrentImageProc, m_parent);
+
+ // callOnMainThread must be paired with cancelCallOnMainThread in the destructor,
+ // in case this object is deleted before the main thread request is handled.
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::visualContextTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*)
+{
+ if (m_visualContext && m_visualContext->isImageAvailableForTime(0))
+ retrieveCurrentImage();
+}
+
+static CFDictionaryRef QTCFDictionaryCreateWithDataCallback(CFAllocatorRef allocator, const UInt8* bytes, CFIndex length)
+{
+ RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(allocator, bytes, length, kCFAllocatorNull));
+ if (!data)
+ return 0;
+
+ return reinterpret_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(allocator, data.get(), kCFPropertyListImmutable, 0));
+}
+
+static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ CGDataProviderRef provider = 0;
+ CGColorSpaceRef colorSpace = 0;
+ CGImageRef image = 0;
+
+ size_t bitsPerComponent = 0;
+ size_t bitsPerPixel = 0;
+ CGImageAlphaInfo alphaInfo = kCGImageAlphaNone;
+
+ if (buffer.pixelFormatIs32BGRA()) {
+ bitsPerComponent = 8;
+ bitsPerPixel = 32;
+ alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
+ } else if (buffer.pixelFormatIs32ARGB()) {
+ bitsPerComponent = 8;
+ bitsPerPixel = 32;
+ alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big);
+ } else {
+ // All other pixel formats are currently unsupported:
+ ASSERT_NOT_REACHED();
+ }
+
+ CGDataProviderDirectAccessCallbacks callbacks = {
+ &QTPixelBuffer::dataProviderGetBytePointerCallback,
+ &QTPixelBuffer::dataProviderReleaseBytePointerCallback,
+ &QTPixelBuffer::dataProviderGetBytesAtPositionCallback,
+ &QTPixelBuffer::dataProviderReleaseInfoCallback,
+ };
+
+ // Colorspace should be device, so that Quartz does not have to do an extra render.
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+ require(colorSpace, Bail);
+
+ provider = CGDataProviderCreateDirectAccess(buffer.pixelBufferRef(), buffer.dataSize(), &callbacks);
+ require(provider, Bail);
+
+ // CGDataProvider does not retain the buffer, but it will release it later, so do an extra retain here:
+ QTPixelBuffer::retainCallback(buffer.pixelBufferRef());
+
+ image = CGImageCreate(buffer.width(), buffer.height(), bitsPerComponent, bitsPerPixel, buffer.bytesPerRow(), colorSpace, alphaInfo, provider, 0, false, kCGRenderingIntentDefault);
+
+Bail:
+ // Once the image is created we can release our reference to the provider and the colorspace, they are retained by the image
+ if (provider)
+ CGDataProviderRelease(provider);
+ if (colorSpace)
+ CGColorSpaceRelease(colorSpace);
+
+ return image;
+#else
+ return 0;
+#endif
+}
+
+
+void MediaPlayerPrivateQuickTimeVisualContext::retrieveCurrentImage()
+{
+ if (!m_visualContext)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer) {
+
+ QTPixelBuffer buffer = m_visualContext->imageForTime(0);
+ if (!buffer.pixelBufferRef())
+ return;
+
+ PlatformCALayer* layer = m_qtVideoLayer.get();
+
+ if (!buffer.lockBaseAddress()) {
+ if (requiredDllsAvailable()) {
+ if (!m_imageQueue) {
+ m_imageQueue = new WKCAImageQueue(buffer.width(), buffer.height(), 30);
+ m_imageQueue->setFlags(WKCAImageQueue::Fill, WKCAImageQueue::Fill);
+ layer->setContents(m_imageQueue->get());
+ }
+
+ // Debug QuickTime links against a non-Debug version of CoreFoundation, so the
+ // CFDictionary attached to the CVPixelBuffer cannot be directly passed on into the
+ // CAImageQueue without being converted to a non-Debug CFDictionary. Additionally,
+ // old versions of QuickTime used a non-AAS CoreFoundation, so the types are not
+ // interchangable even in the release case.
+ RetainPtr<CFDictionaryRef> attachments(AdoptCF, QTCFDictionaryCreateCopyWithDataCallback(kCFAllocatorDefault, buffer.attachments(), &QTCFDictionaryCreateWithDataCallback));
+ CFTimeInterval imageTime = QTMovieVisualContext::currentHostTime();
+
+ m_imageQueue->collect();
+
+ uint64_t imageId = m_imageQueue->registerPixelBuffer(buffer.baseAddress(), buffer.dataSize(), buffer.bytesPerRow(), buffer.width(), buffer.height(), buffer.pixelFormatType(), attachments.get(), 0);
+
+ if (m_imageQueue->insertImage(imageTime, WKCAImageQueue::Buffer, imageId, WKCAImageQueue::Opaque | WKCAImageQueue::Flush, &QTPixelBuffer::imageQueueReleaseCallback, buffer.pixelBufferRef())) {
+ // Retain the buffer one extra time so it doesn't dissappear before CAImageQueue decides to release it:
+ QTPixelBuffer::retainCallback(buffer.pixelBufferRef());
+ }
+
+ } else {
+ CGImageRef image = CreateCGImageFromPixelBuffer(buffer);
+ layer->setContents(image);
+ CGImageRelease(image);
+ }
+
+ buffer.unlockBaseAddress();
+ layer->setNeedsCommit();
+ }
+ } else
+#endif
+ m_player->repaint();
+
+ m_visualContext->task();
+}
+
+static HashSet<String> mimeTypeCache()
+{
+ DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ unsigned count = QTMovie::countSupportedTypes();
+ for (unsigned n = 0; n < count; n++) {
+ const UChar* character;
+ unsigned len;
+ QTMovie::getSupportedType(n, character, len);
+ if (len)
+ typeCache.add(String(character, len));
+ }
+
+ typeListInitialized = true;
+ }
+
+ return typeCache;
+}
+
+static CFStringRef createVersionStringFromModuleName(LPCWSTR moduleName)
+{
+ HMODULE module = GetModuleHandleW(moduleName);
+ if (!module)
+ return 0;
+
+ wchar_t filePath[MAX_PATH] = {0};
+ if (!GetModuleFileNameW(module, filePath, MAX_PATH))
+ return 0;
+
+ DWORD versionInfoSize = GetFileVersionInfoSizeW(filePath, 0);
+ if (!versionInfoSize)
+ return 0;
+
+ CFStringRef versionString = 0;
+ void* versionInfo = calloc(versionInfoSize, sizeof(char));
+ if (GetFileVersionInfo(filePath, 0, versionInfoSize, versionInfo)) {
+ VS_FIXEDFILEINFO* fileInfo = 0;
+ UINT fileInfoLength = 0;
+
+ if (VerQueryValueW(versionInfo, L"\\", reinterpret_cast<LPVOID*>(&fileInfo), &fileInfoLength)) {
+ versionString = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%d.%d.%d.%d"),
+ HIWORD(fileInfo->dwFileVersionMS), LOWORD(fileInfo->dwFileVersionMS),
+ HIWORD(fileInfo->dwFileVersionLS), LOWORD(fileInfo->dwFileVersionLS));
+ }
+ }
+ free(versionInfo);
+
+ return versionString;
+}
+
+static bool requiredDllsAvailable()
+{
+ static bool s_prerequisitesChecked = false;
+ static bool s_prerequisitesSatisfied;
+ static const CFStringRef kMinQuartzCoreVersion = CFSTR("1.0.42.0");
+ static const CFStringRef kMinCoreVideoVersion = CFSTR("1.0.1.0");
+
+ if (s_prerequisitesChecked)
+ return s_prerequisitesSatisfied;
+ s_prerequisitesChecked = true;
+ s_prerequisitesSatisfied = false;
+
+ CFStringRef quartzCoreString = createVersionStringFromModuleName(L"QuartzCore");
+ if (!quartzCoreString)
+ quartzCoreString = createVersionStringFromModuleName(L"QuartzCore_debug");
+
+ CFStringRef coreVideoString = createVersionStringFromModuleName(L"CoreVideo");
+ if (!coreVideoString)
+ coreVideoString = createVersionStringFromModuleName(L"CoreVideo_debug");
+
+ s_prerequisitesSatisfied = (quartzCoreString && coreVideoString
+ && CFStringCompare(quartzCoreString, kMinQuartzCoreVersion, kCFCompareNumerically) != kCFCompareLessThan
+ && CFStringCompare(coreVideoString, kMinCoreVideoVersion, kCFCompareNumerically) != kCFCompareLessThan);
+
+ if (quartzCoreString)
+ CFRelease(quartzCoreString);
+ if (coreVideoString)
+ CFRelease(coreVideoString);
+
+ return s_prerequisitesSatisfied;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::isAvailable()
+{
+ return QTMovie::initializeQuickTime();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivateQuickTimeVisualContext::supportsType(const String& type, const String& codecs)
+{
+ // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type
+ return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieEnded(QTMovie* movie)
+{
+ if (m_parent->m_hasUnsupportedTracks)
+ return;
+
+ m_parent->m_visualContextTimer.stop();
+
+ ASSERT(m_parent->m_movie.get() == movie);
+ m_parent->didEnd();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieLoadStateChanged(QTMovie* movie)
+{
+ if (m_parent->m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_parent->m_movie.get() == movie);
+ m_parent->updateStates();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieTimeChanged(QTMovie* movie)
+{
+ if (m_parent->m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_parent->m_movie.get() == movie);
+ m_parent->updateStates();
+ m_parent->m_player->timeChanged();
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasSingleSecurityOrigin() const
+{
+ // We tell quicktime to disallow resources that come from different origins
+ // so we all media is single origin.
+ return true;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setPreload(MediaPlayer::Preload preload)
+{
+ m_preload = preload;
+ if (m_delayingLoad && m_preload != MediaPlayer::None)
+ resumeLoad();
+}
+
+float MediaPlayerPrivateQuickTimeVisualContext::mediaTimeForTimeValue(float timeValue) const
+{
+ long timeScale;
+ if (m_readyState < MediaPlayer::HaveMetadata || !(timeScale = m_movie->timeScale()))
+ return timeValue;
+
+ long mediaTimeValue = static_cast<long>(timeValue * timeScale);
+ return static_cast<float>(mediaTimeValue) / timeScale;
+}
+
+MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::currentRenderingMode() const
+{
+ if (!m_movie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ return MediaRenderingMovieLayer;
+#endif
+
+ return m_visualContext ? MediaRenderingSoftwareRenderer : MediaRenderingNone;
+}
+
+MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::preferredRenderingMode() const
+{
+ if (!m_player->frameView() || !m_movie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::setUpVideoRendering()
+{
+ MediaRenderingMode currentMode = currentRenderingMode();
+ MediaRenderingMode preferredMode = preferredRenderingMode();
+
+#if !USE(ACCELERATED_COMPOSITING)
+ ASSERT(preferredMode != MediaRenderingMovieLayer);
+#endif
+
+ if (currentMode == preferredMode && currentMode != MediaRenderingNone)
+ return;
+
+ if (currentMode != MediaRenderingNone)
+ tearDownVideoRendering();
+
+ if (preferredMode == MediaRenderingMovieLayer)
+ createLayerForMovie();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+#endif
+
+ QTPixelBuffer::Type contextType = requiredDllsAvailable() && preferredMode == MediaRenderingMovieLayer ? QTPixelBuffer::ConfigureForCAImageQueue : QTPixelBuffer::ConfigureForCGImage;
+ m_visualContext = QTMovieVisualContext::create(m_visualContextClient.get(), contextType);
+ m_visualContext->setMovie(m_movie.get());
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::tearDownVideoRendering()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ destroyLayerForMovie();
+#endif
+
+ m_visualContext = 0;
+}
+
+bool MediaPlayerPrivateQuickTimeVisualContext::hasSetUpVideoRendering() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ return m_qtVideoLayer || (currentRenderingMode() != MediaRenderingMovieLayer && m_visualContext);
+#else
+ return true;
+#endif
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::retrieveAndResetMovieTransform()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ // First things first, reset the total movie transform so that
+ // we can bail out early:
+ m_movieTransform = CGAffineTransformIdentity;
+
+ if (!m_movie || !m_movie->hasVideo())
+ return;
+
+ // This trick will only work on movies with a single video track,
+ // so bail out early if the video contains more than one (or zero)
+ // video tracks.
+ QTTrackArray videoTracks = m_movie->videoTracks();
+ if (videoTracks.size() != 1)
+ return;
+
+ QTTrack* track = videoTracks[0].get();
+ ASSERT(track);
+
+ CGAffineTransform movieTransform = m_movie->getTransform();
+ if (!CGAffineTransformEqualToTransform(movieTransform, CGAffineTransformIdentity))
+ m_movie->resetTransform();
+
+ CGAffineTransform trackTransform = track->getTransform();
+ if (!CGAffineTransformEqualToTransform(trackTransform, CGAffineTransformIdentity))
+ track->resetTransform();
+
+ // Multiply the two transforms together, taking care to
+ // do so in the correct order, track * movie = final:
+ m_movieTransform = CGAffineTransformConcat(trackTransform, movieTransform);
+#endif
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::createLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(supportsAcceleratedRendering());
+
+ if (!m_movie || m_qtVideoLayer)
+ return;
+
+ // Create a PlatformCALayer which will transform the contents of the video layer
+ // which is in m_qtVideoLayer.
+ m_transformLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, m_layerClient.get());
+ if (!m_transformLayer)
+ return;
+
+ // Mark the layer as anchored in the top left.
+ m_transformLayer->setAnchorPoint(FloatPoint3D());
+
+ m_qtVideoLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, 0);
+ if (!m_qtVideoLayer)
+ return;
+
+ if (CGAffineTransformEqualToTransform(m_movieTransform, CGAffineTransformIdentity))
+ retrieveAndResetMovieTransform();
+ CGAffineTransform t = m_movieTransform;
+
+ // Remove the translation portion of the transform, since we will always rotate about
+ // the layer's center point. In our limited use-case (a single video track), this is
+ // safe:
+ t.tx = t.ty = 0;
+ m_qtVideoLayer->setTransform(CATransform3DMakeAffineTransform(t));
+
+#ifndef NDEBUG
+ m_qtVideoLayer->setName("Video layer");
+#endif
+ m_transformLayer->appendSublayer(m_qtVideoLayer.get());
+ m_transformLayer->setNeedsLayout();
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
+#endif
+
+ // Fill the newly created layer with image data, so we're not looking at
+ // an empty layer until the next time a new image is available, which could
+ // be a long time if we're paused.
+ if (m_visualContext)
+ retrieveCurrentImage();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::destroyLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer) {
+ m_qtVideoLayer->removeFromSuperlayer();
+ m_qtVideoLayer = 0;
+ }
+
+ if (m_transformLayer)
+ m_transformLayer = 0;
+
+ if (m_imageQueue)
+ m_imageQueue = 0;
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool MediaPlayerPrivateQuickTimeVisualContext::supportsAcceleratedRendering() const
+{
+ return isReadyForRendering();
+}
+
+void MediaPlayerPrivateQuickTimeVisualContext::acceleratedRenderingStateChanged()
+{
+ // Set up or change the rendering path if necessary.
+ setUpVideoRendering();
+}
+
+#endif
+
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h
new file mode 100644
index 0000000..a12d79e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 MediaPlayerPrivateQuickTimeVisualContext_h
+#define MediaPlayerPrivateQuickTimeVisualContext_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayerPrivate.h"
+#include "Timer.h"
+#include <wtf/Forward.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RetainPtr.h>
+
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
+typedef struct CGImage *CGImageRef;
+class QTMovie;
+class QTMovieVisualContext;
+class QTDecompressionSession;
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntSize;
+class IntRect;
+
+#if USE(ACCELERATED_COMPOSITING)
+class PlatformCALayer;
+class WKCAImageQueue;
+#endif
+
+class MediaPlayerPrivateQuickTimeVisualContext : public MediaPlayerPrivateInterface {
+public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+
+ ~MediaPlayerPrivateQuickTimeVisualContext();
+
+private:
+ MediaPlayerPrivateQuickTimeVisualContext(MediaPlayer*);
+
+ virtual bool supportsFullscreen() const;
+ virtual PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const;
+#endif
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+ bool hasAudio() const;
+
+ void load(const String& url);
+ void cancelLoad();
+ void loadInternal(const String& url);
+ void resumeLoad();
+
+ void play();
+ void pause();
+ void prepareToPlay();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+
+ void setRate(float);
+ void setVolume(float);
+ void setPreservesPitch(bool);
+
+ MediaPlayer::NetworkState networkState() const { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ void loadStateChanged();
+ void didEnd();
+
+ void paint(GraphicsContext*, const IntRect&);
+ void paintCompleted(GraphicsContext&, const IntRect&);
+
+ bool hasSingleSecurityOrigin() const;
+
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool);
+
+ void setPreload(MediaPlayer::Preload);
+
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*);
+ float maxTimeLoaded() const;
+ void sawUnsupportedTracks();
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer*);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool supportsAcceleratedRendering() const;
+ virtual void acceleratedRenderingStateChanged();
+#endif
+
+ enum MediaRenderingMode { MediaRenderingNone, MediaRenderingSoftwareRenderer, MediaRenderingMovieLayer };
+ MediaRenderingMode currentRenderingMode() const;
+ MediaRenderingMode preferredRenderingMode() const;
+ bool isReadyForRendering() const;
+
+ void setUpVideoRendering();
+ void tearDownVideoRendering();
+ bool hasSetUpVideoRendering() const;
+
+ void createLayerForMovie();
+ void destroyLayerForMovie();
+
+ void setUpCookiesForQuickTime(const String& url);
+ String rfc2616DateStringFromTime(CFAbsoluteTime);
+
+ void visualContextTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*);
+ void retrieveCurrentImage();
+
+ class MovieClient;
+ friend class MovieClient;
+ OwnPtr<MovieClient> m_movieClient;
+
+#if USE(ACCELERATED_COMPOSITING)
+ class LayerClient;
+ friend class LayerClient;
+ OwnPtr<LayerClient> m_layerClient;
+#endif
+
+ class VisualContextClient;
+ friend class VisualContextClient;
+ OwnPtr<VisualContextClient> m_visualContextClient;
+
+ void retrieveAndResetMovieTransform();
+
+ virtual float mediaTimeForTimeValue(float) const;
+
+ MediaPlayer* m_player;
+ RefPtr<QTMovie> m_movie;
+#if USE(ACCELERATED_COMPOSITING)
+ RefPtr<PlatformCALayer> m_qtVideoLayer;
+ RefPtr<PlatformCALayer> m_transformLayer;
+ OwnPtr<WKCAImageQueue> m_imageQueue;
+ OwnPtr<QTDecompressionSession> m_decompressionSession;
+ CGAffineTransform m_movieTransform;
+#endif
+ RefPtr<QTMovieVisualContext> m_visualContext;
+ float m_seekTo;
+ Timer<MediaPlayerPrivateQuickTimeVisualContext> m_seekTimer;
+ Timer<MediaPlayerPrivateQuickTimeVisualContext> m_visualContextTimer;
+ IntSize m_size;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ unsigned m_enabledTrackCount;
+ unsigned m_totalTrackCount;
+ bool m_hasUnsupportedTracks;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+ bool m_visible;
+ bool m_newFrameAvailable;
+ bool m_delayingLoad;
+ String m_movieURL;
+ MediaPlayer::Preload m_preload;
+#if DRAW_FRAME_RATE
+ double m_frameCountWhilePlaying;
+ double m_timeStartedPlaying;
+ double m_timeStoppedPlaying;
+#endif
+
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
new file mode 100644
index 0000000..431d624
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -0,0 +1,933 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "Cookie.h"
+#include "CookieJar.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "KURL.h"
+#include "MediaPlayerPrivateTaskTimer.h"
+#include "QTMovieTask.h"
+#include "ScrollView.h"
+#include "SoftLinking.h"
+#include "TimeRanges.h"
+#include "Timer.h"
+#include <Wininet.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/HashSet.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayerCACF.h"
+#include "PlatformCALayer.h"
+#endif
+
+#if DRAW_FRAME_RATE
+#include "Document.h"
+#include "Font.h"
+#include "RenderObject.h"
+#include "RenderStyle.h"
+#include "Windows.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+SOFT_LINK_LIBRARY(Wininet)
+SOFT_LINK(Wininet, InternetSetCookieExW, DWORD, WINAPI, (LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData, DWORD dwFlags, DWORD_PTR dwReserved), (lpszUrl, lpszCookieName, lpszCookieData, dwFlags, dwReserved))
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player)
+ , m_seekTo(-1)
+ , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_enabledTrackCount(0)
+ , m_totalTrackCount(0)
+ , m_hasUnsupportedTracks(false)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+ , m_visible(false)
+ , m_newFrameAvailable(false)
+#if DRAW_FRAME_RATE
+ , m_frameCountWhilePlaying(0)
+ , m_timeStartedPlaying(0)
+ , m_timeStoppedPlaying(0)
+#endif
+{
+}
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+ tearDownVideoRendering();
+ m_qtGWorld->setMovie(0);
+}
+
+bool MediaPlayerPrivate::supportsFullscreen() const
+{
+ return true;
+}
+
+PlatformMedia MediaPlayerPrivate::platformMedia() const
+{
+ PlatformMedia p;
+ p.type = PlatformMedia::QTMovieGWorldType;
+ p.media.qtMovieGWorld = m_qtGWorld.get();
+ return p;
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayerPrivate::platformLayer() const
+{
+ return m_qtVideoLayer ? m_qtVideoLayer->platformLayer() : 0;
+}
+#endif
+
+String MediaPlayerPrivate::rfc2616DateStringFromTime(CFAbsoluteTime time)
+{
+ static const char* const dayStrings[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+ static const char* const monthStrings[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ static const CFStringRef dateFormatString = CFSTR("%s, %02d %s %04d %02d:%02d:%02d GMT");
+ static CFTimeZoneRef gmtTimeZone;
+ if (!gmtTimeZone)
+ gmtTimeZone = CFTimeZoneCopyDefault();
+
+ CFGregorianDate dateValue = CFAbsoluteTimeGetGregorianDate(time, gmtTimeZone);
+ if (!CFGregorianDateIsValid(dateValue, kCFGregorianAllUnits))
+ return String();
+
+ time = CFGregorianDateGetAbsoluteTime(dateValue, gmtTimeZone);
+ SInt32 day = CFAbsoluteTimeGetDayOfWeek(time, 0);
+
+ RetainPtr<CFStringRef> dateCFString(AdoptCF, CFStringCreateWithFormat(0, 0, dateFormatString, dayStrings[day - 1], dateValue.day,
+ monthStrings[dateValue.month - 1], dateValue.year, dateValue.hour, dateValue.minute, (int)dateValue.second));
+ return dateCFString.get();
+}
+
+static void addCookieParam(StringBuilder& cookieBuilder, const String& name, const String& value)
+{
+ if (name.isEmpty())
+ return;
+
+ // If this isn't the first parameter added, terminate the previous one.
+ if (cookieBuilder.length())
+ cookieBuilder.append("; ");
+
+ // Add parameter name, and value if there is one.
+ cookieBuilder.append(name);
+ if (!value.isEmpty()) {
+ cookieBuilder.append('=');
+ cookieBuilder.append(value);
+ }
+}
+
+
+void MediaPlayerPrivate::setUpCookiesForQuickTime(const String& url)
+{
+ // WebCore loaded the page with the movie URL with CFNetwork but QuickTime will
+ // use WinINet to download the movie, so we need to copy any cookies needed to
+ // download the movie into WinInet before asking QuickTime to open it.
+ Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0;
+ if (!frame || !frame->page() || !frame->page()->cookieEnabled())
+ return;
+
+ KURL movieURL = KURL(KURL(), url);
+ Vector<Cookie> documentCookies;
+ if (!getRawCookies(frame->document(), movieURL, documentCookies))
+ return;
+
+ for (size_t ndx = 0; ndx < documentCookies.size(); ndx++) {
+ const Cookie& cookie = documentCookies[ndx];
+
+ if (cookie.name.isEmpty())
+ continue;
+
+ // Build up the cookie string with as much information as we can get so WinINet
+ // knows what to do with it.
+ StringBuilder cookieBuilder;
+ addCookieParam(cookieBuilder, cookie.name, cookie.value);
+ addCookieParam(cookieBuilder, "path", cookie.path);
+ if (cookie.expires)
+ addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires));
+ if (cookie.httpOnly)
+ addCookieParam(cookieBuilder, "httpOnly", String());
+ cookieBuilder.append(';');
+
+ String cookieURL;
+ if (!cookie.domain.isEmpty()) {
+ StringBuilder urlBuilder;
+
+ urlBuilder.append(movieURL.protocol());
+ urlBuilder.append("://");
+ if (cookie.domain[0] == '.')
+ urlBuilder.append(cookie.domain.substring(1));
+ else
+ urlBuilder.append(cookie.domain);
+ if (cookie.path.length() > 1)
+ urlBuilder.append(cookie.path);
+
+ cookieURL = urlBuilder.toString();
+ } else
+ cookieURL = movieURL;
+
+ InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0);
+ }
+}
+
+void MediaPlayerPrivate::load(const String& url)
+{
+ if (!QTMovie::initializeQuickTime()) {
+ // FIXME: is this the right error to return?
+ m_networkState = MediaPlayer::DecodeError;
+ m_player->networkStateChanged();
+ return;
+ }
+
+ // Initialize the task timer.
+ MediaPlayerPrivateTaskTimer::initialize();
+
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+ }
+ cancelSeek();
+
+ setUpCookiesForQuickTime(url);
+
+ m_qtMovie = adoptRef(new QTMovie(this));
+ m_qtMovie->load(url.characters(), url.length(), m_player->preservesPitch());
+ m_qtMovie->setVolume(m_player->volume());
+
+ m_qtGWorld = adoptRef(new QTMovieGWorld(this));
+ m_qtGWorld->setMovie(m_qtMovie.get());
+ m_qtGWorld->setVisible(m_player->visible());
+}
+
+void MediaPlayerPrivate::play()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = true;
+#if DRAW_FRAME_RATE
+ m_frameCountWhilePlaying = 0;
+#endif
+
+ m_qtMovie->play();
+}
+
+void MediaPlayerPrivate::pause()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = WTF::currentTime();
+#endif
+ m_qtMovie->pause();
+}
+
+float MediaPlayerPrivate::duration() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->duration();
+}
+
+float MediaPlayerPrivate::currentTime() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->currentTime();
+}
+
+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();
+ if (oldRate)
+ m_qtMovie->setRate(0);
+ m_qtMovie->setCurrentTime(m_seekTo);
+ float timeAfterSeek = currentTime();
+ // restore playback only if not at end, othewise QTMovie will loop
+ if (oldRate && timeAfterSeek < duration())
+ 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();
+ }
+ }
+}
+
+bool MediaPlayerPrivate::paused() const
+{
+ if (!m_qtMovie)
+ return true;
+ return (!m_qtMovie->rate());
+}
+
+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
+{
+ if (!m_qtMovie)
+ return false;
+ return m_qtMovie->hasVideo();
+}
+
+bool MediaPlayerPrivate::hasAudio() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_qtMovie->hasAudio();
+}
+
+void MediaPlayerPrivate::setVolume(float volume)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setVolume(volume);
+}
+
+void MediaPlayerPrivate::setRate(float rate)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setRate(rate);
+}
+
+void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setPreservesPitch(preservesPitch);
+}
+
+bool MediaPlayerPrivate::hasClosedCaptions() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_qtMovie->hasClosedCaptions();
+}
+
+void MediaPlayerPrivate::setClosedCaptionsVisible(bool visible)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setClosedCaptionsVisible(visible);
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
+{
+ RefPtr<TimeRanges> timeRanges = TimeRanges::create();
+ float loaded = maxTimeLoaded();
+ // rtsp streams are not buffered
+ if (!m_isStreaming && loaded > 0)
+ timeRanges->add(0, loaded);
+ return timeRanges.release();
+}
+
+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;
+}
+
+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;
+
+ tearDownVideoRendering();
+
+ // 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_readyState < MediaPlayer::HaveMetadata) {
+ m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount);
+ if (m_player->inMediaDocument()) {
+ if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) {
+ // This is a type of media that we do not handle directly with a <video>
+ // element, eg. QuickTime VR, a movie with a sprite track, etc. Tell the
+ // MediaPlayerClient that we won't support it.
+ sawUnsupportedTracks();
+ return;
+ }
+ } else if (!m_enabledTrackCount)
+ loadState = QTMovieLoadStateError;
+ }
+
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (loadState >= QTMovieLoadStatePlayable) {
+ // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+ } else if (loadState >= QTMovieLoadStateLoaded) {
+ m_readyState = MediaPlayer::HaveMetadata;
+ } else if (loadState > QTMovieLoadStateError) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveNothing;
+ } else {
+ if (m_player->inMediaDocument()) {
+ // Something went wrong in the loading of media within a standalone file.
+ // This can occur with chained ref movies that eventually resolve to a
+ // file we don't support.
+ sawUnsupportedTracks();
+ return;
+ }
+
+ float loaded = maxTimeLoaded();
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
+ }
+
+ if (isReadyForRendering() && !hasSetUpVideoRendering())
+ setUpVideoRendering();
+
+ if (seeking())
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+}
+
+bool MediaPlayerPrivate::isReadyForRendering() const
+{
+ return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
+}
+
+void MediaPlayerPrivate::sawUnsupportedTracks()
+{
+ m_qtMovie->setDisabled(true);
+ m_hasUnsupportedTracks = true;
+ m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player);
+}
+
+void MediaPlayerPrivate::didEnd()
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = WTF::currentTime();
+#endif
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::setSize(const IntSize& size)
+{
+ if (m_hasUnsupportedTracks || !m_qtMovie || m_size == size)
+ return;
+ m_size = size;
+ m_qtGWorld->setSize(size.width(), size.height());
+}
+
+void MediaPlayerPrivate::setVisible(bool visible)
+{
+ if (m_hasUnsupportedTracks || !m_qtMovie || m_visible == visible)
+ return;
+
+ m_qtGWorld->setVisible(visible);
+ m_visible = visible;
+ if (m_visible) {
+ if (isReadyForRendering())
+ setUpVideoRendering();
+ } else
+ tearDownVideoRendering();
+}
+
+void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ return;
+#endif
+ if (p->paintingDisabled() || !m_qtMovie || m_hasUnsupportedTracks)
+ return;
+
+ bool usingTempBitmap = false;
+ OwnPtr<GraphicsContext::WindowsBitmap> bitmap;
+ // FIXME: use LocalWindowsContext.
+ HDC hdc = p->getWindowsContext(r);
+ if (!hdc) {
+ // The graphics context doesn't have an associated HDC so create a temporary
+ // bitmap where QTMovieGWorld can draw the frame and we can copy it.
+ usingTempBitmap = true;
+ bitmap.set(p->createWindowsBitmap(r.size()));
+ hdc = bitmap->hdc();
+
+ // FIXME: is this necessary??
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -r.x();
+ xform.eDy = -r.y();
+ SetWorldTransform(hdc, &xform);
+ }
+
+ m_qtGWorld->paint(hdc, r.x(), r.y());
+ if (usingTempBitmap)
+ p->drawWindowsBitmap(bitmap.get(), r.topLeft());
+ else
+ p->releaseWindowsContext(hdc, r);
+
+ paintCompleted(*p, r);
+}
+
+void MediaPlayerPrivate::paintCompleted(GraphicsContext& context, const IntRect& rect)
+{
+ m_newFrameAvailable = false;
+
+#if DRAW_FRAME_RATE
+ if (m_frameCountWhilePlaying > 10) {
+ double interval = m_startedPlaying ? WTF::currentTime() - m_timeStartedPlaying : m_timeStoppedPlaying - m_timeStartedPlaying;
+ double frameRate = (m_frameCountWhilePlaying - 1) / interval;
+ CGContextRef cgContext = context.platformContext();
+ CGRect drawRect = rect;
+
+ char text[8];
+ _snprintf(text, sizeof(text), "%1.2f", frameRate);
+
+ static const int fontSize = 25;
+ static const int fontCharWidth = 12;
+ static const int boxHeight = 25;
+ static const int boxBorderWidth = 4;
+ drawRect.size.width = boxBorderWidth * 2 + fontCharWidth * strlen(text);
+ drawRect.size.height = boxHeight;
+
+ CGContextSaveGState(cgContext);
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ CGContextScaleCTM(cgContext, 1, -1);
+ CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, m_qtVideoLayer ? -rect.height() : 0);
+#else
+ CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, 0);
+#endif
+ static const CGFloat backgroundColor[4] = { 0.98, 0.98, 0.82, 0.8 };
+ CGContextSetFillColor(cgContext, backgroundColor);
+ CGContextFillRect(cgContext, drawRect);
+
+ static const CGFloat textColor[4] = { 0, 0, 0, 1 };
+ CGContextSetFillColor(cgContext, textColor);
+ CGContextSetTextMatrix(cgContext, CGAffineTransformMakeScale(1, -1));
+ CGContextSelectFont(cgContext, "Helvetica", fontSize, kCGEncodingMacRoman);
+
+ CGContextShowTextAtPoint(cgContext, drawRect.origin.x + boxBorderWidth, drawRect.origin.y + boxHeight - boxBorderWidth, text, strlen(text));
+
+ CGContextRestoreGState(cgContext);
+ }
+#endif
+}
+
+static HashSet<String> mimeTypeCache()
+{
+ DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ unsigned count = QTMovie::countSupportedTypes();
+ for (unsigned n = 0; n < count; n++) {
+ const UChar* character;
+ unsigned len;
+ QTMovie::getSupportedType(n, character, len);
+ if (len)
+ typeCache.add(String(character, len));
+ }
+
+ typeListInitialized = true;
+ }
+
+ return typeCache;
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
+}
+
+bool MediaPlayerPrivate::isAvailable()
+{
+ return QTMovie::initializeQuickTime();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type
+ return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
+void MediaPlayerPrivate::movieEnded(QTMovie* movie)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_qtMovie.get() == movie);
+ didEnd();
+}
+
+void MediaPlayerPrivate::movieLoadStateChanged(QTMovie* movie)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_qtMovie.get() == movie);
+ updateStates();
+}
+
+void MediaPlayerPrivate::movieTimeChanged(QTMovie* movie)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_qtMovie.get() == movie);
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::movieNewImageAvailable(QTMovieGWorld* movie)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(m_qtGWorld.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 (m_frameCountWhilePlaying == 1)
+ m_timeStartedPlaying = WTF::currentTime();
+ }
+#endif
+
+ m_newFrameAvailable = true;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ m_qtVideoLayer->setNeedsDisplay();
+ else
+#endif
+ m_player->repaint();
+}
+
+bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
+{
+ // We tell quicktime to disallow resources that come from different origins
+ // so we all media is single origin.
+ return true;
+}
+
+MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::currentRenderingMode() const
+{
+ if (!m_qtMovie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::preferredRenderingMode() const
+{
+ if (!m_player->frameView() || !m_qtMovie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+void MediaPlayerPrivate::setUpVideoRendering()
+{
+ MediaRenderingMode currentMode = currentRenderingMode();
+ MediaRenderingMode preferredMode = preferredRenderingMode();
+
+#if !USE(ACCELERATED_COMPOSITING)
+ ASSERT(preferredMode != MediaRenderingMovieLayer);
+#endif
+
+ if (currentMode == preferredMode && currentMode != MediaRenderingNone)
+ return;
+
+ if (currentMode != MediaRenderingNone)
+ tearDownVideoRendering();
+
+ if (preferredMode == MediaRenderingMovieLayer)
+ createLayerForMovie();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+#endif
+}
+
+void MediaPlayerPrivate::tearDownVideoRendering()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ destroyLayerForMovie();
+#endif
+}
+
+bool MediaPlayerPrivate::hasSetUpVideoRendering() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ return m_qtVideoLayer || currentRenderingMode() != MediaRenderingMovieLayer;
+#else
+ return true;
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+
+// Up-call from compositing layer drawing callback.
+void MediaPlayerPrivate::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect&)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(supportsAcceleratedRendering());
+
+ // No reason to replace the current layer image unless we have something new to show.
+ if (!m_newFrameAvailable)
+ return;
+
+ static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ void* buffer;
+ unsigned bitsPerPixel;
+ unsigned rowBytes;
+ unsigned width;
+ unsigned height;
+
+ m_qtGWorld->getCurrentFrameInfo(buffer, bitsPerPixel, rowBytes, width, height);
+ if (!buffer)
+ return;
+
+ RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, static_cast<UInt8*>(buffer), rowBytes * height, kCFAllocatorNull));
+ RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithCFData(data.get()));
+ RetainPtr<CGImageRef> frameImage(AdoptCF, CGImageCreate(width, height, 8, bitsPerPixel, rowBytes, colorSpace,
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst, provider.get(), 0, false, kCGRenderingIntentDefault));
+ if (!frameImage)
+ return;
+
+ IntRect rect(0, 0, m_size.width(), m_size.height());
+ CGContextDrawImage(context.platformContext(), rect, frameImage.get());
+ paintCompleted(context, rect);
+}
+#endif
+
+void MediaPlayerPrivate::createLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(supportsAcceleratedRendering());
+
+ if (!m_qtMovie || m_qtVideoLayer)
+ return;
+
+ // Create a GraphicsLayer that won't be inserted directly into the render tree, but will used
+ // as a wrapper for a PlatformCALayer which gets inserted as the content layer of the video
+ // renderer's GraphicsLayer.
+ m_qtVideoLayer.set(new GraphicsLayerCACF(this));
+ if (!m_qtVideoLayer)
+ return;
+
+ // Mark the layer as drawing itself, anchored in the top left, and bottom-up.
+ m_qtVideoLayer->setDrawsContent(true);
+ m_qtVideoLayer->setAnchorPoint(FloatPoint3D());
+ m_qtVideoLayer->setContentsOrientation(GraphicsLayer::CompositingCoordinatesBottomUp);
+#ifndef NDEBUG
+ m_qtVideoLayer->setName("Video layer");
+#endif
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
+#endif
+}
+
+void MediaPlayerPrivate::destroyLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!m_qtVideoLayer)
+ return;
+ m_qtVideoLayer = 0;
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool MediaPlayerPrivate::supportsAcceleratedRendering() const
+{
+ return isReadyForRendering();
+}
+
+void MediaPlayerPrivate::acceleratedRenderingStateChanged()
+{
+ // Set up or change the rendering path if necessary.
+ setUpVideoRendering();
+}
+
+#endif
+
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
new file mode 100644
index 0000000..ab9b1f0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 MediaPlayerPrivateQuickTimeWin_h
+#define MediaPlayerPrivateQuickTimeWin_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayerPrivate.h"
+#include "Timer.h"
+#include <QTMovie.h>
+#include <QTMovieGWorld.h>
+#include <wtf/Forward.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RetainPtr.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayerClient.h"
+#endif
+
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
+typedef struct CGImage *CGImageRef;
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntSize;
+class IntRect;
+
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface, public QTMovieClient, public QTMovieGWorldClient
+#if USE(ACCELERATED_COMPOSITING)
+ , public GraphicsLayerClient
+#endif
+{
+public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+
+ ~MediaPlayerPrivate();
+
+private:
+
+#if USE(ACCELERATED_COMPOSITING)
+ // GraphicsLayerClient methods
+ virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip);
+ virtual void notifyAnimationStarted(const GraphicsLayer*, double time) { }
+ virtual void notifySyncRequired(const GraphicsLayer*) { }
+ virtual bool showDebugBorders() const { return false; }
+ virtual bool showRepaintCounter() const { return false; }
+#endif
+
+ MediaPlayerPrivate(MediaPlayer*);
+
+ virtual bool supportsFullscreen() const;
+ virtual PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+ bool hasAudio() 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 setRate(float);
+ void setVolume(float);
+ void setPreservesPitch(bool);
+
+ MediaPlayer::NetworkState networkState() const { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ void loadStateChanged();
+ void didEnd();
+
+ void paint(GraphicsContext*, const IntRect&);
+ void paintCompleted(GraphicsContext&, const IntRect&);
+
+ bool hasSingleSecurityOrigin() const;
+
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool);
+
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivate>*);
+ float maxTimeLoaded() const;
+ void sawUnsupportedTracks();
+
+ virtual void movieEnded(QTMovie*);
+ virtual void movieLoadStateChanged(QTMovie*);
+ virtual void movieTimeChanged(QTMovie*);
+ virtual void movieNewImageAvailable(QTMovieGWorld*);
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer*);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool supportsAcceleratedRendering() const;
+ virtual void acceleratedRenderingStateChanged();
+#endif
+
+ enum MediaRenderingMode { MediaRenderingNone, MediaRenderingSoftwareRenderer, MediaRenderingMovieLayer };
+ MediaRenderingMode currentRenderingMode() const;
+ MediaRenderingMode preferredRenderingMode() const;
+ bool isReadyForRendering() const;
+
+ void setUpVideoRendering();
+ void tearDownVideoRendering();
+ bool hasSetUpVideoRendering() const;
+
+ void createLayerForMovie();
+ void destroyLayerForMovie();
+
+ void setUpCookiesForQuickTime(const String& url);
+ String rfc2616DateStringFromTime(CFAbsoluteTime);
+
+ MediaPlayer* m_player;
+ RefPtr<QTMovie> m_qtMovie;
+ RefPtr<QTMovieGWorld> m_qtGWorld;
+#if USE(ACCELERATED_COMPOSITING)
+ OwnPtr<GraphicsLayer> m_qtVideoLayer;
+#endif
+ float m_seekTo;
+ Timer<MediaPlayerPrivate> m_seekTimer;
+ IntSize m_size;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ unsigned m_enabledTrackCount;
+ unsigned m_totalTrackCount;
+ bool m_hasUnsupportedTracks;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+ bool m_visible;
+ bool m_newFrameAvailable;
+#if DRAW_FRAME_RATE
+ double m_frameCountWhilePlaying;
+ double m_timeStartedPlaying;
+ double m_timeStoppedPlaying;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp
new file mode 100644
index 0000000..770e73e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 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 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 "MediaPlayerPrivateTaskTimer.h"
+
+#include "QTMovieTask.h"
+
+namespace WebCore {
+
+MediaPlayerPrivateTaskTimer* MediaPlayerPrivateTaskTimer::s_timer = 0;
+
+void MediaPlayerPrivateTaskTimer::initialize()
+{
+ if (s_timer)
+ return;
+
+ s_timer = new MediaPlayerPrivateTaskTimer;
+
+ QTMovieTask::sharedTask()->setTaskTimerFuncs(setDelay, stopTaskTimer);
+}
+
+void MediaPlayerPrivateTaskTimer::setDelay(double delayInSeconds)
+{
+ ASSERT(s_timer);
+
+ s_timer->startOneShot(delayInSeconds);
+}
+
+void MediaPlayerPrivateTaskTimer::stopTaskTimer()
+{
+ ASSERT(s_timer);
+
+ s_timer->stop();
+}
+
+void MediaPlayerPrivateTaskTimer::fired()
+{
+ QTMovieTask::sharedTask()->fireTaskClients();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h
new file mode 100644
index 0000000..10f861e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 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 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 MediaPlayerPrivateTaskTimer_h
+#define MediaPlayerPrivateTaskTimer_h
+
+#include "Timer.h"
+
+namespace WebCore {
+
+class MediaPlayerPrivateTaskTimer : TimerBase {
+public:
+ static void initialize();
+
+private:
+ static void setDelay(double);
+ static void stopTaskTimer();
+
+ void fired();
+
+ static MediaPlayerPrivateTaskTimer* s_timer;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTCFDictionary.cpp b/Source/WebCore/platform/graphics/win/QTCFDictionary.cpp
new file mode 100644
index 0000000..3c72792
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTCFDictionary.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "QTCFDictionary.h"
+
+#include <CFData.h>
+#include <windows.h>
+
+CFDataRef QTCFPropertyListCreateXMLData(CFAllocatorRef allocator, CFPropertyListRef propertyList)
+{
+
+ typedef CFDataRef (* pfnCFPropertyListCreateXMLData)(CFAllocatorRef allocator, CFPropertyListRef propertyList);
+ static pfnCFPropertyListCreateXMLData pCFPropertyListCreateXMLData = 0;
+ if (!pCFPropertyListCreateXMLData) {
+ HMODULE qtcfDLL = LoadLibraryW(L"QTCF.dll");
+ if (qtcfDLL)
+ pCFPropertyListCreateXMLData = reinterpret_cast<pfnCFPropertyListCreateXMLData>(GetProcAddress(qtcfDLL, "QTCF_CFPropertyListCreateXMLData"));
+ }
+
+ if (pCFPropertyListCreateXMLData)
+ return pCFPropertyListCreateXMLData(allocator, propertyList);
+ return 0;
+}
+
+CFDictionaryRef QTCFDictionaryCreateCopyWithDataCallback(CFAllocatorRef allocator, CFDictionaryRef dictionary, QTCFDictonaryCreateFromDataCallback callback)
+{
+ ASSERT(dictionary);
+ ASSERT(callback);
+
+ CFDataRef data = QTCFPropertyListCreateXMLData(kCFAllocatorDefault, dictionary);
+ if (!data)
+ return 0;
+ CFDictionaryRef outputDictionary = callback(allocator, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+
+ return outputDictionary;
+}
diff --git a/Source/WebCore/platform/graphics/win/QTCFDictionary.h b/Source/WebCore/platform/graphics/win/QTCFDictionary.h
new file mode 100644
index 0000000..ff34328
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTCFDictionary.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 QTCFDictionary_h
+#define QTCFDictionary_h
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+#include <CoreFoundation/CFBase.h>
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+
+typedef CFDictionaryRef (* QTCFDictonaryCreateFromDataCallback)(CFAllocatorRef, const UInt8*, CFIndex);
+
+QTMOVIEWIN_API CFDictionaryRef QTCFDictionaryCreateCopyWithDataCallback(CFAllocatorRef, CFDictionaryRef, QTCFDictonaryCreateFromDataCallback);
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp b/Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp
new file mode 100644
index 0000000..eeb3ca7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2010 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 "QTDecompressionSession.h"
+
+#include <ImageCompression.h>
+#include <algorithm>
+
+class QTDecompressionSessionClient {
+public:
+ static void trackingCallback(void *decompressionTrackingRefCon, OSStatus,
+ ICMDecompressionTrackingFlags decompressionTrackingFlags, CVPixelBufferRef pixelBuffer,
+ TimeValue64, TimeValue64, ICMValidTimeFlags, void *, void *)
+ {
+ QTDecompressionSession* session = static_cast<QTDecompressionSession*>(decompressionTrackingRefCon);
+ ASSERT(session);
+
+ if (decompressionTrackingFlags & kICMDecompressionTracking_FrameDecoded)
+ session->m_latestFrame = QTPixelBuffer(pixelBuffer);
+ }
+};
+
+PassOwnPtr<QTDecompressionSession> QTDecompressionSession::create(unsigned long pixelFormat, size_t width, size_t height)
+{
+ return adoptPtr(new QTDecompressionSession(pixelFormat, width, height));
+}
+
+QTDecompressionSession::QTDecompressionSession(unsigned long pixelFormat, size_t width, size_t height)
+ : m_session(0)
+ , m_pixelFormat(pixelFormat)
+ , m_width(width)
+ , m_height(height)
+{
+ initializeSession();
+}
+
+QTDecompressionSession::~QTDecompressionSession()
+{
+ if (m_session)
+ ICMDecompressionSessionRelease(m_session);
+}
+
+void QTDecompressionSession::initializeSession()
+{
+ if (m_session)
+ return;
+
+ ICMPixelFormatInfo pixelFormatInfo = {sizeof(ICMPixelFormatInfo), 0};
+ if (ICMGetPixelFormatInfo(m_pixelFormat, &pixelFormatInfo) != noErr) {
+ // The ICM does not know anything about the pixelFormat contained in
+ // the pixel buffer, so it won't be able to convert it to RGBA.
+ return;
+ }
+
+ // The depth and cType fields of the ImageDescriptionHandle are filled
+ // out according to the instructions in Technical Q&A QA1183:
+ // http://developer.apple.com/library/mac/#qa/qa2001/qa1183.html
+ bool isIndexed = pixelFormatInfo.formatFlags & kICMPixelFormatIsIndexed;
+ bool isQD = pixelFormatInfo.formatFlags & kICMPixelFormatIsSupportedByQD;
+ bool isMonochrome = pixelFormatInfo.formatFlags & kICMPixelFormatIsMonochrome;
+ bool hasAlpha = pixelFormatInfo.formatFlags & kICMPixelFormatHasAlphaChannel;
+
+ unsigned int depth = 24; // The default depth is 24.
+ if (hasAlpha)
+ depth = 32; // Any pixel format with alpha gets a depth of 32.
+ else if (isMonochrome) {
+ // Grayscale pixel formats get depths 33 through 40, depending
+ // on their bits per pixel. Yes, this means that 16-bit grayscale
+ // and 8-bit grayscale have the same pixel depth.
+ depth = 32 + std::min<unsigned int>(8, pixelFormatInfo.bitsPerPixel[0]);
+ } else if (isIndexed) {
+ // Indexed pixel formats get a depth of 1 through 8, depending on
+ // the their bits per pixel.
+ depth = pixelFormatInfo.bitsPerPixel[0];
+ }
+
+ // If QuickDraw supports the given pixel format, the cType should be kRawCodecType.
+ // Otherwise, use the pixel format code for the cType. We are assuming the pixel
+ // buffer is uncompressed.
+ unsigned long cType = isQD ? kRawCodecType : m_pixelFormat;
+
+ ImageDescriptionHandle description = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
+ (**description).idSize = sizeof(ImageDescription);
+ (**description).cType = cType;
+ (**description).version = 2;
+ (**description).spatialQuality = codecLosslessQuality;
+ (**description).width = m_width;
+ (**description).height = m_height;
+ (**description).hRes = 72 << 16; // 72 DPI as a fixed-point number
+ (**description).vRes = 72 << 16; // 72 DPI as a fixed-point number
+ (**description).frameCount = 1;
+ (**description).depth = depth;
+ (**description).clutID = -1;
+
+ // Create the mandatory ICMDecompressionSessionOptions, but leave
+ // all the default values.
+ ICMDecompressionSessionOptionsRef options = 0;
+ ICMDecompressionSessionOptionsCreate(kCFAllocatorDefault, &options);
+
+ CFDictionaryRef pixelBufferAttributes = QTPixelBuffer::createPixelBufferAttributesDictionary(QTPixelBuffer::ConfigureForCGImage);
+
+ ICMDecompressionTrackingCallbackRecord callback = {
+ QTDecompressionSessionClient::trackingCallback,
+ this,
+ };
+
+ ICMDecompressionSessionCreate(kCFAllocatorDefault,
+ description,
+ options,
+ pixelBufferAttributes,
+ &callback,
+ &m_session);
+
+ if (pixelBufferAttributes)
+ CFRelease(pixelBufferAttributes);
+
+ ICMDecompressionSessionOptionsRelease(options);
+ DisposeHandle((Handle)description);
+}
+
+bool QTDecompressionSession::canDecompress(QTPixelBuffer inBuffer)
+{
+ return m_session
+ && inBuffer.pixelFormatType() == m_pixelFormat
+ && inBuffer.width() == m_width
+ && inBuffer.height() == m_height;
+}
+
+QTPixelBuffer QTDecompressionSession::decompress(QTPixelBuffer inBuffer)
+{
+ if (!canDecompress(inBuffer))
+ return QTPixelBuffer();
+
+ inBuffer.lockBaseAddress();
+ ICMDecompressionSessionDecodeFrame(m_session,
+ static_cast<UInt8*>(inBuffer.baseAddress()),
+ inBuffer.dataSize(),
+ 0, // frameOptions
+ 0, // frameTime
+ 0); // sourceFrameRefCon
+
+ // Because we passed in 0 for frameTime, the above function
+ // is synchronous, and the client callback will have been
+ // called before the function returns, and m_latestFrame
+ // will contain the newly decompressed frame.
+ return m_latestFrame;
+}
diff --git a/Source/WebCore/platform/graphics/win/QTDecompressionSession.h b/Source/WebCore/platform/graphics/win/QTDecompressionSession.h
new file mode 100644
index 0000000..67b6635
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTDecompressionSession.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 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 QTDecompressionSession_h
+#define QTDecompressionSession_h
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+#include "QTPixelBuffer.h"
+
+#include <WTF/PassOwnPtr.h>
+
+class QTDecompressionSessionClient;
+typedef struct OpaqueICMDecompressionSession* ICMDecompressionSessionRef;
+
+class QTMOVIEWIN_API QTDecompressionSession {
+public:
+ static PassOwnPtr<QTDecompressionSession> create(unsigned long pixelFormat, size_t width, size_t height);
+ ~QTDecompressionSession();
+
+ bool canDecompress(QTPixelBuffer);
+
+ // The resulting QTPixelBuffer will be a CG compatable ARGB pixel buffer.
+ QTPixelBuffer decompress(QTPixelBuffer);
+
+private:
+ friend class QTDecompressionSessionClient;
+ QTDecompressionSession(unsigned long pixelFormat, size_t width, size_t height);
+ void initializeSession();
+
+ unsigned long m_pixelFormat;
+ size_t m_width;
+ size_t m_height;
+ QTPixelBuffer m_latestFrame;
+ ICMDecompressionSessionRef m_session;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovie.cpp b/Source/WebCore/platform/graphics/win/QTMovie.cpp
new file mode 100644
index 0000000..efaf218
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovie.cpp
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "QTMovie.h"
+
+#include "QTMovieTask.h"
+#include "QTMovieWinTimer.h"
+#include <FixMath.h>
+#include <GXMath.h>
+#include <Movies.h>
+#include <QTML.h>
+#include <QuickTimeComponents.h>
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+static const long minimumQuickTimeVersion = 0x07300000; // 7.3
+
+static const long closedCaptionTrackType = 'clcp';
+static const long subTitleTrackType = 'sbtl';
+static const long mpeg4ObjectDescriptionTrackType = 'odsm';
+static const long mpeg4SceneDescriptionTrackType = 'sdsm';
+static const long closedCaptionDisplayPropertyID = 'disp';
+static LPCTSTR fullscreenQTMoviePointerProp = TEXT("fullscreenQTMoviePointer");
+
+// 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 Vector<CFStringRef>* gSupportedTypes = 0;
+static SInt32 quickTimeVersion = 0;
+
+class QTMoviePrivate : public Noncopyable, public QTMovieTaskClient {
+public:
+ QTMoviePrivate();
+ ~QTMoviePrivate();
+ void task();
+ void startTask();
+ void endTask();
+
+ void createMovieController();
+ void cacheMovieScale();
+
+ QTMovie* m_movieWin;
+ Movie m_movie;
+ MovieController m_movieController;
+ bool m_tasking;
+ bool m_disabled;
+ Vector<QTMovieClient*> m_clients;
+ long m_loadState;
+ bool m_ended;
+ bool m_seeking;
+ float m_lastMediaTime;
+ double m_lastLoadStateCheckTime;
+ int m_width;
+ int m_height;
+ bool m_visible;
+ long m_loadError;
+ float m_widthScaleFactor;
+ float m_heightScaleFactor;
+ CFURLRef m_currentURL;
+ float m_timeToRestore;
+ float m_rateToRestore;
+#if !ASSERT_DISABLED
+ bool m_scaleCached;
+#endif
+};
+
+QTMoviePrivate::QTMoviePrivate()
+ : m_movieWin(0)
+ , m_movie(0)
+ , m_movieController(0)
+ , m_tasking(false)
+ , 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_loadError(0)
+ , m_widthScaleFactor(1)
+ , m_heightScaleFactor(1)
+ , m_currentURL(0)
+ , m_timeToRestore(-1.0f)
+ , m_rateToRestore(-1.0f)
+ , m_disabled(false)
+#if !ASSERT_DISABLED
+ , m_scaleCached(false)
+#endif
+{
+}
+
+QTMoviePrivate::~QTMoviePrivate()
+{
+ endTask();
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
+ if (m_movie)
+ DisposeMovie(m_movie);
+ if (m_currentURL)
+ CFRelease(m_currentURL);
+}
+
+void QTMoviePrivate::startTask()
+{
+ if (!m_tasking) {
+ QTMovieTask::sharedTask()->addTaskClient(this);
+ m_tasking = true;
+ }
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMoviePrivate::endTask()
+{
+ if (m_tasking) {
+ QTMovieTask::sharedTask()->removeTaskClient(this);
+ m_tasking = false;
+ }
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMoviePrivate::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 QTMovieLoadStateComplete.
+ // This is different from QTKit API and seems strange.
+ long loadState = m_loadError ? QTMovieLoadStateError : 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
+ bool shouldRestorePlaybackState = false;
+ bool movieNewlyPlayable = loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded;
+ m_loadState = loadState;
+ if (movieNewlyPlayable) {
+ cacheMovieScale();
+ shouldRestorePlaybackState = true;
+ }
+
+ if (!m_movieController && m_loadState >= QTMovieLoadStateLoaded)
+ createMovieController();
+
+ for (size_t i = 0; i < m_clients.size(); ++i)
+ m_clients[i]->movieLoadStateChanged(m_movieWin);
+
+ if (shouldRestorePlaybackState && m_timeToRestore != -1.0f) {
+ m_movieWin->setCurrentTime(m_timeToRestore);
+ m_timeToRestore = -1.0f;
+ m_movieWin->setRate(m_rateToRestore);
+ m_rateToRestore = -1.0f;
+ }
+
+ if (m_disabled) {
+ endTask();
+ return;
+ }
+ }
+ m_lastLoadStateCheckTime = systemTime();
+ }
+
+ bool ended = !!IsMovieDone(m_movie);
+ if (ended != m_ended) {
+ m_ended = ended;
+ if (ended) {
+ for (size_t i = 0; i < m_clients.size(); ++i)
+ m_clients[i]->movieEnded(m_movieWin);
+ }
+ }
+
+ float time = m_movieWin->currentTime();
+ if (time < m_lastMediaTime || time >= m_lastMediaTime + cNonContinuousTimeChange || m_seeking) {
+ m_seeking = false;
+ for (size_t i = 0; i < m_clients.size(); ++i)
+ m_clients[i]->movieTimeChanged(m_movieWin);
+ }
+ m_lastMediaTime = time;
+
+ if (m_loadError)
+ endTask();
+ else
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMoviePrivate::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;
+
+ // Disable automatic looping.
+ MCDoAction(m_movieController, mcActionSetLooping, 0);
+}
+
+void QTMoviePrivate::cacheMovieScale()
+{
+ Rect naturalRect;
+ Rect initialRect;
+
+ GetMovieNaturalBoundsRect(m_movie, &naturalRect);
+ GetMovieBox(m_movie, &initialRect);
+
+ float naturalWidth = naturalRect.right - naturalRect.left;
+ float naturalHeight = naturalRect.bottom - naturalRect.top;
+
+ if (naturalWidth)
+ m_widthScaleFactor = (initialRect.right - initialRect.left) / naturalWidth;
+ if (naturalHeight)
+ m_heightScaleFactor = (initialRect.bottom - initialRect.top) / naturalHeight;
+#if !ASSERT_DISABLED
+ m_scaleCached = true;
+#endif
+}
+
+QTMovie::QTMovie(QTMovieClient* client)
+ : m_private(new QTMoviePrivate())
+{
+ m_private->m_movieWin = this;
+ if (client)
+ m_private->m_clients.append(client);
+ initializeQuickTime();
+}
+
+QTMovie::~QTMovie()
+{
+ delete m_private;
+}
+
+void QTMovie::disableComponent(uint32_t cd[5])
+{
+ ComponentDescription nullDesc = {'null', 'base', kAppleManufacturer, 0, 0};
+ Component nullComp = FindNextComponent(0, &nullDesc);
+ Component disabledComp = 0;
+
+ while (disabledComp = FindNextComponent(disabledComp, (ComponentDescription*)&cd[0]))
+ CaptureComponent(disabledComp, nullComp);
+}
+
+void QTMovie::addClient(QTMovieClient* client)
+{
+ if (client)
+ m_private->m_clients.append(client);
+}
+
+void QTMovie::removeClient(QTMovieClient* client)
+{
+ size_t indexOfClient = m_private->m_clients.find(client);
+ if (indexOfClient != notFound)
+ m_private->m_clients.remove(indexOfClient);
+}
+
+void QTMovie::play()
+{
+ m_private->m_timeToRestore = -1.0f;
+
+ 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 QTMovie::pause()
+{
+ m_private->m_timeToRestore = -1.0f;
+
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPlay, 0);
+ else
+ StopMovie(m_private->m_movie);
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+float QTMovie::rate() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ return FixedToFloat(GetMovieRate(m_private->m_movie));
+}
+
+void QTMovie::setRate(float rate)
+{
+ if (!m_private->m_movie)
+ return;
+ m_private->m_timeToRestore = -1.0f;
+
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)FloatToFixed(rate));
+ else
+ SetMovieRate(m_private->m_movie, FloatToFixed(rate));
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+float QTMovie::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 QTMovie::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 QTMovie::setCurrentTime(float time) const
+{
+ if (!m_private->m_movie)
+ return;
+
+ m_private->m_timeToRestore = -1.0f;
+
+ 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));
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMovie::setVolume(float volume)
+{
+ if (!m_private->m_movie)
+ return;
+ SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256));
+}
+
+void QTMovie::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_private->m_movie || !m_private->m_currentURL)
+ return;
+
+ OSErr error;
+ bool prop = false;
+
+ error = QTGetMovieProperty(m_private->m_movie, kQTPropertyClass_Audio, kQTAudioPropertyID_RateChangesPreservePitch,
+ sizeof(kQTAudioPropertyID_RateChangesPreservePitch), static_cast<QTPropertyValuePtr>(&prop), 0);
+
+ if (error || prop == preservesPitch)
+ return;
+
+ m_private->m_timeToRestore = currentTime();
+ m_private->m_rateToRestore = rate();
+ load(m_private->m_currentURL, preservesPitch);
+}
+
+unsigned QTMovie::dataSize() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie));
+}
+
+float QTMovie::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 QTMovie::loadState() const
+{
+ return m_private->m_loadState;
+}
+
+void QTMovie::getNaturalSize(int& width, int& height)
+{
+ Rect rect = { 0, };
+
+ if (m_private->m_movie)
+ GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
+ width = (rect.right - rect.left) * m_private->m_widthScaleFactor;
+ height = (rect.bottom - rect.top) * m_private->m_heightScaleFactor;
+}
+
+void QTMovie::load(const UChar* url, int len, bool preservesPitch)
+{
+ CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len);
+ CFURLRef cfURL = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0);
+
+ load(cfURL, preservesPitch);
+
+ CFRelease(cfURL);
+ CFRelease(urlStringRef);
+}
+
+void QTMovie::load(CFURLRef url, bool preservesPitch)
+{
+ if (!url)
+ return;
+
+ if (m_private->m_movie) {
+ m_private->endTask();
+ 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;
+ m_private->m_loadState = 0;
+ }
+
+ // Define a property array for NewMovieFromProperties. 8 should be enough for our needs.
+ QTNewMoviePropertyElement movieProps[8];
+ ItemCount moviePropCount = 0;
+
+ bool boolTrue = true;
+
+ // Disable streaming support for now.
+ CFStringRef scheme = CFURLCopyScheme(url);
+ bool isRTSP = CFStringHasPrefix(scheme, CFSTR("rtsp:"));
+ CFRelease(scheme);
+
+ if (isRTSP) {
+ m_private->m_loadError = noMovieFound;
+ goto end;
+ }
+
+ if (m_private->m_currentURL) {
+ if (m_private->m_currentURL != url) {
+ CFRelease(m_private->m_currentURL);
+ m_private->m_currentURL = url;
+ CFRetain(url);
+ }
+ } else {
+ m_private->m_currentURL = url;
+ CFRetain(url);
+ }
+
+ // Add the movie data location to the property array
+ movieProps[moviePropCount].propClass = kQTPropertyClass_DataLocation;
+ movieProps[moviePropCount].propID = kQTDataLocationPropertyID_CFURL;
+ movieProps[moviePropCount].propValueSize = sizeof(m_private->m_currentURL);
+ movieProps[moviePropCount].propValueAddress = &(m_private->m_currentURL);
+ 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++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_Audio;
+ movieProps[moviePropCount].propID = kQTAudioPropertyID_RateChangesPreservePitch;
+ movieProps[moviePropCount].propValueSize = sizeof(preservesPitch);
+ movieProps[moviePropCount].propValueAddress = &preservesPitch;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ ASSERT(moviePropCount <= WTF_ARRAY_LENGTH(movieProps));
+ m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, 0, &m_private->m_movie);
+
+end:
+ m_private->startTask();
+ // get the load fail callback quickly
+ if (m_private->m_loadError)
+ QTMovieTask::sharedTask()->updateTaskTimer(0);
+ else {
+ OSType mode = kQTApertureMode_CleanAperture;
+
+ // Set the aperture mode property on a movie to signal that we want aspect ratio
+ // and clean aperture dimensions. Don't worry about errors, we can't do anything if
+ // the installed version of QT doesn't support it and it isn't serious enough to
+ // warrant failing.
+ QTSetMovieProperty(m_private->m_movie, kQTPropertyClass_Visual, kQTVisualPropertyID_ApertureMode, sizeof(mode), &mode);
+ }
+}
+
+void QTMovie::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount)
+{
+ if (!m_private->m_movie) {
+ totalTrackCount = 0;
+ 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(closedCaptionTrackType);
+ allowedTrackTypes->add(subTitleTrackType);
+ allowedTrackTypes->add(mpeg4ObjectDescriptionTrackType);
+ allowedTrackTypes->add(mpeg4SceneDescriptionTrackType);
+ allowedTrackTypes->add(TimeCodeMediaType);
+ allowedTrackTypes->add(TimeCode64MediaType);
+ }
+
+ long trackCount = GetMovieTrackCount(m_private->m_movie);
+ enabledTrackCount = trackCount;
+ totalTrackCount = 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)) {
+
+ // Different mpeg variants import as different track types so check for the "mpeg
+ // characteristic" instead of hard coding the (current) list of mpeg media types.
+ if (GetMovieIndTrackType(m_private->m_movie, 1, 'mpeg', movieTrackCharacteristic | movieTrackEnabledOnly))
+ continue;
+
+ 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;
+ }
+ }
+}
+
+bool QTMovie::isDisabled() const
+{
+ return m_private->m_disabled;
+}
+
+void QTMovie::setDisabled(bool b)
+{
+ m_private->m_disabled = b;
+}
+
+
+bool QTMovie::hasVideo() const
+{
+ if (!m_private->m_movie)
+ return false;
+ return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly));
+}
+
+bool QTMovie::hasAudio() const
+{
+ if (!m_private->m_movie)
+ return false;
+ return (GetMovieIndTrackType(m_private->m_movie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly));
+}
+
+QTTrackArray QTMovie::videoTracks() const
+{
+ QTTrackArray tracks;
+ long trackIndex = 1;
+
+ while (Track theTrack = GetMovieIndTrackType(m_private->m_movie, trackIndex++, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly))
+ tracks.append(QTTrack::create(theTrack));
+
+ return tracks;
+}
+
+bool QTMovie::hasClosedCaptions() const
+{
+ if (!m_private->m_movie)
+ return false;
+ return GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType);
+}
+
+void QTMovie::setClosedCaptionsVisible(bool visible)
+{
+ if (!m_private->m_movie)
+ return;
+
+ Track ccTrack = GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType);
+ if (!ccTrack)
+ return;
+
+ Boolean doDisplay = visible;
+ QTSetTrackProperty(ccTrack, closedCaptionTrackType, closedCaptionDisplayPropertyID, sizeof(doDisplay), &doDisplay);
+}
+
+long QTMovie::timeScale() const
+{
+ if (!m_private->m_movie)
+ return 0;
+
+ return GetMovieTimeScale(m_private->m_movie);
+}
+
+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 = 0;
+ 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, 0);
+ 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(0, 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 QTMovie::countSupportedTypes()
+{
+ initializeSupportedTypes();
+ return static_cast<unsigned>(gSupportedTypes->size());
+}
+
+void QTMovie::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);
+
+}
+
+CGAffineTransform QTMovie::getTransform() const
+{
+ ASSERT(m_private->m_movie);
+ MatrixRecord m = {0};
+ GetMovieMatrix(m_private->m_movie, &m);
+
+ ASSERT(!m.matrix[0][2]);
+ ASSERT(!m.matrix[1][2]);
+ CGAffineTransform transform = CGAffineTransformMake(
+ Fix2X(m.matrix[0][0]),
+ Fix2X(m.matrix[0][1]),
+ Fix2X(m.matrix[1][0]),
+ Fix2X(m.matrix[1][1]),
+ Fix2X(m.matrix[2][0]),
+ Fix2X(m.matrix[2][1]));
+ return transform;
+}
+
+void QTMovie::setTransform(CGAffineTransform t)
+{
+ ASSERT(m_private->m_movie);
+ MatrixRecord m = {{
+ {X2Fix(t.a), X2Fix(t.b), 0},
+ {X2Fix(t.c), X2Fix(t.d), 0},
+ {X2Fix(t.tx), X2Fix(t.ty), fract1},
+ }};
+
+ SetMovieMatrix(m_private->m_movie, &m);
+ m_private->cacheMovieScale();
+}
+
+void QTMovie::resetTransform()
+{
+ ASSERT(m_private->m_movie);
+ SetMovieMatrix(m_private->m_movie, 0);
+ m_private->cacheMovieScale();
+}
+
+
+bool QTMovie::initializeQuickTime()
+{
+ static bool initialized = false;
+ static bool initializationSucceeded = false;
+ if (!initialized) {
+ initialized = true;
+ // Initialize and check QuickTime version
+ OSErr result = InitializeQTML(kInitializeQTMLEnableDoubleBufferedSurface);
+ 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();
+ initializationSucceeded = true;
+ }
+ return initializationSucceeded;
+}
+
+Movie QTMovie::getMovieHandle() const
+{
+ return m_private->m_movie;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ return TRUE;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ return FALSE;
+ }
+ ASSERT_NOT_REACHED();
+ return FALSE;
+}
diff --git a/Source/WebCore/platform/graphics/win/QTMovie.h b/Source/WebCore/platform/graphics/win/QTMovie.h
new file mode 100644
index 0000000..5e4c4e7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovie.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 QTMovie_h
+#define QTMovie_h
+
+#include "QTTrack.h"
+#include <WTF/Vector.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTMovie;
+class QTMoviePrivate;
+typedef struct MovieType** Movie;
+typedef Vector<RefPtr<QTTrack>> QTTrackArray;
+
+class QTMovieClient {
+public:
+ virtual void movieEnded(QTMovie*) = 0;
+ virtual void movieLoadStateChanged(QTMovie*) = 0;
+ virtual void movieTimeChanged(QTMovie*) = 0;
+};
+
+enum {
+ QTMovieLoadStateError = -1L,
+ QTMovieLoadStateLoaded = 2000L,
+ QTMovieLoadStatePlayable = 10000L,
+ QTMovieLoadStatePlaythroughOK = 20000L,
+ QTMovieLoadStateComplete = 100000L
+};
+
+typedef const struct __CFURL * CFURLRef;
+
+class QTMOVIEWIN_API QTMovie : public RefCounted<QTMovie> {
+public:
+ static bool initializeQuickTime();
+ static void taskTimerFired();
+
+ static void disableComponent(uint32_t[5]);
+
+ QTMovie(QTMovieClient*);
+ ~QTMovie();
+
+ void addClient(QTMovieClient*);
+ void removeClient(QTMovieClient*);
+
+ void load(const UChar* url, int len, bool preservesPitch);
+ void load(CFURLRef, bool preservesPitch);
+
+ 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);
+ void setPreservesPitch(bool);
+
+ unsigned dataSize() const;
+
+ void getNaturalSize(int& width, int& height);
+
+ void disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount);
+
+ bool isDisabled() const;
+ void setDisabled(bool);
+
+ bool hasVideo() const;
+ bool hasAudio() const;
+
+ QTTrackArray videoTracks() const;
+
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool);
+
+ static unsigned countSupportedTypes();
+ static void getSupportedType(unsigned index, const UChar*& str, unsigned& len);
+
+ CGAffineTransform getTransform() const;
+ void setTransform(CGAffineTransform);
+ void resetTransform();
+
+ Movie getMovieHandle() const;
+
+ long timeScale() const;
+
+private:
+ QTMoviePrivate* m_private;
+ friend class QTMoviePrivate;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp b/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp
new file mode 100644
index 0000000..e13f732
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "QTMovieGWorld.h"
+
+#include "QTMovieTask.h"
+#include <GXMath.h>
+#include <Movies.h>
+#include <QTML.h>
+#include <QuickTimeComponents.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
+
+static LPCTSTR fullscreenQTMovieGWorldPointerProp = TEXT("fullscreenQTMovieGWorldPointer");
+
+// 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<QTMovieGWorldPrivate*>* gTaskList;
+static Vector<CFStringRef>* gSupportedTypes = 0;
+static SInt32 quickTimeVersion = 0;
+
+class QTMovieGWorldPrivate : public QTMovieClient {
+public:
+ QTMovieGWorldPrivate(QTMovieGWorld* movieWin);
+ virtual ~QTMovieGWorldPrivate();
+
+ void registerDrawingCallback();
+ void unregisterDrawingCallback();
+ void drawingComplete();
+ void updateGWorld();
+ void createGWorld();
+ void deleteGWorld();
+ void clearGWorld();
+ void updateMovieSize();
+
+ void setSize(int, int);
+
+ virtual void movieEnded(QTMovie*);
+ virtual void movieLoadStateChanged(QTMovie*);
+ virtual void movieTimeChanged(QTMovie*);
+
+ QTMovieGWorld* m_movieWin;
+ RefPtr<QTMovie> m_qtMovie;
+ Movie m_movie;
+ QTMovieGWorldClient* m_client;
+ long m_loadState;
+ int m_width;
+ int m_height;
+ bool m_visible;
+ GWorldPtr m_gWorld;
+ int m_gWorldWidth;
+ int m_gWorldHeight;
+ GWorldPtr m_savedGWorld;
+ float m_widthScaleFactor;
+ float m_heightScaleFactor;
+#if !ASSERT_DISABLED
+ bool m_scaleCached;
+#endif
+ WindowPtr m_fullscreenWindow;
+ GWorldPtr m_fullscreenOrigGWorld;
+ Rect m_fullscreenRect;
+ QTMovieGWorldFullscreenClient* m_fullscreenClient;
+ char* m_fullscreenRestoreState;
+ bool m_disabled;
+};
+
+QTMovieGWorldPrivate::QTMovieGWorldPrivate(QTMovieGWorld* movieWin)
+ : m_movieWin(movieWin)
+ , m_movie(0)
+ , m_client(0)
+ , m_loadState(0)
+ , m_width(0)
+ , m_height(0)
+ , m_visible(false)
+ , m_gWorld(0)
+ , m_gWorldWidth(0)
+ , m_gWorldHeight(0)
+ , m_savedGWorld(0)
+ , m_widthScaleFactor(1)
+ , m_heightScaleFactor(1)
+#if !ASSERT_DISABLED
+ , m_scaleCached(false)
+#endif
+ , m_fullscreenWindow(0)
+ , m_fullscreenOrigGWorld(0)
+ , m_fullscreenClient(0)
+ , m_fullscreenRestoreState(0)
+ , m_disabled(false)
+ , m_qtMovie(0)
+{
+ Rect rect = { 0, 0, 0, 0 };
+ m_fullscreenRect = rect;
+}
+
+QTMovieGWorldPrivate::~QTMovieGWorldPrivate()
+{
+ ASSERT(!m_fullscreenWindow);
+
+ if (m_gWorld)
+ deleteGWorld();
+}
+
+pascal OSErr movieDrawingCompleteProc(Movie movie, long data)
+{
+ UppParam param;
+ param.longValue = data;
+ QTMovieGWorldPrivate* mp = static_cast<QTMovieGWorldPrivate*>(param.ptr);
+ if (mp)
+ mp->drawingComplete();
+ return 0;
+}
+
+void QTMovieGWorldPrivate::registerDrawingCallback()
+{
+ if (!gMovieDrawingCompleteUPP)
+ gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc);
+
+ UppParam param;
+ param.ptr = this;
+ SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, gMovieDrawingCompleteUPP, param.longValue);
+}
+
+void QTMovieGWorldPrivate::unregisterDrawingCallback()
+{
+ SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, 0, 0);
+}
+
+void QTMovieGWorldPrivate::drawingComplete()
+{
+ if (!m_gWorld || m_movieWin->m_private->m_disabled || m_loadState < QTMovieLoadStateLoaded)
+ return;
+ m_client->movieNewImageAvailable(m_movieWin);
+}
+
+void QTMovieGWorldPrivate::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 QTMovieGWorldPrivate::createGWorld()
+{
+ ASSERT(!m_gWorld);
+ if (!m_movie || m_loadState < QTMovieLoadStateLoaded)
+ 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, 0, 0, 0);
+ if (err)
+ return;
+ GetMovieGWorld(m_movie, &m_savedGWorld, 0);
+ SetMovieGWorld(m_movie, m_gWorld, 0);
+ bounds.right = m_width;
+ bounds.bottom = m_height;
+ SetMovieBox(m_movie, &bounds);
+}
+
+void QTMovieGWorldPrivate::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 QTMovieGWorldPrivate::setSize(int width, int height)
+{
+ if (m_width == width && m_height == height)
+ return;
+ m_width = width;
+ m_height = height;
+
+ // Do not change movie box before reaching load state loaded as we grab
+ // the initial size when task() sees that state for the first time, and
+ // we need the initial size to be able to scale movie properly.
+ if (!m_movie || m_loadState < QTMovieLoadStateLoaded)
+ return;
+
+#if !ASSERT_DISABLED
+ ASSERT(m_scaleCached);
+#endif
+
+ updateMovieSize();
+}
+
+void QTMovieGWorldPrivate::updateMovieSize()
+{
+ if (!m_movie || m_loadState < QTMovieLoadStateLoaded)
+ return;
+
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = m_width;
+ bounds.bottom = m_height;
+ SetMovieBox(m_movie, &bounds);
+ updateGWorld();
+}
+
+
+void QTMovieGWorldPrivate::deleteGWorld()
+{
+ ASSERT(m_gWorld);
+ if (m_movie)
+ SetMovieGWorld(m_movie, m_savedGWorld, 0);
+ m_savedGWorld = 0;
+ DisposeGWorld(m_gWorld);
+ m_gWorld = 0;
+ m_gWorldWidth = 0;
+ m_gWorldHeight = 0;
+}
+
+void QTMovieGWorldPrivate::movieEnded(QTMovie*)
+{
+ // Do nothing
+}
+
+void QTMovieGWorldPrivate::movieLoadStateChanged(QTMovie* movie)
+{
+ long loadState = GetMovieLoadState(movie->getMovieHandle());
+ 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
+ bool movieNewlyPlayable = loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded;
+ m_loadState = loadState;
+
+ if (movieNewlyPlayable) {
+ updateMovieSize();
+ if (m_visible)
+ clearGWorld();
+ }
+ }
+}
+
+void QTMovieGWorldPrivate::movieTimeChanged(QTMovie*)
+{
+ // Do nothing
+}
+
+QTMovieGWorld::QTMovieGWorld(QTMovieGWorldClient* client)
+ : m_private(new QTMovieGWorldPrivate(this))
+{
+ m_private->m_client = client;
+}
+
+QTMovieGWorld::~QTMovieGWorld()
+{
+ delete m_private;
+}
+
+void QTMovieGWorld::setSize(int width, int height)
+{
+ m_private->setSize(width, height);
+ QTMovieTask::sharedTask()->updateTaskTimer();
+}
+
+void QTMovieGWorld::setVisible(bool b)
+{
+ m_private->m_visible = b;
+ m_private->updateGWorld();
+}
+
+void QTMovieGWorld::getCurrentFrameInfo(void*& buffer, unsigned& bitsPerPixel, unsigned& rowBytes, unsigned& width, unsigned& height)
+{
+ if (!m_private->m_gWorld) {
+ buffer = 0;
+ bitsPerPixel = 0;
+ rowBytes = 0;
+ width = 0;
+ height = 0;
+ return;
+ }
+ PixMapHandle offscreenPixMap = GetGWorldPixMap(m_private->m_gWorld);
+ buffer = (*offscreenPixMap)->baseAddr;
+ bitsPerPixel = (*offscreenPixMap)->pixelSize;
+ rowBytes = (*offscreenPixMap)->rowBytes & 0x3FFF;
+ width = m_private->m_width;
+ height = m_private->m_height;
+}
+
+void QTMovieGWorld::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 QTMovieGWorld::setDisabled(bool b)
+{
+ m_private->m_disabled = b;
+}
+
+bool QTMovieGWorld::isDisabled() const
+{
+ return m_private->m_disabled;
+}
+
+LRESULT QTMovieGWorld::fullscreenWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ QTMovieGWorld* movie = static_cast<QTMovieGWorld*>(GetProp(wnd, fullscreenQTMovieGWorldPointerProp));
+
+ if (message == WM_DESTROY)
+ RemoveProp(wnd, fullscreenQTMovieGWorldPointerProp);
+
+ if (!movie)
+ return DefWindowProc(wnd, message, wParam, lParam);
+
+ return movie->m_private->m_fullscreenClient->fullscreenClientWndProc(wnd, message, wParam, lParam);
+}
+
+HWND QTMovieGWorld::enterFullscreen(QTMovieGWorldFullscreenClient* client)
+{
+ m_private->m_fullscreenClient = client;
+
+ BeginFullScreen(&m_private->m_fullscreenRestoreState, 0, 0, 0, &m_private->m_fullscreenWindow, 0, fullScreenAllowEvents);
+ QTMLSetWindowWndProc(m_private->m_fullscreenWindow, fullscreenWndProc);
+ CreatePortAssociation(GetPortNativeWindow(m_private->m_fullscreenWindow), 0, 0);
+
+ GetMovieBox(m_private->m_movie, &m_private->m_fullscreenRect);
+ GetMovieGWorld(m_private->m_movie, &m_private->m_fullscreenOrigGWorld, 0);
+ SetMovieGWorld(m_private->m_movie, reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow), GetGWorldDevice(reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow)));
+
+ // Set the size of the box to preserve aspect ratio
+ Rect rect = m_private->m_fullscreenWindow->portRect;
+
+ float movieRatio = static_cast<float>(m_private->m_width) / m_private->m_height;
+ int windowWidth = rect.right - rect.left;
+ int windowHeight = rect.bottom - rect.top;
+ float windowRatio = static_cast<float>(windowWidth) / windowHeight;
+ int actualWidth = (windowRatio > movieRatio) ? (windowHeight * movieRatio) : windowWidth;
+ int actualHeight = (windowRatio < movieRatio) ? (windowWidth / movieRatio) : windowHeight;
+ int offsetX = (windowWidth - actualWidth) / 2;
+ int offsetY = (windowHeight - actualHeight) / 2;
+
+ rect.left = offsetX;
+ rect.right = offsetX + actualWidth;
+ rect.top = offsetY;
+ rect.bottom = offsetY + actualHeight;
+
+ SetMovieBox(m_private->m_movie, &rect);
+ ShowHideTaskBar(true);
+
+ // Set the 'this' pointer on the HWND
+ HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow));
+ SetProp(wnd, fullscreenQTMovieGWorldPointerProp, static_cast<HANDLE>(this));
+
+ return wnd;
+}
+
+void QTMovieGWorld::exitFullscreen()
+{
+ if (!m_private->m_fullscreenWindow)
+ return;
+
+ HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow));
+ DestroyPortAssociation(reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow));
+ SetMovieGWorld(m_private->m_movie, m_private->m_fullscreenOrigGWorld, 0);
+ EndFullScreen(m_private->m_fullscreenRestoreState, 0L);
+ SetMovieBox(m_private->m_movie, &m_private->m_fullscreenRect);
+ m_private->m_fullscreenWindow = 0;
+}
+
+void QTMovieGWorld::setMovie(PassRefPtr<QTMovie> movie)
+{
+ if (m_private->m_qtMovie) {
+ m_private->unregisterDrawingCallback();
+ m_private->m_qtMovie->removeClient(m_private);
+ m_private->m_qtMovie = 0;
+ m_private->m_movie = 0;
+ }
+
+ m_private->m_qtMovie = movie;
+
+ if (m_private->m_qtMovie) {
+ m_private->m_qtMovie->addClient(m_private);
+ m_private->m_movie = m_private->m_qtMovie->getMovieHandle();
+ m_private->registerDrawingCallback();
+ }
+}
+
+QTMovie* QTMovieGWorld::movie() const
+{
+ return m_private->m_qtMovie.get();
+}
diff --git a/Source/WebCore/platform/graphics/win/QTMovieGWorld.h b/Source/WebCore/platform/graphics/win/QTMovieGWorld.h
new file mode 100644
index 0000000..495fe25
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieGWorld.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 QTMovieGWorld_h
+#define QTMovieGWorld_h
+
+
+#include "QTMovie.h"
+#include <Unicode.h>
+#include <WTF/RefCounted.h>
+#include <WTF/RefPtr.h>
+#include <windows.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTMovieGWorld;
+class QTMovieGWorldPrivate;
+
+class QTMovieGWorldClient {
+public:
+ virtual void movieNewImageAvailable(QTMovieGWorld*) = 0;
+};
+
+class QTMovieGWorldFullscreenClient {
+public:
+ virtual LRESULT fullscreenClientWndProc(HWND, UINT message, WPARAM, LPARAM) = 0;
+};
+
+class QTMOVIEWIN_API QTMovieGWorld : public RefCounted<QTMovieGWorld> {
+public:
+ QTMovieGWorld(QTMovieGWorldClient*);
+ ~QTMovieGWorld();
+
+ void getNaturalSize(int& width, int& height);
+ void setSize(int width, int height);
+
+ void setVisible(bool);
+ void paint(HDC, int x, int y);
+ void getCurrentFrameInfo(void*& buffer, unsigned& bitsPerPixel, unsigned& rowBytes, unsigned& width, unsigned& height);
+
+ void setDisabled(bool);
+ bool isDisabled() const;
+
+ // Returns the full-screen window created
+ HWND enterFullscreen(QTMovieGWorldFullscreenClient*);
+ void exitFullscreen();
+
+ void setMovie(PassRefPtr<QTMovie>);
+ QTMovie* movie() const;
+
+private:
+ static LRESULT fullscreenWndProc(HWND, UINT message, WPARAM, LPARAM);
+
+ QTMovieGWorldPrivate* m_private;
+ friend class QTMovieGWorldPrivate;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovieTask.cpp b/Source/WebCore/platform/graphics/win/QTMovieTask.cpp
new file mode 100644
index 0000000..8713588
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieTask.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "QTMovieTask.h"
+
+// Put Movies.h first so build failures here point clearly to QuickTime
+#include <Movies.h>
+
+#include <wtf/HashSet.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+QTMovieTask::QTMovieTask()
+ : m_setTaskTimerDelay(0)
+ , m_stopTaskTimer(0)
+{
+}
+
+QTMovieTask::~QTMovieTask()
+{
+}
+
+QTMovieTask* QTMovieTask::sharedTask()
+{
+ static QTMovieTask* s_sharedTask = new QTMovieTask;
+ return s_sharedTask;
+}
+
+void QTMovieTask::updateTaskTimer(double maxInterval, double minInterval)
+{
+ ASSERT(m_setTaskTimerDelay);
+ if (!m_setTaskTimerDelay)
+ return;
+
+ ASSERT(m_stopTaskTimer);
+ if (!m_taskList.size() && m_stopTaskTimer) {
+ m_stopTaskTimer();
+ return;
+ }
+
+ long intervalInMS;
+ OSStatus status = QTGetTimeUntilNextTask(&intervalInMS, 1000);
+ double interval = intervalInMS / 1000.0;
+ if (interval < minInterval)
+ interval = minInterval;
+ if (interval > maxInterval)
+ interval = maxInterval;
+ m_setTaskTimerDelay(interval);
+}
+
+void QTMovieTask::fireTaskClients()
+{
+ Vector<QTMovieTaskClient*> clients;
+ copyToVector(m_taskList, clients);
+ for (Vector<QTMovieTaskClient*>::iterator i = clients.begin(); i != clients.end(); ++i)
+ (*i)->task();
+}
+
+void QTMovieTask::addTaskClient(QTMovieTaskClient* client)
+{
+ ASSERT(client);
+ if (!client)
+ return;
+
+ m_taskList.add(client);
+}
+
+void QTMovieTask::removeTaskClient(QTMovieTaskClient* client)
+{
+ ASSERT(client);
+ if (!client)
+ return;
+
+ m_taskList.remove(client);
+}
+
+void QTMovieTask::setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer)
+{
+ m_setTaskTimerDelay = setTaskTimerDelay;
+ m_stopTaskTimer = stopTaskTimer;
+}
+
diff --git a/Source/WebCore/platform/graphics/win/QTMovieTask.h b/Source/WebCore/platform/graphics/win/QTMovieTask.h
new file mode 100644
index 0000000..e394d6e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieTask.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 QTMovieTask_h
+#define QTMovieTask_h
+
+#include <WTF/HashSet.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTMovieTaskClient {
+public:
+ virtual void task() = 0;
+};
+
+typedef void (*SetTaskTimerDelayFunc)(double);
+typedef void (*StopTaskTimerFunc)();
+
+class QTMOVIEWIN_API QTMovieTask {
+public:
+ static QTMovieTask* sharedTask();
+
+ void addTaskClient(QTMovieTaskClient* client);
+ void removeTaskClient(QTMovieTaskClient*);
+ void fireTaskClients();
+
+ void updateTaskTimer(double maxInterval = 1.0, double minInterval = 1.0 / 30);
+ void setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer);
+
+protected:
+ QTMovieTask();
+ ~QTMovieTask();
+
+ SetTaskTimerDelayFunc m_setTaskTimerDelay;
+ StopTaskTimerFunc m_stopTaskTimer;
+ HashSet<QTMovieTaskClient*> m_taskList;
+
+private:
+ QTMovieTask(const QTMovieTask&);
+ QTMovieTask& operator=(const QTMovieTask&);
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp b/Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp
new file mode 100644
index 0000000..0fcc7e2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "QTMovieVisualContext.h"
+
+#include "QTMovieTask.h"
+#include <CVBase.h>
+#include <CVHostTime.h>
+#include <ImageCompression.h>
+#include <Movies.h>
+#include <windows.h>
+
+struct QTCVTimeStamp {
+ CVTimeStamp t;
+};
+
+class QTMovieVisualContextPriv {
+public:
+ QTMovieVisualContextPriv(QTMovieVisualContext* parent, QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType);
+ ~QTMovieVisualContextPriv();
+
+ bool isImageAvailableForTime(const QTCVTimeStamp*) const;
+ QTPixelBuffer imageForTime(const QTCVTimeStamp*);
+ void task();
+
+ QTVisualContextRef visualContextRef();
+
+ void setMovie(PassRefPtr<QTMovie>);
+ QTMovie* movie() const;
+
+ static void imageAvailableCallback(QTVisualContextRef visualContext, const CVTimeStamp *timeStamp, void *refCon);
+
+private:
+ QTMovieVisualContext* m_parent;
+ QTMovieVisualContextClient* m_client;
+ QTVisualContextRef m_visualContext;
+ RefPtr<QTMovie> m_movie;
+
+};
+
+static CFDictionaryRef createPixelBufferOptionsDictionary(QTPixelBuffer::Type contextType)
+{
+ const void* key = kQTVisualContextPixelBufferAttributesKey;
+ const void* value = QTPixelBuffer::createPixelBufferAttributesDictionary(contextType);
+ CFDictionaryRef pixelBufferOptions = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFRelease(value);
+ return pixelBufferOptions;
+}
+
+static CFDictionaryRef pixelBufferCreationOptions(QTPixelBuffer::Type contextType)
+{
+ if (contextType == QTPixelBuffer::ConfigureForCAImageQueue) {
+ static CFDictionaryRef imageQueueOptions = createPixelBufferOptionsDictionary(contextType);
+ return imageQueueOptions;
+ }
+
+ ASSERT(contextType == QTPixelBuffer::ConfigureForCGImage);
+ static CFDictionaryRef cgImageOptions = createPixelBufferOptionsDictionary(contextType);
+ return cgImageOptions;
+}
+
+QTMovieVisualContextPriv::QTMovieVisualContextPriv(QTMovieVisualContext* parent, QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
+ : m_parent(parent)
+ , m_client(client)
+ , m_visualContext(0)
+{
+ typedef OSStatus ( __cdecl *pfnQTPixelBufferContextCreate)(CFAllocatorRef, CFDictionaryRef, QTVisualContextRef*);
+ static pfnQTPixelBufferContextCreate pPixelBufferContextCreate = 0;
+ if (!pPixelBufferContextCreate) {
+ HMODULE qtmlDLL = ::LoadLibraryW(L"QTMLClient.dll");
+ if (!qtmlDLL)
+ return;
+ pPixelBufferContextCreate = reinterpret_cast<pfnQTPixelBufferContextCreate>(GetProcAddress(qtmlDLL, "QTPixelBufferContextCreate"));
+ if (!pPixelBufferContextCreate)
+ return;
+ }
+
+ OSStatus status = pPixelBufferContextCreate(kCFAllocatorDefault, pixelBufferCreationOptions(contextType), &m_visualContext);
+ if (status == noErr && m_visualContext)
+ QTVisualContextSetImageAvailableCallback(m_visualContext, &QTMovieVisualContextPriv::imageAvailableCallback, static_cast<void*>(this));
+}
+
+QTMovieVisualContextPriv::~QTMovieVisualContextPriv()
+{
+ if (m_visualContext)
+ QTVisualContextSetImageAvailableCallback(m_visualContext, 0, 0);
+}
+
+bool QTMovieVisualContextPriv::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const
+{
+ if (!m_visualContext)
+ return false;
+
+ return QTVisualContextIsNewImageAvailable(m_visualContext, reinterpret_cast<const CVTimeStamp*>(timeStamp));
+}
+
+QTPixelBuffer QTMovieVisualContextPriv::imageForTime(const QTCVTimeStamp* timeStamp)
+{
+ QTPixelBuffer pixelBuffer;
+ if (m_visualContext) {
+ CVImageBufferRef newImage = 0;
+ OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, kCFAllocatorDefault, reinterpret_cast<const CVTimeStamp*>(timeStamp), &newImage);
+ if (status == noErr)
+ pixelBuffer.adopt(newImage);
+ }
+ return pixelBuffer;
+}
+
+void QTMovieVisualContextPriv::task()
+{
+ if (m_visualContext)
+ QTVisualContextTask(m_visualContext);
+}
+
+QTVisualContextRef QTMovieVisualContextPriv::visualContextRef()
+{
+ return m_visualContext;
+}
+
+void QTMovieVisualContextPriv::setMovie(PassRefPtr<QTMovie> movie)
+{
+ if (movie == m_movie)
+ return;
+
+ if (m_movie) {
+ SetMovieVisualContext(m_movie->getMovieHandle(), 0);
+ m_movie = 0;
+ }
+
+ if (movie)
+ OSStatus status = SetMovieVisualContext(movie->getMovieHandle(), m_visualContext);
+
+ m_movie = movie;
+}
+
+QTMovie* QTMovieVisualContextPriv::movie() const
+{
+ return m_movie.get();
+}
+
+void QTMovieVisualContextPriv::imageAvailableCallback(QTVisualContextRef visualContext, const CVTimeStamp *timeStamp, void *refCon)
+{
+ if (!refCon)
+ return;
+
+ QTMovieVisualContextPriv* vc = static_cast<QTMovieVisualContextPriv*>(refCon);
+ if (!vc->m_client)
+ return;
+
+ vc->m_client->imageAvailableForTime(reinterpret_cast<const QTCVTimeStamp*>(timeStamp));
+}
+
+PassRefPtr<QTMovieVisualContext> QTMovieVisualContext::create(QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
+{
+ return adoptRef(new QTMovieVisualContext(client, contextType));
+}
+
+QTMovieVisualContext::QTMovieVisualContext(QTMovieVisualContextClient* client, QTPixelBuffer::Type contextType)
+ : m_private(new QTMovieVisualContextPriv(this, client, contextType))
+{
+}
+
+QTMovieVisualContext::~QTMovieVisualContext()
+{
+}
+
+bool QTMovieVisualContext::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const
+{
+ return m_private->isImageAvailableForTime(timeStamp);
+}
+
+QTPixelBuffer QTMovieVisualContext::imageForTime(const QTCVTimeStamp* timeStamp)
+{
+ return m_private->imageForTime(timeStamp);
+}
+
+void QTMovieVisualContext::task()
+{
+ m_private->task();
+}
+
+QTVisualContextRef QTMovieVisualContext::visualContextRef()
+{
+ return m_private->visualContextRef();
+}
+
+void QTMovieVisualContext::setMovie(PassRefPtr<QTMovie> movie)
+{
+ m_private->setMovie(movie);
+}
+
+QTMovie* QTMovieVisualContext::movie() const
+{
+ return m_private->movie();
+}
+
+double QTMovieVisualContext::currentHostTime()
+{
+ return CVGetCurrentHostTime() / CVGetHostClockFrequency();
+}
diff --git a/Source/WebCore/platform/graphics/win/QTMovieVisualContext.h b/Source/WebCore/platform/graphics/win/QTMovieVisualContext.h
new file mode 100644
index 0000000..8410208
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieVisualContext.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 QTMovieVisualContext_h
+#define QTMovieVisualContext_h
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+#include "QTMovie.h"
+#include "QTMovieTask.h"
+#include "QTPixelBuffer.h"
+#include <WTF/OwnPtr.h>
+#include <WTF/RefCounted.h>
+
+typedef const struct __CFDictionary* CFDictionaryRef;
+typedef struct OpaqueQTVisualContext* QTVisualContextRef;
+
+// QTCVTimeStamp is a struct containing only a CVTimeStamp. This is to
+// work around the inability of CVTimeStamp to be forward declared, in
+// addition to it being declared in different header files when building
+// the QTMovieWin and WebCore projects.
+struct QTCVTimeStamp;
+
+class QTMovieVisualContextClient {
+public:
+ virtual void imageAvailableForTime(const QTCVTimeStamp*) = 0;
+};
+
+class QTMOVIEWIN_API QTMovieVisualContext : public RefCounted<QTMovieVisualContext> {
+public:
+ static PassRefPtr<QTMovieVisualContext> create(QTMovieVisualContextClient*, QTPixelBuffer::Type);
+ ~QTMovieVisualContext();
+
+ bool isImageAvailableForTime(const QTCVTimeStamp*) const;
+ QTPixelBuffer imageForTime(const QTCVTimeStamp*);
+ void task();
+
+ QTVisualContextRef visualContextRef();
+
+ void setMovie(PassRefPtr<QTMovie>);
+ QTMovie* movie() const;
+
+ static double currentHostTime();
+
+protected:
+ QTMovieVisualContext(QTMovieVisualContextClient*, QTPixelBuffer::Type);
+ void setupVisualContext();
+
+ friend class QTMovieVisualContextPriv;
+ OwnPtr<QTMovieVisualContextPriv> m_private;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp b/Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
new file mode 100644
index 0000000..f6103ea
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 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 if (message == WM_TIMER && wParam == timerID) {
+ stopSharedTimer();
+ sharedTimerFiredFunction();
+ } 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;
+}
+
+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;
+ }
+
+ stopSharedTimer();
+ initializeOffScreenTimerWindow();
+
+ // 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)
+ PostMessage(timerWindowHandle, timerFiredMessage, 0, 0);
+ } else
+ timerID = SetTimer(timerWindowHandle, timerFiredMessage, intervalInMS, 0);
+}
+
+void stopSharedTimer()
+{
+ if (timerID) {
+ KillTimer(timerWindowHandle, 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/Source/WebCore/platform/graphics/win/QTMovieWinTimer.h b/Source/WebCore/platform/graphics/win/QTMovieWinTimer.h
new file mode 100644
index 0000000..976b310
--- /dev/null
+++ b/Source/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 QTMovieWinTimer_h
+#define QTMovieWinTimer_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/Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp b/Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp
new file mode 100644
index 0000000..44a1b0e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "QTPixelBuffer.h"
+
+#include <CFNumber.h>
+#include <CFString.h>
+#include <CGColorSpace.h>
+#include <CGImage.h>
+#include <CVPixelBuffer.h>
+#include <QuickDraw.h>
+#include <memory.h>
+
+static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, CFStringRef inKey, SInt32 inValue)
+{
+ CFNumberRef number;
+
+ number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue);
+ if (!number)
+ return coreFoundationUnknownErr;
+
+ CFDictionarySetValue(inDict, inKey, number);
+ CFRelease(number);
+
+ return noErr;
+}
+
+CFDictionaryRef QTPixelBuffer::createPixelBufferAttributesDictionary(QTPixelBuffer::Type contextType)
+{
+ static const CFStringRef kDirect3DCompatibilityKey = CFSTR("Direct3DCompatibility");
+
+ CFMutableDictionaryRef pixelBufferAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (contextType == QTPixelBuffer::ConfigureForCAImageQueue) {
+ // Ask for D3D compatible pixel buffers so no further work is needed.
+ CFDictionarySetValue(pixelBufferAttributes, kDirect3DCompatibilityKey, kCFBooleanTrue);
+ } else {
+ // Use the k32BGRAPixelFormat, as QuartzCore will be able to use the pixels directly,
+ // without needing an additional copy or rendering pass.
+ SetNumberValue(pixelBufferAttributes, kCVPixelBufferPixelFormatTypeKey, k32BGRAPixelFormat);
+
+ // Set kCVPixelBufferBytesPerRowAlignmentKey to 16 to ensure that each row of pixels
+ // starts at a 16 byte aligned address for most efficient data reading.
+ SetNumberValue(pixelBufferAttributes, kCVPixelBufferBytesPerRowAlignmentKey, 16);
+ CFDictionarySetValue(pixelBufferAttributes, kCVPixelBufferCGImageCompatibilityKey, kCFBooleanTrue);
+ }
+ return pixelBufferAttributes;
+}
+
+QTPixelBuffer::QTPixelBuffer()
+ : m_pixelBuffer(0)
+{
+}
+
+QTPixelBuffer::QTPixelBuffer(const QTPixelBuffer& p)
+ : m_pixelBuffer(p.m_pixelBuffer)
+{
+ CVPixelBufferRetain(m_pixelBuffer);
+}
+
+QTPixelBuffer::QTPixelBuffer(CVPixelBufferRef ref)
+ : m_pixelBuffer(ref)
+{
+ CVPixelBufferRetain(m_pixelBuffer);
+}
+
+QTPixelBuffer::~QTPixelBuffer()
+{
+ clear();
+}
+
+QTPixelBuffer& QTPixelBuffer::operator=(const QTPixelBuffer& p)
+{
+ set(p.m_pixelBuffer);
+ return *this;
+}
+
+void QTPixelBuffer::set(CVPixelBufferRef ref)
+{
+ CVPixelBufferRetain(ref);
+ CVPixelBufferRelease(m_pixelBuffer);
+ m_pixelBuffer = ref;
+}
+
+CVPixelBufferRef QTPixelBuffer::pixelBufferRef()
+{
+ return m_pixelBuffer;
+}
+
+void QTPixelBuffer::adopt(CVPixelBufferRef ref)
+{
+ if (ref == m_pixelBuffer)
+ return;
+ CVPixelBufferRelease(m_pixelBuffer);
+ m_pixelBuffer = ref;
+}
+
+void QTPixelBuffer::clear()
+{
+ CVPixelBufferRelease(m_pixelBuffer);
+ m_pixelBuffer = 0;
+}
+
+CVReturn QTPixelBuffer::lockBaseAddress()
+{
+ return CVPixelBufferLockBaseAddress(m_pixelBuffer, 0);
+}
+
+CVReturn QTPixelBuffer::unlockBaseAddress()
+{
+ return CVPixelBufferUnlockBaseAddress(m_pixelBuffer, 0);
+}
+
+void* QTPixelBuffer::baseAddress()
+{
+ return CVPixelBufferGetBaseAddress(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::width() const
+{
+ return CVPixelBufferGetWidth(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::height() const
+{
+ return CVPixelBufferGetHeight(m_pixelBuffer);
+}
+
+unsigned long QTPixelBuffer::pixelFormatType() const
+{
+ return CVPixelBufferGetPixelFormatType(m_pixelBuffer);
+}
+
+bool QTPixelBuffer::pixelFormatIs32ARGB() const
+{
+ return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32ARGBPixelFormat;
+}
+
+bool QTPixelBuffer::pixelFormatIs32BGRA() const
+{
+ return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32BGRAPixelFormat;
+}
+
+size_t QTPixelBuffer::bytesPerRow() const
+{
+ return CVPixelBufferGetBytesPerRow(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::dataSize() const
+{
+ return CVPixelBufferGetDataSize(m_pixelBuffer);
+}
+
+bool QTPixelBuffer::isPlanar() const
+{
+ return CVPixelBufferIsPlanar(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::planeCount() const
+{
+ return CVPixelBufferGetPlaneCount(m_pixelBuffer);
+}
+
+size_t QTPixelBuffer::widthOfPlane(size_t plane) const
+{
+ return CVPixelBufferGetWidthOfPlane(m_pixelBuffer, plane);
+}
+
+size_t QTPixelBuffer::heightOfPlane(size_t plane) const
+{
+ return CVPixelBufferGetHeightOfPlane(m_pixelBuffer, plane);
+}
+
+void* QTPixelBuffer::baseAddressOfPlane(size_t plane) const
+{
+ return CVPixelBufferGetBaseAddressOfPlane(m_pixelBuffer, plane);
+}
+
+size_t QTPixelBuffer::bytesPerRowOfPlane(size_t plane) const
+{
+ return CVPixelBufferGetBytesPerRowOfPlane(m_pixelBuffer, plane);
+}
+
+void QTPixelBuffer::getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const
+{
+ return CVPixelBufferGetExtendedPixels(m_pixelBuffer, left, right, top, bottom);
+}
+
+CFDictionaryRef QTPixelBuffer::attachments() const
+{
+ return CVBufferGetAttachments(m_pixelBuffer, kCVAttachmentMode_ShouldPropagate);
+}
+
+void QTPixelBuffer::retainCallback(void* refcon)
+{
+ CVPixelBufferRetain(static_cast<CVPixelBufferRef>(refcon));
+}
+
+void QTPixelBuffer::releaseCallback(void* refcon)
+{
+ CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
+}
+
+void QTPixelBuffer::imageQueueReleaseCallback(unsigned int type, uint64_t id, void* refcon)
+{
+ CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
+}
+
+void QTPixelBuffer::dataProviderReleaseBytePointerCallback(void* refcon, const void* pointer)
+{
+ CVPixelBufferUnlockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0);
+}
+
+const void* QTPixelBuffer::dataProviderGetBytePointerCallback(void* refcon)
+{
+ CVPixelBufferLockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0);
+ return CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon));
+}
+
+size_t QTPixelBuffer::dataProviderGetBytesAtPositionCallback(void* refcon, void* buffer, size_t position, size_t count)
+{
+ char* data = (char*)CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon));
+ size_t size = CVPixelBufferGetDataSize(static_cast<CVPixelBufferRef>(refcon));
+ if (size - position < count)
+ count = size - position;
+
+ memcpy(buffer, data+position, count);
+ return count;
+}
+
+void QTPixelBuffer::dataProviderReleaseInfoCallback(void* refcon)
+{
+ CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon));
+}
diff --git a/Source/WebCore/platform/graphics/win/QTPixelBuffer.h b/Source/WebCore/platform/graphics/win/QTPixelBuffer.h
new file mode 100644
index 0000000..13630da
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTPixelBuffer.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 QTPixelBuffer_h
+#define QTPixelBuffer_h
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+#include <stdint.h>
+
+typedef struct __CVBuffer *CVBufferRef;
+typedef CVBufferRef CVPixelBufferRef;
+typedef struct CGImage* CGImageRef;
+typedef int32_t CVReturn;
+typedef const struct __CFDictionary * CFDictionaryRef;
+
+// QTPixelBuffer wraps QuickTime's implementation of CVPixelBuffer, so its functions are
+// safe to call within WebKit.
+class QTMOVIEWIN_API QTPixelBuffer {
+public:
+ enum Type { ConfigureForCGImage, ConfigureForCAImageQueue };
+ static CFDictionaryRef createPixelBufferAttributesDictionary(Type);
+
+ QTPixelBuffer();
+ QTPixelBuffer(const QTPixelBuffer&);
+ QTPixelBuffer(CVPixelBufferRef);
+ QTPixelBuffer& operator=(const QTPixelBuffer&);
+ ~QTPixelBuffer();
+
+ void set(CVPixelBufferRef);
+ CVPixelBufferRef pixelBufferRef();
+ void adopt(CVPixelBufferRef);
+ void clear();
+
+ CVReturn lockBaseAddress();
+ CVReturn unlockBaseAddress();
+ void* baseAddress();
+
+ size_t width() const;
+ size_t height() const;
+ unsigned long pixelFormatType() const;
+ bool pixelFormatIs32ARGB() const;
+ bool pixelFormatIs32BGRA() const;
+ size_t bytesPerRow() const;
+ size_t dataSize() const;
+
+ bool isPlanar() const;
+ size_t planeCount() const;
+ size_t widthOfPlane(size_t) const;
+ size_t heightOfPlane(size_t) const;
+ void* baseAddressOfPlane(size_t) const;
+ size_t bytesPerRowOfPlane(size_t) const;
+
+ void getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const;
+ CFDictionaryRef attachments() const;
+
+ // Generic CFRetain/CFRelease callbacks
+ static void releaseCallback(void* refcon);
+ static void retainCallback(void* refcon);
+
+ // CAImageQueue callbacks
+ static void imageQueueReleaseCallback(unsigned int type, uint64_t id, void* refcon);
+
+ // CGDataProvider callbacks
+ static void dataProviderReleaseBytePointerCallback(void* refcon, const void* pointer);
+ static const void* dataProviderGetBytePointerCallback(void* refcon);
+ static size_t dataProviderGetBytesAtPositionCallback(void* refcon, void* buffer, size_t position, size_t count);
+ static void dataProviderReleaseInfoCallback(void* refcon);
+
+private:
+ CVPixelBufferRef m_pixelBuffer;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/QTTrack.cpp b/Source/WebCore/platform/graphics/win/QTTrack.cpp
new file mode 100644
index 0000000..09142bc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTTrack.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 "QTTrack.h"
+
+#include <Movies.h>
+#include <QTML.h>
+
+using namespace std;
+
+class QTTrackPrivate : public Noncopyable {
+public:
+ QTTrackPrivate();
+ ~QTTrackPrivate();
+
+ QTTrack* m_track;
+ Track m_trackHandle;
+};
+
+QTTrackPrivate::QTTrackPrivate()
+ : m_track(0)
+ , m_trackHandle(0)
+{
+}
+
+QTTrackPrivate::~QTTrackPrivate()
+{
+ m_trackHandle = 0;
+}
+
+PassRefPtr<QTTrack> QTTrack::create(Track trackHandle)
+{
+ return adoptRef(new QTTrack(trackHandle));
+}
+
+QTTrack::QTTrack(Track trackHandle)
+ : m_private(new QTTrackPrivate())
+{
+ m_private->m_track = this;
+ m_private->m_trackHandle = trackHandle;
+}
+
+QTTrack::~QTTrack()
+{
+ delete m_private;
+}
+
+bool QTTrack::isEnabled() const
+{
+ ASSERT(m_private->m_track);
+ return GetTrackEnabled(m_private->m_trackHandle);
+}
+
+void QTTrack::setEnabled(bool enabled)
+{
+ ASSERT(m_private->m_trackHandle);
+ SetTrackEnabled(m_private->m_trackHandle, enabled);
+}
+
+CGAffineTransform QTTrack::getTransform() const
+{
+ ASSERT(m_private->m_trackHandle);
+ MatrixRecord m = {0};
+ GetTrackMatrix(m_private->m_trackHandle, &m);
+
+ ASSERT(!m.matrix[0][2]);
+ ASSERT(!m.matrix[1][2]);
+ CGAffineTransform transform = CGAffineTransformMake(
+ Fix2X(m.matrix[0][0]),
+ Fix2X(m.matrix[0][1]),
+ Fix2X(m.matrix[1][0]),
+ Fix2X(m.matrix[1][1]),
+ Fix2X(m.matrix[2][0]),
+ Fix2X(m.matrix[2][1]));
+
+ return transform;
+}
+
+void QTTrack::setTransform(CGAffineTransform t)
+{
+ ASSERT(m_private->m_trackHandle);
+ MatrixRecord m = {{
+ {X2Fix(t.a), X2Fix(t.b), 0},
+ {X2Fix(t.c), X2Fix(t.d), 0},
+ {X2Fix(t.tx), X2Fix(t.ty), fract1},
+ }};
+
+ SetTrackMatrix(m_private->m_trackHandle, &m);
+}
+
+void QTTrack::resetTransform()
+{
+ ASSERT(m_private->m_trackHandle);
+ SetTrackMatrix(m_private->m_trackHandle, 0);
+}
+
diff --git a/Source/WebCore/platform/graphics/win/QTTrack.h b/Source/WebCore/platform/graphics/win/QTTrack.h
new file mode 100644
index 0000000..bda5644
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/QTTrack.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 QTTrack_h
+#define QTTrack_h
+
+#include <Unicode.h>
+#include <windows.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+// We must include this after <Unicode.h>, or the definition of OSErr will change:
+#include <CoreGraphics/CGAffineTransform.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTTrack;
+class QTTrackPrivate;
+typedef struct TrackType** Track;
+
+class QTMOVIEWIN_API QTTrack : public RefCounted<QTTrack> {
+public:
+ static PassRefPtr<QTTrack> create(Track);
+ ~QTTrack();
+
+ CGAffineTransform getTransform() const;
+ void setTransform(CGAffineTransform);
+ void resetTransform();
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ Track getTrackHandle() const;
+private:
+ QTTrack(Track);
+ QTTrackPrivate* m_private;
+ friend class QTTrackPrivate;
+};
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h b/Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h
new file mode 100644
index 0000000..65f66f1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2010 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 RefCountedGDIHandle_h
+#define RefCountedGDIHandle_h
+
+#include <windows.h>
+#include <wtf/HashFunctions.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+template <typename T> class RefCountedGDIHandle : public RefCounted<RefCountedGDIHandle<T> > {
+public:
+ static PassRefPtr<RefCountedGDIHandle> create(T handle)
+ {
+ return adoptRef(new RefCountedGDIHandle<T>(handle));
+ }
+
+ static PassRefPtr<RefCountedGDIHandle<T> > createDeleted()
+ {
+ return adoptRef(new RefCountedGDIHandle<T>(reinterpret_cast<T>(-1)));
+ }
+
+ ~RefCountedGDIHandle()
+ {
+ if (m_handle != reinterpret_cast<T>(-1))
+ WTF::deleteOwnedPtr(m_handle);
+ }
+
+ T handle() const
+ {
+ return m_handle;
+ }
+
+ unsigned hash() const
+ {
+ return WTF::PtrHash<T>::hash(m_handle);
+ }
+
+private:
+ RefCountedGDIHandle(T handle)
+ : m_handle(handle)
+ {
+ }
+
+ T m_handle;
+};
+
+} // namespace WebCore
+
+#endif // RefCountedGDIHandle_h
diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
new file mode 100644
index 0000000..20d42ff
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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_platformData.syntheticBold() ? 1.0f : 0.f;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+
+ if (m_platformData.useGDI())
+ return initGDIFont();
+
+ CGFontRef font = m_platformData.cgFont();
+ int iAscent = CGFontGetAscent(font);
+ int iDescent = CGFontGetDescent(font);
+ int iLineGap = CGFontGetLeading(font);
+ m_unitsPerEm = CGFontGetUnitsPerEm(font);
+ float pointSize = m_platformData.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_platformData.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::platformCharWidthInit()
+{
+ // GDI Fonts init charwidths in initGDIFont.
+ if (!m_platformData.useGDI()) {
+ m_avgCharWidth = 0.f;
+ m_maxCharWidth = 0.f;
+ initCharWidths();
+ }
+}
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const
+{
+ if (m_platformData.useGDI())
+ return boundsForGDIGlyph(glyph);
+
+ CGRect box;
+ CGFontGetGlyphBBoxes(m_platformData.cgFont(), &glyph, 1, &box);
+ float pointSize = m_platformData.size();
+ CGFloat scale = pointSize / unitsPerEm();
+ FloatRect boundingBox = CGRectApplyAffineTransform(box, CGAffineTransformMakeScale(scale, -scale));
+ if (m_syntheticBoldOffset)
+ boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset);
+
+ return boundingBox;
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_platformData.useGDI())
+ return widthForGDIGlyph(glyph);
+
+ CGFontRef font = m_platformData.cgFont();
+ float pointSize = m_platformData.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/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
new file mode 100644
index 0000000..62ea060
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 <cairo.h>
+#include <cairo-win32.h>
+#include <mlang.h>
+#include <tchar.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+
+ m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f;
+
+ if (m_platformData.useGDI())
+ return initGDIFont();
+
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ cairo_scaled_font_t* scaledFont = m_platformData.scaledFont();
+ const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_platformData.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;
+ m_avgCharWidth = lroundf(textMetrics.tmAveCharWidth * metricsMultiplier);
+ m_maxCharWidth = lroundf(textMetrics.tmMaxCharWidth * metricsMultiplier);
+
+ 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::platformCharWidthInit()
+{
+ // charwidths are set in platformInit.
+}
+
+FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const
+{
+ if (m_platformData.useGDI())
+ return boundsForGDIGlyph(glyph);
+ //FIXME: Implement this
+ return FloatRect();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_platformData.useGDI())
+ return widthForGDIGlyph(glyph);
+
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ cairo_scaled_font_t* scaledFont = m_platformData.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_platformData.size();
+ return width * metricsMultiplier;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
new file mode 100644
index 0000000..60afe6a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -0,0 +1,259 @@
+/*
+ * 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 <mlang.h>
+#include <tchar.h>
+
+#if PLATFORM(CG)
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+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()
+{
+ if (!m_platformData.size()) {
+ m_ascent = 0;
+ m_descent = 0;
+ m_lineGap = 0;
+ m_lineSpacing = 0;
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+ m_xHeight = 0;
+ m_unitsPerEm = 0;
+ return;
+ }
+
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_platformData.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_avgCharWidth = textMetrics.tmAveCharWidth;
+ m_maxCharWidth = textMetrics.tmMaxCharWidth;
+ 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::platformDestroy()
+{
+ ScriptFreeCache(&m_scriptCache);
+ delete m_scriptFontProperties;
+}
+
+SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
+{
+ float scaledSize = scaleFactor * m_platformData.size();
+ if (isCustomFont()) {
+ FontPlatformData scaledFont(m_platformData);
+ scaledFont.setSize(scaledSize);
+ return new SimpleFontData(scaledFont, true, false);
+ }
+
+ LOGFONT winfont;
+ GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont);
+ winfont.lfHeight = -lroundf(scaledSize * (m_platformData.useGDI() ? 1 : 32));
+ HFONT hfont = CreateFontIndirect(&winfont);
+ return new SimpleFontData(FontPlatformData(hfont, scaledSize, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI()), isCustomFont(), false);
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->smallCaps)
+ m_derivedFontData->smallCaps = scaledFontData(fontDescription, cSmallCapsFontSizeMultiplier);
+
+ return m_derivedFontData->smallCaps.get();
+}
+
+SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
+{
+ if (!m_derivedFontData)
+ m_derivedFontData = DerivedFontData::create(isCustomFont());
+ if (!m_derivedFontData->emphasisMark)
+ m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5);
+
+ return m_derivedFontData->emphasisMark.get();
+}
+
+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_platformData.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_platformData.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);
+}
+
+FloatRect SimpleFontData::boundsForGDIGlyph(Glyph glyph) const
+{
+ HDC hdc = GetDC(0);
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
+
+ GLYPHMETRICS gdiMetrics;
+ static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 };
+ GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity);
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y,
+ gdiMetrics.gmBlackBoxX + m_syntheticBoldOffset, gdiMetrics.gmBlackBoxY);
+}
+
+float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
+{
+ HDC hdc = GetDC(0);
+ SetGraphicsMode(hdc, GM_ADVANCED);
+ HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont());
+
+ GLYPHMETRICS gdiMetrics;
+ static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 };
+ GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity);
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return gdiMetrics.gmCellIncX + 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_platformData.hfont());
+ ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties);
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+ }
+ }
+ return m_scriptFontProperties;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp b/Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
new file mode 100644
index 0000000..47806a2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 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 "TransformationMatrix.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+TransformationMatrix::operator XFORM() const
+{
+ XFORM xform;
+ xform.eM11 = a();
+ xform.eM12 = b();
+ xform.eM21 = c();
+ xform.eM22 = d();
+ xform.eDx = e();
+ xform.eDy = f();
+
+ return xform;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/win/UniscribeController.cpp b/Source/WebCore/platform/graphics/win/UniscribeController.cpp
new file mode 100644
index 0000000..ab32150
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/UniscribeController.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 INC. 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 INC. 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>
+
+using namespace std;
+
+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, HashSet<const SimpleFontData*>* fallbackFonts)
+ : m_font(*font)
+ , m_run(run)
+ , m_fallbackFonts(fallbackFonts)
+ , m_minGlyphBoundingBoxX(numeric_limits<float>::max())
+ , m_maxGlyphBoundingBoxX(numeric_limits<float>::min())
+ , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
+ , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
+ , m_end(run.length())
+ , m_currentCharacter(0)
+ , m_runWidthSoFar(0)
+ , m_padding(run.padding())
+ , m_computingOffsetPosition(false)
+ , m_includePartialGlyphs(false)
+ , m_offsetX(0)
+ , m_offsetPosition(0)
+{
+ 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 = m_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 ? SmallCapsVariant : AutoVariant).fontData;
+ if (m_font.isSmallCaps()) {
+ nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c;
+ if (nextIsSmallCaps)
+ smallCapsBuffer[index] = forceSmallCaps ? c : newC;
+ }
+
+ if (m_fallbackFonts && nextFontData != fontData && fontData != m_font.primaryFont())
+ m_fallbackFonts->add(fontData);
+
+ 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) {
+ if (m_fallbackFonts && nextFontData != m_font.primaryFont())
+ m_fallbackFonts->add(nextFontData);
+
+ 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->platformData().useGDI() ? 1.0f : 32.0f;
+ unsigned logicalSpaceWidth = fontData->spaceWidth() * cLogicalScale;
+ float roundedSpaceWidth = roundf(fontData->spaceWidth());
+
+ for (int k = 0; k < len; k++) {
+ UChar ch = *(str + k);
+ bool treatAsSpace = Font::treatAsSpace(ch);
+ bool treatAsZeroWidthSpace = ch == zeroWidthSpace || Font::treatAsZeroWidthSpace(ch);
+ if (treatAsSpace || treatAsZeroWidthSpace) {
+ // Substitute in the space glyph at the appropriate place in the glyphs
+ // array.
+ glyphs[clusters[k]] = fontData->spaceGlyph();
+ advances[clusters[k]] = treatAsSpace ? logicalSpaceWidth : 0;
+ if (treatAsSpace)
+ 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()) {
+ // When at the last character in the str, don't look one past the end for a rounding hack character.
+ // Instead look ahead to the first character of next item, if there is a next one.
+ if (k + 1 == len) {
+ if (i + 2 < m_items.size() // Check for at least 2 items remaining. The last item is a terminating item containing no characters.
+ && Font::isRoundingHackCharacter(*(cp + m_items[i + 1].iCharPos)))
+ roundingHackWordBoundaries[clusters[k]] = boundary;
+ } else if (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->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->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) &&
+ m_run.applyWordRounding())
+ advance = fontData->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.
+ int characterIndex = spaceCharacters[k];
+ // characterIndex is left at the initial value of -1 for glyphs that do not map back to treated-as-space characters.
+ if (characterIndex != -1) {
+ // 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 {
+ float previousPadding = m_padding;
+ m_padding -= m_padPerSpace;
+ advance += roundf(previousPadding) - roundf(m_padding);
+ }
+ }
+
+ // Account for word-spacing.
+ 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);
+ }
+
+ FloatRect glyphBounds = fontData->boundsForGlyph(glyph);
+ glyphBounds.move(m_glyphOrigin.x(), m_glyphOrigin.y());
+ m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x());
+ m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.right());
+ m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y());
+ m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.bottom());
+ m_glyphOrigin.move(advance + offsetX, -offsetY);
+
+ // 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/Source/WebCore/platform/graphics/win/UniscribeController.h b/Source/WebCore/platform/graphics/win/UniscribeController.h
new file mode 100644
index 0000000..162ddbe
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/UniscribeController.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010 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 INC. 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 INC. 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&, HashSet<const SimpleFontData*>* fallbackFonts = 0);
+
+ // 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; }
+
+ float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; }
+ float maxGlyphBoundingBoxX() const { return m_maxGlyphBoundingBoxX; }
+ float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; }
+ float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; }
+
+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;
+ HashSet<const SimpleFontData*>* m_fallbackFonts;
+ FloatPoint m_glyphOrigin;
+ float m_minGlyphBoundingBoxX;
+ float m_maxGlyphBoundingBoxX;
+ float m_minGlyphBoundingBoxY;
+ float m_maxGlyphBoundingBoxY;
+
+ 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
diff --git a/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp b/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp
new file mode 100644
index 0000000..d75c854
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2009 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 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 USE(ACCELERATED_COMPOSITING)
+
+#include "WKCACFContextFlusher.h"
+
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+WKCACFContextFlusher& WKCACFContextFlusher::shared()
+{
+ DEFINE_STATIC_LOCAL(WKCACFContextFlusher, flusher, ());
+ return flusher;
+}
+
+WKCACFContextFlusher::WKCACFContextFlusher()
+{
+}
+
+WKCACFContextFlusher::~WKCACFContextFlusher()
+{
+}
+
+void WKCACFContextFlusher::addContext(WKCACFContext* context)
+{
+ ASSERT(context);
+
+ m_contexts.add(context);
+}
+
+void WKCACFContextFlusher::removeContext(WKCACFContext* context)
+{
+ ASSERT(context);
+
+ m_contexts.remove(context);
+}
+
+void WKCACFContextFlusher::flushAllContexts()
+{
+ // addContext might get called beneath CACFContextFlush, and we don't want m_contexts to change while
+ // we're iterating over it, so we move the contexts into a local ContextSet and iterate over that instead.
+ ContextSet contextsToFlush;
+ contextsToFlush.swap(m_contexts);
+
+ ContextSet::const_iterator end = contextsToFlush.end();
+ for (ContextSet::const_iterator it = contextsToFlush.begin(); it != end; ++it)
+ wkCACFContextFlush(*it);
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h b/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h
new file mode 100644
index 0000000..17ec41d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 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 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 WKCACFContextFlusher_h
+#define WKCACFContextFlusher_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include <wtf/Noncopyable.h>
+
+#include <wtf/HashSet.h>
+
+struct WKCACFContext;
+
+namespace WebCore {
+
+class WKCACFContextFlusher : public Noncopyable {
+public:
+ static WKCACFContextFlusher& shared();
+
+ void addContext(WKCACFContext*);
+ void removeContext(WKCACFContext*);
+
+ void flushAllContexts();
+
+private:
+ WKCACFContextFlusher();
+ ~WKCACFContextFlusher();
+
+ typedef HashSet<WKCACFContext*> ContextSet;
+ ContextSet m_contexts;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WKCACFContextFlusher_h
diff --git a/Source/WebCore/platform/graphics/win/WKCACFLayer.cpp b/Source/WebCore/platform/graphics/win/WKCACFLayer.cpp
new file mode 100644
index 0000000..a8714e3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFLayer.cpp
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2009 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 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 USE(ACCELERATED_COMPOSITING)
+
+#include "WKCACFLayer.h"
+
+#include "WKCACFLayerRenderer.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <stdio.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+using namespace std;
+
+#ifndef NDEBUG
+void WKCACFLayer::internalCheckLayerConsistency()
+{
+ ASSERT(layer());
+ size_t n = sublayerCount();
+ for (size_t i = 0; i < n; ++i) {
+ // This will ASSERT in internalSublayerAtIndex if this entry doesn't have proper user data
+ WKCACFLayer* sublayer = internalSublayerAtIndex(i);
+
+ // Make sure we don't have any null entries in the list
+ ASSERT(sublayer);
+
+ // Make sure the each layer has a corresponding CACFLayer
+ ASSERT(sublayer->layer());
+ }
+}
+#endif
+
+static void displayCallback(CACFLayerRef layer, CGContextRef context)
+{
+ ASSERT_ARG(layer, WKCACFLayer::layer(layer));
+ WKCACFLayer::layer(layer)->drawInContext(context);
+}
+
+static CFStringRef toCACFLayerType(WKCACFLayer::LayerType type)
+{
+ switch (type) {
+ case WKCACFLayer::Layer: return kCACFLayer;
+ case WKCACFLayer::TransformLayer: return kCACFTransformLayer;
+ default: return 0;
+ }
+}
+
+static CFStringRef toCACFContentsGravityType(WKCACFLayer::ContentsGravityType type)
+{
+ switch (type) {
+ case WKCACFLayer::Center: return kCACFGravityCenter;
+ case WKCACFLayer::Top: return kCACFGravityTop;
+ case WKCACFLayer::Bottom: return kCACFGravityBottom;
+ case WKCACFLayer::Left: return kCACFGravityLeft;
+ case WKCACFLayer::Right: return kCACFGravityRight;
+ case WKCACFLayer::TopLeft: return kCACFGravityTopLeft;
+ case WKCACFLayer::TopRight: return kCACFGravityTopRight;
+ case WKCACFLayer::BottomLeft: return kCACFGravityBottomLeft;
+ case WKCACFLayer::BottomRight: return kCACFGravityBottomRight;
+ case WKCACFLayer::Resize: return kCACFGravityResize;
+ case WKCACFLayer::ResizeAspect: return kCACFGravityResizeAspect;
+ case WKCACFLayer::ResizeAspectFill: return kCACFGravityResizeAspectFill;
+ default: return 0;
+ }
+}
+
+static WKCACFLayer::ContentsGravityType fromCACFContentsGravityType(CFStringRef string)
+{
+ if (CFEqual(string, kCACFGravityTop))
+ return WKCACFLayer::Top;
+
+ if (CFEqual(string, kCACFGravityBottom))
+ return WKCACFLayer::Bottom;
+
+ if (CFEqual(string, kCACFGravityLeft))
+ return WKCACFLayer::Left;
+
+ if (CFEqual(string, kCACFGravityRight))
+ return WKCACFLayer::Right;
+
+ if (CFEqual(string, kCACFGravityTopLeft))
+ return WKCACFLayer::TopLeft;
+
+ if (CFEqual(string, kCACFGravityTopRight))
+ return WKCACFLayer::TopRight;
+
+ if (CFEqual(string, kCACFGravityBottomLeft))
+ return WKCACFLayer::BottomLeft;
+
+ if (CFEqual(string, kCACFGravityBottomRight))
+ return WKCACFLayer::BottomRight;
+
+ if (CFEqual(string, kCACFGravityResize))
+ return WKCACFLayer::Resize;
+
+ if (CFEqual(string, kCACFGravityResizeAspect))
+ return WKCACFLayer::ResizeAspect;
+
+ if (CFEqual(string, kCACFGravityResizeAspectFill))
+ return WKCACFLayer::ResizeAspectFill;
+
+ return WKCACFLayer::Center;
+}
+
+static CFStringRef toCACFFilterType(WKCACFLayer::FilterType type)
+{
+ switch (type) {
+ case WKCACFLayer::Linear: return kCACFFilterLinear;
+ case WKCACFLayer::Nearest: return kCACFFilterNearest;
+ case WKCACFLayer::Trilinear: return kCACFFilterTrilinear;
+ default: return 0;
+ }
+}
+
+static WKCACFLayer::FilterType fromCACFFilterType(CFStringRef string)
+{
+ if (CFEqual(string, kCACFFilterNearest))
+ return WKCACFLayer::Nearest;
+
+ if (CFEqual(string, kCACFFilterTrilinear))
+ return WKCACFLayer::Trilinear;
+
+ return WKCACFLayer::Linear;
+}
+
+PassRefPtr<WKCACFLayer> WKCACFLayer::create(LayerType type)
+{
+ if (!WKCACFLayerRenderer::acceleratedCompositingAvailable())
+ return 0;
+ return adoptRef(new WKCACFLayer(type));
+}
+
+// FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually
+// get destroyed in debug builds. A static counter could accomplish this pretty easily.
+
+WKCACFLayer::WKCACFLayer(LayerType type)
+ : m_layer(AdoptCF, CACFLayerCreate(toCACFLayerType(type)))
+ , m_layoutClient(0)
+ , m_needsDisplayOnBoundsChange(false)
+{
+ CACFLayerSetUserData(layer(), this);
+ CACFLayerSetDisplayCallback(layer(), displayCallback);
+}
+
+WKCACFLayer::~WKCACFLayer()
+{
+ // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer.
+ ASSERT(!superlayer());
+
+ // Get rid of the children so we don't have any dangling references around
+ removeAllSublayers();
+
+#ifndef NDEBUG
+ CACFLayerSetUserData(layer(), reinterpret_cast<void*>(0xDEADBEEF));
+#else
+ CACFLayerSetUserData(layer(), 0);
+#endif
+ CACFLayerSetDisplayCallback(layer(), 0);
+}
+
+void WKCACFLayer::becomeRootLayerForContext(WKCACFContext* context)
+{
+ wkCACFContextSetLayer(context, layer());
+ setNeedsCommit();
+}
+
+void WKCACFLayer::setNeedsCommit()
+{
+ WKCACFLayer* root = rootLayer();
+
+ // Call setNeedsRender on the root layer, which will cause a render to
+ // happen in WKCACFLayerRenderer
+ root->setNeedsRender();
+}
+
+bool WKCACFLayer::isTransformLayer() const
+{
+ return CACFLayerGetClass(layer()) == kCACFTransformLayer;
+}
+
+void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer)
+{
+ insertSublayer(sublayer, sublayerCount());
+}
+
+void WKCACFLayer::internalInsertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index)
+{
+ index = min(index, sublayerCount() + 1);
+ sublayer->removeFromSuperlayer();
+ CACFLayerInsertSublayer(layer(), sublayer->layer(), index);
+ setNeedsCommit();
+ checkLayerConsistency();
+}
+
+void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference)
+{
+ if (!reference) {
+ insertSublayer(sublayer, 0);
+ return;
+ }
+
+ int referenceIndex = internalIndexOfSublayer(reference);
+ if (referenceIndex == -1) {
+ addSublayer(sublayer);
+ return;
+ }
+
+ insertSublayer(sublayer, referenceIndex + 1);
+}
+
+void WKCACFLayer::insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference)
+{
+ if (!reference) {
+ insertSublayer(sublayer, 0);
+ return;
+ }
+
+ int referenceIndex = internalIndexOfSublayer(reference);
+ if (referenceIndex == -1) {
+ addSublayer(sublayer);
+ return;
+ }
+
+ insertSublayer(sublayer, referenceIndex);
+}
+
+void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer> newLayer)
+{
+ ASSERT_ARG(reference, reference);
+ ASSERT_ARG(reference, reference->superlayer() == this);
+
+ if (reference == newLayer)
+ return;
+
+ int referenceIndex = internalIndexOfSublayer(reference);
+ ASSERT(referenceIndex != -1);
+ if (referenceIndex == -1)
+ return;
+
+ reference->removeFromSuperlayer();
+
+ if (newLayer) {
+ newLayer->removeFromSuperlayer();
+ insertSublayer(newLayer, referenceIndex);
+ }
+}
+
+size_t WKCACFLayer::internalSublayerCount() const
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer());
+ return sublayers ? CFArrayGetCount(sublayers) : 0;
+}
+
+void WKCACFLayer::adoptSublayers(WKCACFLayer* source)
+{
+ // We will use setSublayers() because it properly nulls
+ // out the superlayer pointer.
+ Vector<RefPtr<WKCACFLayer> > sublayers;
+ size_t n = source->sublayerCount();
+
+ for (size_t i = 0; i < n; ++i)
+ sublayers.append(source->internalSublayerAtIndex(i));
+
+ setSublayers(sublayers);
+ source->checkLayerConsistency();
+}
+
+void WKCACFLayer::removeFromSuperlayer()
+{
+ WKCACFLayer* superlayer = this->superlayer();
+ CACFLayerRemoveFromSuperlayer(layer());
+ checkLayerConsistency();
+
+ if (superlayer)
+ superlayer->setNeedsCommit();
+}
+
+WKCACFLayer* WKCACFLayer::internalSublayerAtIndex(int index) const
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer());
+ if (!sublayers || index < 0 || CFArrayGetCount(sublayers) <= index)
+ return 0;
+
+ return layer(static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index))));
+}
+
+int WKCACFLayer::internalIndexOfSublayer(const WKCACFLayer* reference)
+{
+ CACFLayerRef ref = reference->layer();
+ if (!ref)
+ return -1;
+
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer());
+ if (!sublayers)
+ return -1;
+
+ size_t n = CFArrayGetCount(sublayers);
+
+ for (size_t i = 0; i < n; ++i)
+ if (CFArrayGetValueAtIndex(sublayers, i) == ref)
+ return i;
+
+ return -1;
+}
+
+WKCACFLayer* WKCACFLayer::ancestorOrSelfWithSuperlayer(WKCACFLayer* superlayer) const
+{
+ WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
+ for (WKCACFLayer* ancestor = this->superlayer(); ancestor; layer = ancestor, ancestor = ancestor->superlayer()) {
+ if (ancestor == superlayer)
+ return layer;
+ }
+ return 0;
+}
+
+void WKCACFLayer::setBounds(const CGRect& rect)
+{
+ if (CGRectEqualToRect(rect, bounds()))
+ return;
+
+ CACFLayerSetBounds(layer(), rect);
+ setNeedsCommit();
+
+ if (m_needsDisplayOnBoundsChange)
+ setNeedsDisplay();
+
+ if (m_layoutClient)
+ setNeedsLayout();
+}
+
+void WKCACFLayer::setFrame(const CGRect& rect)
+{
+ CGRect oldFrame = frame();
+ if (CGRectEqualToRect(rect, oldFrame))
+ return;
+
+ CACFLayerSetFrame(layer(), rect);
+ setNeedsCommit();
+
+ if (m_needsDisplayOnBoundsChange && !CGSizeEqualToSize(rect.size, oldFrame.size))
+ setNeedsDisplay();
+
+ if (m_layoutClient)
+ setNeedsLayout();
+}
+
+void WKCACFLayer::setContentsGravity(ContentsGravityType type)
+{
+ CACFLayerSetContentsGravity(layer(), toCACFContentsGravityType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::ContentsGravityType WKCACFLayer::contentsGravity() const
+{
+ return fromCACFContentsGravityType(CACFLayerGetContentsGravity(layer()));
+}
+
+void WKCACFLayer::setMagnificationFilter(FilterType type)
+{
+ CACFLayerSetMagnificationFilter(layer(), toCACFFilterType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::FilterType WKCACFLayer::magnificationFilter() const
+{
+ return fromCACFFilterType(CACFLayerGetMagnificationFilter(layer()));
+}
+
+void WKCACFLayer::setMinificationFilter(FilterType type)
+{
+ CACFLayerSetMinificationFilter(layer(), toCACFFilterType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::FilterType WKCACFLayer::minificationFilter() const
+{
+ return fromCACFFilterType(CACFLayerGetMinificationFilter(layer()));
+}
+
+WKCACFLayer* WKCACFLayer::rootLayer() const
+{
+ WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
+ for (WKCACFLayer* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { }
+ return layer;
+}
+
+void WKCACFLayer::internalRemoveAllSublayers()
+{
+ CACFLayerSetSublayers(layer(), 0);
+ setNeedsCommit();
+}
+
+void WKCACFLayer::internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers)
+{
+ // Remove all the current sublayers and add the passed layers
+ CACFLayerSetSublayers(layer(), 0);
+
+ // Perform removeFromSuperLayer in a separate pass. CACF requires superlayer to
+ // be null or CACFLayerInsertSublayer silently fails.
+ for (size_t i = 0; i < sublayers.size(); i++)
+ CACFLayerRemoveFromSuperlayer(sublayers[i]->layer());
+
+ for (size_t i = 0; i < sublayers.size(); i++)
+ CACFLayerInsertSublayer(layer(), sublayers[i]->layer(), i);
+
+ setNeedsCommit();
+}
+
+WKCACFLayer* WKCACFLayer::superlayer() const
+{
+ CACFLayerRef super = CACFLayerGetSuperlayer(layer());
+ if (!super)
+ return 0;
+ return WKCACFLayer::layer(super);
+}
+
+void WKCACFLayer::internalSetNeedsDisplay(const CGRect* dirtyRect)
+{
+ CACFLayerSetNeedsDisplay(layer(), dirtyRect);
+}
+
+void WKCACFLayer::setLayoutClient(WKCACFLayerLayoutClient* layoutClient)
+{
+ if (layoutClient == m_layoutClient)
+ return;
+
+ m_layoutClient = layoutClient;
+ CACFLayerSetLayoutCallback(layer(), m_layoutClient ? layoutSublayersProc : 0);
+}
+
+void WKCACFLayer::layoutSublayersProc(CACFLayerRef caLayer)
+{
+ WKCACFLayer* layer = WKCACFLayer::layer(caLayer);
+ if (layer && layer->m_layoutClient)
+ layer->m_layoutClient->layoutSublayersOfLayer(layer);
+}
+
+#ifndef NDEBUG
+static void printIndent(int indent)
+{
+ for ( ; indent > 0; --indent)
+ fprintf(stderr, " ");
+}
+
+static void printTransform(const CATransform3D& transform)
+{
+ fprintf(stderr, "[%g %g %g %g; %g %g %g %g; %g %g %g %g; %g %g %g %g]",
+ transform.m11, transform.m12, transform.m13, transform.m14,
+ transform.m21, transform.m22, transform.m23, transform.m24,
+ transform.m31, transform.m32, transform.m33, transform.m34,
+ transform.m41, transform.m42, transform.m43, transform.m44);
+}
+
+void WKCACFLayer::printTree() const
+{
+ // Print heading info
+ CGRect rootBounds = bounds();
+ fprintf(stderr, "\n\n** Render tree at time %g (bounds %g, %g %gx%g) **\n\n",
+ currentTime(), rootBounds.origin.x, rootBounds.origin.y, rootBounds.size.width, rootBounds.size.height);
+
+ // Print layer tree from the root
+ printLayer(0);
+}
+
+void WKCACFLayer::printLayer(int indent) const
+{
+ CGPoint layerPosition = position();
+ CGPoint layerAnchorPoint = anchorPoint();
+ CGRect layerBounds = bounds();
+ printIndent(indent);
+ fprintf(stderr, "(%s [%g %g %g] [%g %g %g %g] [%g %g %g] superlayer=%p\n",
+ isTransformLayer() ? "transform-layer" : "layer",
+ layerPosition.x, layerPosition.y, zPosition(),
+ layerBounds.origin.x, layerBounds.origin.y, layerBounds.size.width, layerBounds.size.height,
+ layerAnchorPoint.x, layerAnchorPoint.y, anchorPointZ(), superlayer());
+
+ // Print name if needed
+ String layerName = name();
+ if (!layerName.isEmpty()) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(name %s)\n", layerName.utf8().data());
+ }
+
+ // Print masksToBounds if needed
+ bool layerMasksToBounds = masksToBounds();
+ if (layerMasksToBounds) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(masksToBounds true)\n");
+ }
+
+ // Print opacity if needed
+ float layerOpacity = opacity();
+ if (layerOpacity != 1) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(opacity %hf)\n", layerOpacity);
+ }
+
+ // Print sublayerTransform if needed
+ CATransform3D layerTransform = sublayerTransform();
+ if (!CATransform3DIsIdentity(layerTransform)) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(sublayerTransform ");
+ printTransform(layerTransform);
+ fprintf(stderr, ")\n");
+ }
+
+ // Print transform if needed
+ layerTransform = transform();
+ if (!CATransform3DIsIdentity(layerTransform)) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(transform ");
+ printTransform(layerTransform);
+ fprintf(stderr, ")\n");
+ }
+
+ // Print contents if needed
+ CFTypeRef layerContents = contents();
+ if (layerContents) {
+ if (CFGetTypeID(layerContents) == CGImageGetTypeID()) {
+ CGImageRef imageContents = static_cast<CGImageRef>(const_cast<void*>(layerContents));
+ printIndent(indent + 1);
+ fprintf(stderr, "(contents (image [%d %d]))\n",
+ CGImageGetWidth(imageContents), CGImageGetHeight(imageContents));
+ }
+ }
+
+ // Print sublayers if needed
+ int n = sublayerCount();
+ if (n > 0) {
+ printIndent(indent + 1);
+ fprintf(stderr, "(sublayers\n");
+ for (int i = 0; i < n; ++i)
+ internalSublayerAtIndex(i)->printLayer(indent + 2);
+
+ printIndent(indent + 1);
+ fprintf(stderr, ")\n");
+ }
+
+ printIndent(indent);
+ fprintf(stderr, ")\n");
+}
+#endif // #ifndef NDEBUG
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WKCACFLayer.h b/Source/WebCore/platform/graphics/win/WKCACFLayer.h
new file mode 100644
index 0000000..4c6639a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFLayer.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2009 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 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 WKCACFLayer_h
+#define WKCACFLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include <wtf/RefCounted.h>
+
+#include <QuartzCore/CACFLayer.h>
+#include <QuartzCore/CACFVector.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include "TransformationMatrix.h"
+
+struct WKCACFContext;
+
+namespace WebCore {
+
+class WKCACFLayer;
+
+class WKCACFLayerLayoutClient {
+public:
+ virtual void layoutSublayersOfLayer(WKCACFLayer*) = 0;
+protected:
+ virtual ~WKCACFLayerLayoutClient() {}
+};
+
+class WKCACFLayer : public RefCounted<WKCACFLayer> {
+public:
+ enum LayerType { Layer, TransformLayer };
+ enum FilterType { Linear, Nearest, Trilinear };
+ enum ContentsGravityType { Center, Top, Bottom, Left, Right, TopLeft, TopRight,
+ BottomLeft, BottomRight, Resize, ResizeAspect, ResizeAspectFill };
+
+ static PassRefPtr<WKCACFLayer> create(LayerType);
+ static WKCACFLayer* layer(CACFLayerRef layer)
+ {
+ ASSERT(CACFLayerGetUserData(layer) != reinterpret_cast<void*>(0xDEADBEEF));
+ return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer));
+ }
+
+ virtual ~WKCACFLayer();
+
+ virtual void setNeedsRender() { }
+
+ virtual void drawInContext(PlatformGraphicsContext*) { }
+
+ void setLayoutClient(WKCACFLayerLayoutClient*);
+ WKCACFLayerLayoutClient* layoutClient() const { return m_layoutClient; }
+ void setNeedsLayout() { CACFLayerSetNeedsLayout(layer()); }
+
+ void setNeedsDisplay(const CGRect* dirtyRect = 0)
+ {
+ internalSetNeedsDisplay(dirtyRect);
+ setNeedsCommit();
+ }
+
+ // Makes this layer the root when the passed context is rendered
+ void becomeRootLayerForContext(WKCACFContext*);
+
+ static RetainPtr<CFTypeRef> cfValue(float value) { return RetainPtr<CFTypeRef>(AdoptCF, CFNumberCreate(0, kCFNumberFloat32Type, &value)); }
+ static RetainPtr<CFTypeRef> cfValue(const TransformationMatrix& value)
+ {
+ CATransform3D t;
+ t.m11 = value.m11();
+ t.m12 = value.m12();
+ t.m13 = value.m13();
+ t.m14 = value.m14();
+ t.m21 = value.m21();
+ t.m22 = value.m22();
+ t.m23 = value.m23();
+ t.m24 = value.m24();
+ t.m31 = value.m31();
+ t.m32 = value.m32();
+ t.m33 = value.m33();
+ t.m34 = value.m34();
+ t.m41 = value.m41();
+ t.m42 = value.m42();
+ t.m43 = value.m43();
+ t.m44 = value.m44();
+ return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreateTransform(t));
+ }
+ static RetainPtr<CFTypeRef> cfValue(const FloatPoint& value)
+ {
+ CGPoint p;
+ p.x = value.x(); p.y = value.y();
+ return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreatePoint(p));
+ }
+ static RetainPtr<CFTypeRef> cfValue(const FloatRect& rect)
+ {
+ CGRect r;
+ r.origin.x = rect.x();
+ r.origin.y = rect.y();
+ r.size.width = rect.width();
+ r.size.height = rect.height();
+ CGFloat v[4] = { CGRectGetMinX(r), CGRectGetMinY(r), CGRectGetMaxX(r), CGRectGetMaxY(r) };
+ return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreate(4, v));
+ }
+ static RetainPtr<CFTypeRef> cfValue(const Color& color)
+ {
+ return RetainPtr<CFTypeRef>(AdoptCF, CGColorCreateGenericRGB(color.red(), color.green(), color.blue(), color.alpha()));
+ }
+
+ bool isTransformLayer() const;
+
+ void addSublayer(PassRefPtr<WKCACFLayer> sublayer);
+ void insertSublayerAboveLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference);
+ void insertSublayerBelowLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference);
+ void replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer>);
+ void adoptSublayers(WKCACFLayer* source);
+
+ void removeAllSublayers() { internalRemoveAllSublayers(); }
+ void setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers)
+ {
+ internalSetSublayers(sublayers);
+ checkLayerConsistency();
+ }
+
+ void insertSublayer(PassRefPtr<WKCACFLayer> layer, size_t index) { internalInsertSublayer(layer, index); }
+
+ size_t sublayerCount() const { return internalSublayerCount(); }
+
+ void removeFromSuperlayer();
+
+ WKCACFLayer* ancestorOrSelfWithSuperlayer(WKCACFLayer*) const;
+
+ void setAnchorPoint(const CGPoint& p) { CACFLayerSetAnchorPoint(layer(), p); setNeedsCommit(); }
+ CGPoint anchorPoint() const { return CACFLayerGetAnchorPoint(layer()); }
+
+ void setAnchorPointZ(CGFloat z) { CACFLayerSetAnchorPointZ(layer(), z); setNeedsCommit(); }
+ CGFloat anchorPointZ() const { return CACFLayerGetAnchorPointZ(layer()); }
+
+ void setBackgroundColor(CGColorRef color) { CACFLayerSetBackgroundColor(layer(), color); setNeedsCommit(); }
+ CGColorRef backgroundColor() const { return CACFLayerGetBackgroundColor(layer()); }
+
+ void setBorderColor(CGColorRef color) { CACFLayerSetBorderColor(layer(), color); setNeedsCommit(); }
+ CGColorRef borderColor() const { return CACFLayerGetBorderColor(layer()); }
+
+ void setBorderWidth(CGFloat width) { CACFLayerSetBorderWidth(layer(), width); setNeedsCommit(); }
+ CGFloat borderWidth() const { return CACFLayerGetBorderWidth(layer()); }
+
+ virtual void setBounds(const CGRect&);
+ CGRect bounds() const { return CACFLayerGetBounds(layer()); }
+
+ void setContents(CFTypeRef contents) { CACFLayerSetContents(layer(), contents); setNeedsCommit(); }
+ CFTypeRef contents() const { return CACFLayerGetContents(layer()); }
+
+ void setContentsRect(const CGRect& contentsRect) { CACFLayerSetContentsRect(layer(), contentsRect); setNeedsCommit(); }
+ CGRect contentsRect() const { return CACFLayerGetContentsRect(layer()); }
+
+ void setContentsGravity(ContentsGravityType);
+ ContentsGravityType contentsGravity() const;
+
+ void setDoubleSided(bool b) { CACFLayerSetDoubleSided(layer(), b); setNeedsCommit(); }
+ bool doubleSided() const { return CACFLayerIsDoubleSided(layer()); }
+
+ void setEdgeAntialiasingMask(uint32_t mask) { CACFLayerSetEdgeAntialiasingMask(layer(), mask); setNeedsCommit(); }
+ uint32_t edgeAntialiasingMask() const { return CACFLayerGetEdgeAntialiasingMask(layer()); }
+
+ virtual void setFrame(const CGRect&);
+ CGRect frame() const { return CACFLayerGetFrame(layer()); }
+
+ void setHidden(bool hidden) { CACFLayerSetHidden(layer(), hidden); setNeedsCommit(); }
+ bool isHidden() const { return CACFLayerIsHidden(layer()); }
+
+ void setMasksToBounds(bool b) { CACFLayerSetMasksToBounds(layer(), b); }
+ bool masksToBounds() const { return CACFLayerGetMasksToBounds(layer()); }
+
+ void setMagnificationFilter(FilterType);
+ FilterType magnificationFilter() const;
+
+ void setMinificationFilter(FilterType);
+ FilterType minificationFilter() const;
+
+ void setMinificationFilterBias(float bias) { CACFLayerSetMinificationFilterBias(layer(), bias); }
+ float minificationFilterBias() const { return CACFLayerGetMinificationFilterBias(layer()); }
+
+ void setName(const String& name) { CACFLayerSetName(layer(), RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get()); }
+ String name() const { return CACFLayerGetName(layer()); }
+
+ void setNeedsDisplayOnBoundsChange(bool needsDisplay) { m_needsDisplayOnBoundsChange = needsDisplay; }
+
+ void setOpacity(float opacity) { CACFLayerSetOpacity(layer(), opacity); setNeedsCommit(); }
+ float opacity() const { return CACFLayerGetOpacity(layer()); }
+
+ void setOpaque(bool b) { CACFLayerSetOpaque(layer(), b); setNeedsCommit(); }
+ bool opaque() const { return CACFLayerIsOpaque(layer()); }
+
+ void setPosition(const CGPoint& position) { CACFLayerSetPosition(layer(), position); setNeedsCommit(); }
+ CGPoint position() const { return CACFLayerGetPosition(layer()); }
+
+ void setZPosition(CGFloat position) { CACFLayerSetZPosition(layer(), position); setNeedsCommit(); }
+ CGFloat zPosition() const { return CACFLayerGetZPosition(layer()); }
+
+ void setSpeed(float speed) { CACFLayerSetSpeed(layer(), speed); }
+ CFTimeInterval speed() const { return CACFLayerGetSpeed(layer()); }
+
+ void setTimeOffset(CFTimeInterval t) { CACFLayerSetTimeOffset(layer(), t); }
+ CFTimeInterval timeOffset() const { return CACFLayerGetTimeOffset(layer()); }
+
+ WKCACFLayer* rootLayer() const;
+
+ void setSublayerTransform(const CATransform3D& transform) { CACFLayerSetSublayerTransform(layer(), transform); setNeedsCommit(); }
+ CATransform3D sublayerTransform() const { return CACFLayerGetSublayerTransform(layer()); }
+
+ WKCACFLayer* superlayer() const;
+
+ void setTransform(const CATransform3D& transform) { CACFLayerSetTransform(layer(), transform); setNeedsCommit(); }
+ CATransform3D transform() const { return CACFLayerGetTransform(layer()); }
+
+ void setGeometryFlipped(bool flipped) { CACFLayerSetGeometryFlipped(layer(), flipped); setNeedsCommit(); }
+ bool geometryFlipped() const { return CACFLayerIsGeometryFlipped(layer()); }
+
+#ifndef NDEBUG
+ // Print the tree from the root. Also does consistency checks
+ void printTree() const;
+#endif
+
+protected:
+ WKCACFLayer(LayerType);
+
+ void setNeedsCommit();
+
+ CACFLayerRef layer() const { return m_layer.get(); }
+ // This should only be called from removeFromSuperlayer.
+ void removeSublayer(const WKCACFLayer*);
+
+ void checkLayerConsistency()
+ {
+#ifndef NDEBUG
+ internalCheckLayerConsistency();
+#endif
+ }
+
+ // Methods to be overridden for sublayer and rendering management
+ virtual WKCACFLayer* internalSublayerAtIndex(int) const;
+
+ // Returns the index of the passed layer in this layer's sublayers list
+ // or -1 if not found
+ virtual int internalIndexOfSublayer(const WKCACFLayer*);
+
+ virtual size_t internalSublayerCount() const;
+ virtual void internalInsertSublayer(PassRefPtr<WKCACFLayer>, size_t index);
+ virtual void internalRemoveAllSublayers();
+ virtual void internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >&);
+
+ virtual void internalSetNeedsDisplay(const CGRect* dirtyRect);
+
+#ifndef NDEBUG
+ virtual void internalCheckLayerConsistency();
+#endif
+
+#ifndef NDEBUG
+ // Print this layer and its children to the console
+ void printLayer(int indent) const;
+#endif
+
+private:
+ static void layoutSublayersProc(CACFLayerRef);
+
+ RetainPtr<CACFLayerRef> m_layer;
+ WKCACFLayerLayoutClient* m_layoutClient;
+ bool m_needsDisplayOnBoundsChange;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WKCACFLayer_h
diff --git a/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
new file mode 100644
index 0000000..4c5e61d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2009 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 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 USE(ACCELERATED_COMPOSITING)
+
+#ifndef NDEBUG
+#define D3D_DEBUG_INFO
+#endif
+
+#include "WKCACFLayerRenderer.h"
+
+#include "PlatformCALayer.h"
+#include "WKCACFContextFlusher.h"
+#include "WebCoreInstanceHandle.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <limits.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/HashMap.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/StdLibExtras.h>
+#include <d3d9.h>
+#include <d3dx9.h>
+
+using namespace std;
+
+#pragma comment(lib, "d3d9")
+#pragma comment(lib, "d3dx9")
+#ifdef DEBUG_ALL
+#pragma comment(lib, "QuartzCore_debug")
+#else
+#pragma comment(lib, "QuartzCore")
+#endif
+
+static IDirect3D9* s_d3d = 0;
+static IDirect3D9* d3d()
+{
+ if (s_d3d)
+ return s_d3d;
+
+ if (!LoadLibrary(TEXT("d3d9.dll")))
+ return 0;
+
+ s_d3d = Direct3DCreate9(D3D_SDK_VERSION);
+
+ return s_d3d;
+}
+
+inline static CGRect winRectToCGRect(RECT rc)
+{
+ return CGRectMake(rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top));
+}
+
+inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect)
+{
+ return CGRectMake(rc.left, (relativeToRect.bottom-rc.bottom), (rc.right - rc.left), (rc.bottom - rc.top));
+}
+
+namespace WebCore {
+
+static D3DPRESENT_PARAMETERS initialPresentationParameters()
+{
+ D3DPRESENT_PARAMETERS parameters = {0};
+ parameters.Windowed = TRUE;
+ parameters.SwapEffect = D3DSWAPEFFECT_COPY;
+ parameters.BackBufferCount = 1;
+ parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
+ parameters.MultiSampleType = D3DMULTISAMPLE_NONE;
+
+ return parameters;
+}
+
+// FIXME: <rdar://6507851> Share this code with CoreAnimation.
+static bool hardwareCapabilitiesIndicateCoreAnimationSupport(const D3DCAPS9& caps)
+{
+ // CoreAnimation needs two or more texture units.
+ if (caps.MaxTextureBlendStages < 2)
+ return false;
+
+ // CoreAnimation needs non-power-of-two textures.
+ if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && !(caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL))
+ return false;
+
+ // CoreAnimation needs vertex shader 2.0 or greater.
+ if (D3DSHADER_VERSION_MAJOR(caps.VertexShaderVersion) < 2)
+ return false;
+
+ // CoreAnimation needs pixel shader 2.0 or greater.
+ if (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion) < 2)
+ return false;
+
+ return true;
+}
+
+bool WKCACFLayerRenderer::acceleratedCompositingAvailable()
+{
+ static bool available;
+ static bool tested;
+
+ if (tested)
+ return available;
+
+ tested = true;
+
+ // Initialize available to true since this function will be called from a
+ // propagation within createRenderer(). We want to be able to return true
+ // when that happens so that the test can continue.
+ available = true;
+
+ HMODULE library = LoadLibrary(TEXT("d3d9.dll"));
+ if (!library) {
+ available = false;
+ return available;
+ }
+
+ FreeLibrary(library);
+#ifdef DEBUG_ALL
+ library = LoadLibrary(TEXT("QuartzCore_debug.dll"));
+#else
+ library = LoadLibrary(TEXT("QuartzCore.dll"));
+#endif
+ if (!library) {
+ available = false;
+ return available;
+ }
+
+ FreeLibrary(library);
+
+ // Make a dummy HWND.
+ WNDCLASSEX wcex = { 0 };
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = DefWindowProc;
+ wcex.hInstance = WebCore::instanceHandle();
+ wcex.lpszClassName = L"CoreAnimationTesterWindowClass";
+ ::RegisterClassEx(&wcex);
+ HWND testWindow = ::CreateWindow(L"CoreAnimationTesterWindowClass", L"CoreAnimationTesterWindow", WS_POPUP, -500, -500, 0, 0, 0, 0, 0, 0);
+
+ if (!testWindow) {
+ available = false;
+ return available;
+ }
+
+ OwnPtr<WKCACFLayerRenderer> testLayerRenderer = WKCACFLayerRenderer::create(0);
+ testLayerRenderer->setHostWindow(testWindow);
+ available = testLayerRenderer->createRenderer();
+ ::DestroyWindow(testWindow);
+
+ return available;
+}
+
+PassOwnPtr<WKCACFLayerRenderer> WKCACFLayerRenderer::create(WKCACFLayerRendererClient* client)
+{
+ if (!acceleratedCompositingAvailable())
+ return 0;
+ return new WKCACFLayerRenderer(client);
+}
+
+WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client)
+ : m_client(client)
+ , m_mightBeAbleToCreateDeviceLater(true)
+ , m_rootLayer(PlatformCALayer::create(PlatformCALayer::LayerTypeRootLayer, 0))
+ , m_context(wkCACFContextCreate())
+ , m_hostWindow(0)
+ , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired)
+ , m_backingStoreDirty(false)
+ , m_mustResetLostDeviceBeforeRendering(false)
+ , m_syncLayerChanges(false)
+{
+ // Point the CACFContext to this
+ wkCACFContextSetUserData(m_context, this);
+
+ // Under the root layer, we have a clipping layer to clip the content,
+ // that contains a scroll layer that we use for scrolling the content.
+ // The root layer is the size of the client area of the window.
+ // The clipping layer is the size of the WebView client area (window less the scrollbars).
+ // The scroll layer is the size of the root child layer.
+ // Resizing the window will change the bounds of the rootLayer and the clip layer and will not
+ // cause any repositioning.
+ // Scrolling will affect only the position of the scroll layer without affecting the bounds.
+
+ m_rootLayer->setName("WKCACFLayerRenderer rootLayer");
+ m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0));
+ m_rootLayer->setGeometryFlipped(true);
+
+#ifndef NDEBUG
+ CGColorRef debugColor = CGColorCreateGenericRGB(1, 0, 0, 0.8);
+ m_rootLayer->setBackgroundColor(debugColor);
+ CGColorRelease(debugColor);
+#endif
+
+ if (m_context)
+ wkCACFContextSetLayer(m_context, m_rootLayer->platformLayer());
+
+#ifndef NDEBUG
+ char* printTreeFlag = getenv("CA_PRINT_TREE");
+ m_printTree = printTreeFlag && atoi(printTreeFlag);
+#endif
+}
+
+WKCACFLayerRenderer::~WKCACFLayerRenderer()
+{
+ destroyRenderer();
+ wkCACFContextDestroy(m_context);
+}
+
+PlatformCALayer* WKCACFLayerRenderer::rootLayer() const
+{
+ return m_rootLayer.get();
+}
+
+void WKCACFLayerRenderer::addPendingAnimatedLayer(PassRefPtr<PlatformCALayer> layer)
+{
+ m_pendingAnimatedLayers.add(layer);
+}
+
+void WKCACFLayerRenderer::setRootContents(CGImageRef image)
+{
+ ASSERT(m_rootLayer);
+ m_rootLayer->setContents(image);
+ renderSoon();
+}
+
+void WKCACFLayerRenderer::setRootContentsAndDisplay(CGImageRef image)
+{
+ ASSERT(m_rootLayer);
+ m_rootLayer->setContents(image);
+ paint();
+}
+
+void WKCACFLayerRenderer::setRootChildLayer(PlatformCALayer* layer)
+{
+ m_rootLayer->removeAllSublayers();
+ m_rootChildLayer = layer;
+ if (m_rootChildLayer)
+ m_rootLayer->appendSublayer(m_rootChildLayer.get());
+}
+
+void WKCACFLayerRenderer::layerTreeDidChange()
+{
+ WKCACFContextFlusher::shared().addContext(m_context);
+ renderSoon();
+}
+
+void WKCACFLayerRenderer::setNeedsDisplay(bool sync)
+{
+ if (!m_syncLayerChanges && sync)
+ m_syncLayerChanges = true;
+
+ ASSERT(m_rootLayer);
+ m_rootLayer->setNeedsDisplay(0);
+ renderSoon();
+}
+
+bool WKCACFLayerRenderer::createRenderer()
+{
+ if (m_d3dDevice || !m_mightBeAbleToCreateDeviceLater)
+ return m_d3dDevice;
+
+ m_mightBeAbleToCreateDeviceLater = false;
+ D3DPRESENT_PARAMETERS parameters = initialPresentationParameters();
+
+ if (!d3d() || !::IsWindow(m_hostWindow))
+ return false;
+
+ // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the
+ // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero
+ // size eventually, and then the backbuffer size will get reset.
+ RECT rect;
+ GetClientRect(m_hostWindow, &rect);
+
+ if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) {
+ parameters.BackBufferWidth = 1;
+ parameters.BackBufferHeight = 1;
+ }
+
+ D3DCAPS9 d3dCaps;
+ if (FAILED(d3d()->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps)))
+ return false;
+
+ DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE;
+ if ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) && d3dCaps.VertexProcessingCaps)
+ behaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ else
+ behaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+
+ COMPtr<IDirect3DDevice9> device;
+ if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, behaviorFlags, &parameters, &device))) {
+ // In certain situations (e.g., shortly after waking from sleep), Direct3DCreate9() will
+ // return an IDirect3D9 for which IDirect3D9::CreateDevice will always fail. In case we
+ // have one of these bad IDirect3D9s, get rid of it so we'll fetch a new one the next time
+ // we want to call CreateDevice.
+ s_d3d->Release();
+ s_d3d = 0;
+
+ // Even if we don't have a bad IDirect3D9, in certain situations (e.g., shortly after
+ // waking from sleep), CreateDevice will fail, but will later succeed if called again.
+ m_mightBeAbleToCreateDeviceLater = true;
+
+ return false;
+ }
+
+ // Now that we've created the IDirect3DDevice9 based on the capabilities we
+ // got from the IDirect3D9 global object, we requery the device for its
+ // actual capabilities. The capabilities returned by the device can
+ // sometimes be more complete, for example when using software vertex
+ // processing.
+ D3DCAPS9 deviceCaps;
+ if (FAILED(device->GetDeviceCaps(&deviceCaps)))
+ return false;
+
+ if (!hardwareCapabilitiesIndicateCoreAnimationSupport(deviceCaps))
+ return false;
+
+ m_d3dDevice = device;
+
+ initD3DGeometry();
+
+ wkCACFContextInitializeD3DDevice(m_context, m_d3dDevice.get());
+
+ if (IsWindow(m_hostWindow))
+ m_rootLayer->setBounds(bounds());
+
+ return true;
+}
+
+void WKCACFLayerRenderer::destroyRenderer()
+{
+ wkCACFContextSetLayer(m_context, m_rootLayer->platformLayer());
+
+ m_d3dDevice = 0;
+ if (s_d3d)
+ s_d3d->Release();
+
+ s_d3d = 0;
+ m_rootLayer = 0;
+ m_rootChildLayer = 0;
+
+ m_mightBeAbleToCreateDeviceLater = true;
+}
+
+void WKCACFLayerRenderer::resize()
+{
+ if (!m_d3dDevice)
+ return;
+
+ // Resetting the device might fail here. But that's OK, because if it does it we will attempt to
+ // reset the device the next time we try to render.
+ resetDevice(ChangedWindowSize);
+
+ if (m_rootLayer) {
+ m_rootLayer->setBounds(bounds());
+ WKCACFContextFlusher::shared().flushAllContexts();
+ }
+}
+
+static void getDirtyRects(HWND window, Vector<CGRect>& outRects)
+{
+ ASSERT_ARG(outRects, outRects.isEmpty());
+
+ RECT clientRect;
+ if (!GetClientRect(window, &clientRect))
+ return;
+
+ OwnPtr<HRGN> region(CreateRectRgn(0, 0, 0, 0));
+ int regionType = GetUpdateRgn(window, region.get(), false);
+ if (regionType != COMPLEXREGION) {
+ RECT dirtyRect;
+ if (GetUpdateRect(window, &dirtyRect, false))
+ outRects.append(winRectToCGRect(dirtyRect, clientRect));
+ return;
+ }
+
+ DWORD dataSize = GetRegionData(region.get(), 0, 0);
+ OwnArrayPtr<unsigned char> regionDataBuffer(new unsigned char[dataSize]);
+ RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get());
+ if (!GetRegionData(region.get(), dataSize, regionData))
+ return;
+
+ outRects.resize(regionData->rdh.nCount);
+
+ RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer);
+ for (size_t i = 0; i < outRects.size(); ++i, ++rect)
+ outRects[i] = winRectToCGRect(*rect, clientRect);
+}
+
+void WKCACFLayerRenderer::renderTimerFired(Timer<WKCACFLayerRenderer>*)
+{
+ paint();
+}
+
+void WKCACFLayerRenderer::paint()
+{
+ createRenderer();
+ if (!m_d3dDevice) {
+ if (m_mightBeAbleToCreateDeviceLater)
+ renderSoon();
+ return;
+ }
+
+ if (m_backingStoreDirty) {
+ // If the backing store is still dirty when we are about to draw the
+ // composited content, we need to force the window to paint into the
+ // backing store. The paint will only paint the dirty region that
+ // if being tracked in WebView.
+ UpdateWindow(m_hostWindow);
+ return;
+ }
+
+ Vector<CGRect> dirtyRects;
+ getDirtyRects(m_hostWindow, dirtyRects);
+ render(dirtyRects);
+}
+
+void WKCACFLayerRenderer::render(const Vector<CGRect>& windowDirtyRects)
+{
+ ASSERT(m_d3dDevice);
+
+ if (m_mustResetLostDeviceBeforeRendering && !resetDevice(LostDevice)) {
+ // We can't reset the device right now. Try again soon.
+ renderSoon();
+ return;
+ }
+
+ if (m_client && !m_client->shouldRender()) {
+ renderSoon();
+ return;
+ }
+
+ // Sync the layer if needed
+ if (m_syncLayerChanges) {
+ m_client->syncCompositingState();
+ m_syncLayerChanges = false;
+ }
+
+ // Flush the root layer to the render tree.
+ wkCACFContextFlush(m_context);
+
+ // All pending animations will have been started with the flush. Fire the animationStarted calls
+ double currentTime = WTF::currentTime();
+ double currentMediaTime = CACurrentMediaTime();
+ double t = currentTime + wkCACFContextGetLastCommitTime(m_context) - currentMediaTime;
+ ASSERT(t <= currentTime);
+
+ HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end();
+ for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it) {
+ PlatformCALayerClient* owner = (*it)->owner();
+ owner->platformCALayerAnimationStarted(t);
+ }
+
+ m_pendingAnimatedLayers.clear();
+
+ CGRect bounds = this->bounds();
+
+ // Give the renderer some space to use. This needs to be valid until the
+ // wkCACFContextFinishUpdate() call below.
+ char space[4096];
+ if (!wkCACFContextBeginUpdate(m_context, space, sizeof(space), currentMediaTime, bounds, windowDirtyRects.data(), windowDirtyRects.size()))
+ return;
+
+ HRESULT err = S_OK;
+ CFTimeInterval timeToNextRender = numeric_limits<CFTimeInterval>::infinity();
+
+ do {
+ // FIXME: don't need to clear dirty region if layer tree is opaque.
+
+ WKCACFUpdateRectEnumerator* e = wkCACFContextCopyUpdateRectEnumerator(m_context);
+ if (!e)
+ break;
+
+ Vector<D3DRECT, 64> rects;
+ for (const CGRect* r = wkCACFUpdateRectEnumeratorNextRect(e); r; r = wkCACFUpdateRectEnumeratorNextRect(e)) {
+ D3DRECT rect;
+ rect.x1 = r->origin.x;
+ rect.x2 = rect.x1 + r->size.width;
+ rect.y1 = bounds.origin.y + bounds.size.height - (r->origin.y + r->size.height);
+ rect.y2 = rect.y1 + r->size.height;
+
+ rects.append(rect);
+ }
+ wkCACFUpdateRectEnumeratorRelease(e);
+
+ timeToNextRender = wkCACFContextGetNextUpdateTime(m_context);
+
+ if (rects.isEmpty())
+ break;
+
+ m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0);
+
+ m_d3dDevice->BeginScene();
+ wkCACFContextRenderUpdate(m_context);
+ m_d3dDevice->EndScene();
+
+ err = m_d3dDevice->Present(0, 0, 0, 0);
+
+ if (err == D3DERR_DEVICELOST) {
+ wkCACFContextAddUpdateRect(m_context, bounds);
+ if (!resetDevice(LostDevice)) {
+ // We can't reset the device right now. Try again soon.
+ renderSoon();
+ return;
+ }
+ }
+ } while (err == D3DERR_DEVICELOST);
+
+ wkCACFContextFinishUpdate(m_context);
+
+#ifndef NDEBUG
+ if (m_printTree)
+ m_rootLayer->printTree();
+#endif
+
+ // If timeToNextRender is not infinity, it means animations are running, so queue up to render again
+ if (timeToNextRender != numeric_limits<CFTimeInterval>::infinity())
+ renderSoon();
+}
+
+void WKCACFLayerRenderer::renderSoon()
+{
+ if (!m_renderTimer.isActive())
+ m_renderTimer.startOneShot(0);
+}
+
+CGRect WKCACFLayerRenderer::bounds() const
+{
+ RECT clientRect;
+ GetClientRect(m_hostWindow, &clientRect);
+
+ return winRectToCGRect(clientRect);
+}
+
+void WKCACFLayerRenderer::initD3DGeometry()
+{
+ ASSERT(m_d3dDevice);
+
+ CGRect bounds = this->bounds();
+
+ float x0 = bounds.origin.x;
+ float y0 = bounds.origin.y;
+ float x1 = x0 + bounds.size.width;
+ float y1 = y0 + bounds.size.height;
+
+ D3DXMATRIXA16 projection;
+ D3DXMatrixOrthoOffCenterRH(&projection, x0, x1, y0, y1, -1.0f, 1.0f);
+
+ m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection);
+}
+
+bool WKCACFLayerRenderer::resetDevice(ResetReason reason)
+{
+ ASSERT(m_d3dDevice);
+ ASSERT(m_context);
+
+ HRESULT hr = m_d3dDevice->TestCooperativeLevel();
+
+ if (hr == D3DERR_DEVICELOST || hr == D3DERR_DRIVERINTERNALERROR) {
+ // The device cannot be reset at this time. Try again soon.
+ m_mustResetLostDeviceBeforeRendering = true;
+ return false;
+ }
+
+ m_mustResetLostDeviceBeforeRendering = false;
+
+ if (reason == LostDevice && hr == D3D_OK) {
+ // The device wasn't lost after all.
+ return true;
+ }
+
+ // We can reset the device.
+
+ // We have to release the context's D3D resrouces whenever we reset the IDirect3DDevice9 in order to
+ // destroy any D3DPOOL_DEFAULT resources that Core Animation has allocated (e.g., textures used
+ // for mask layers). See <http://msdn.microsoft.com/en-us/library/bb174425(v=VS.85).aspx>.
+ wkCACFContextReleaseD3DResources(m_context);
+
+ D3DPRESENT_PARAMETERS parameters = initialPresentationParameters();
+ hr = m_d3dDevice->Reset(&parameters);
+
+ // TestCooperativeLevel told us the device may be reset now, so we should
+ // not be told here that the device is lost.
+ ASSERT(hr != D3DERR_DEVICELOST);
+
+ initD3DGeometry();
+
+ return true;
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
new file mode 100644
index 0000000..aff1f83
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2009 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 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 WKCACFLayerRenderer_h
+#define WKCACFLayerRenderer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "COMPtr.h"
+#include "Timer.h"
+
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+#include <CoreGraphics/CGGeometry.h>
+
+interface IDirect3DDevice9;
+struct WKCACFContext;
+
+typedef struct CGImage* CGImageRef;
+
+namespace WebCore {
+
+class PlatformCALayer;
+
+class WKCACFLayerRendererClient {
+public:
+ virtual ~WKCACFLayerRendererClient() { }
+ virtual bool shouldRender() const = 0;
+ virtual void animationsStarted(CFTimeInterval) { }
+ virtual void syncCompositingState() { }
+};
+
+// FIXME: Currently there is a WKCACFLayerRenderer for each WebView and each
+// has its own CARenderOGLContext and Direct3DDevice9, which is inefficient.
+// (https://bugs.webkit.org/show_bug.cgi?id=31855)
+class WKCACFLayerRenderer : public Noncopyable {
+ friend PlatformCALayer;
+
+public:
+ static PassOwnPtr<WKCACFLayerRenderer> create(WKCACFLayerRendererClient*);
+ ~WKCACFLayerRenderer();
+
+ static bool acceleratedCompositingAvailable();
+
+ void setRootContents(CGImageRef);
+ void setRootContentsAndDisplay(CGImageRef);
+ void setRootChildLayer(PlatformCALayer*);
+ void layerTreeDidChange();
+ void setNeedsDisplay(bool sync = false);
+ void setHostWindow(HWND window) { m_hostWindow = window; }
+ void setBackingStoreDirty(bool dirty) { m_backingStoreDirty = dirty; }
+ bool createRenderer();
+ void destroyRenderer();
+ void resize();
+ void renderSoon();
+
+protected:
+ PlatformCALayer* rootLayer() const;
+ void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>);
+
+private:
+ WKCACFLayerRenderer(WKCACFLayerRendererClient*);
+
+ void renderTimerFired(Timer<WKCACFLayerRenderer>*);
+
+ CGRect bounds() const;
+
+ void initD3DGeometry();
+
+ // Call this when the device window has changed size or when IDirect3DDevice9::Present returns
+ // D3DERR_DEVICELOST. Returns true if the device was recovered, false if rendering must be
+ // aborted and reattempted soon.
+ enum ResetReason { ChangedWindowSize, LostDevice };
+ bool resetDevice(ResetReason);
+
+ void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>());
+ void paint();
+
+ WKCACFLayerRendererClient* m_client;
+ bool m_mightBeAbleToCreateDeviceLater;
+ COMPtr<IDirect3DDevice9> m_d3dDevice;
+ RefPtr<PlatformCALayer> m_rootLayer;
+ RefPtr<PlatformCALayer> m_rootChildLayer;
+ WKCACFContext* m_context;
+ HWND m_hostWindow;
+ Timer<WKCACFLayerRenderer> m_renderTimer;
+ bool m_backingStoreDirty;
+ bool m_mustResetLostDeviceBeforeRendering;
+ bool m_syncLayerChanges;
+ HashSet<RefPtr<PlatformCALayer> > m_pendingAnimatedLayers;
+
+#ifndef NDEBUG
+ bool m_printTree;
+#endif
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WKCACFLayerRenderer_h
diff --git a/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp b/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp
new file mode 100644
index 0000000..c2a178b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 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 INC. 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 INC. 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"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WKCAImageQueue.h"
+
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+class WKCAImageQueuePrivate {
+public:
+ RetainPtr<CAImageQueueRef> m_imageQueue;
+};
+
+static CAImageQueueRef WKCAImageQueueRetain(CAImageQueueRef iq)
+{
+ if (iq)
+ return (CAImageQueueRef)CFRetain(iq);
+ return 0;
+}
+
+static void WKCAImageQueueRelease(CAImageQueueRef iq)
+{
+ if (iq)
+ CFRelease(iq);
+}
+
+WKCAImageQueue::WKCAImageQueue(uint32_t width, uint32_t height, uint32_t capacity)
+ : m_private(new WKCAImageQueuePrivate())
+{
+ m_private->m_imageQueue.adoptCF(wkCAImageQueueCreate(width, height, capacity));
+}
+
+WKCAImageQueue::WKCAImageQueue(const WKCAImageQueue& o)
+ : m_private(new WKCAImageQueuePrivate())
+{
+ m_private->m_imageQueue = o.m_private->m_imageQueue;
+}
+
+WKCAImageQueue::~WKCAImageQueue(void)
+{
+}
+
+WKCAImageQueue& WKCAImageQueue::operator=(const WKCAImageQueue& o)
+{
+ m_private->m_imageQueue = o.m_private->m_imageQueue;
+ return *this;
+}
+
+size_t WKCAImageQueue::collect()
+{
+ return wkCAImageQueueCollect(m_private->m_imageQueue.get());
+}
+
+bool WKCAImageQueue::insertImage(double t, unsigned int type, uint64_t id, uint32_t flags, ReleaseCallback release, void* info)
+{
+ return wkCAImageQueueInsertImage(m_private->m_imageQueue.get(), t, type, id, flags, release, info);
+}
+
+uint64_t WKCAImageQueue::registerPixelBuffer(void *data, size_t data_size, size_t rowbytes, size_t width, size_t height, uint32_t pixel_format, CFDictionaryRef attachments, uint32_t flags)
+{
+ return wkCAImageQueueRegisterPixelBuffer(m_private->m_imageQueue.get(), data, data_size, rowbytes, width, height, pixel_format, attachments, flags);
+}
+
+void WKCAImageQueue::setFlags(uint32_t mask, uint32_t flags)
+{
+ wkCAImageQueueSetFlags(m_private->m_imageQueue.get(), mask, flags);
+}
+
+CFTypeRef WKCAImageQueue::get()
+{
+ return m_private->m_imageQueue.get();
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/WKCAImageQueue.h b/Source/WebCore/platform/graphics/win/WKCAImageQueue.h
new file mode 100644
index 0000000..3d25b48
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WKCAImageQueue.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 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 INC. 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 INC. 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 WKCAImageQueue_h
+#define WKCAImageQueue_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+typedef const void * CFTypeRef;
+typedef const struct __CFDictionary * CFDictionaryRef;
+
+#include <stdint.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class WKCAImageQueuePrivate;
+
+class WKCAImageQueue {
+public:
+ enum Flags {
+ Async = 1U << 0,
+ Fill = 1U << 1,
+ Protected = 1U << 2,
+ UseCleanAperture = 1U << 3,
+ UseAspectRatio = 1U << 4,
+ LowQualityColor = 1U << 5,
+ };
+
+ enum ImageType {
+ Nil = 1,
+ Surface,
+ Buffer,
+ IOSurface,
+ };
+
+ enum ImageFlags {
+ Opaque = 1U << 0,
+ Flush = 1U << 1,
+ WillFlush = 1U << 2,
+ Flipped = 1U << 3,
+ WaitGPU = 1U << 4,
+ };
+
+ typedef void (*ReleaseCallback)(unsigned int type, uint64_t id, void* info);
+
+ WKCAImageQueue(uint32_t width, uint32_t height, uint32_t capacity);
+ ~WKCAImageQueue(void);
+
+ size_t collect();
+
+ bool insertImage(double t, unsigned int type, uint64_t id, uint32_t flags, ReleaseCallback release, void* info);
+ uint64_t registerPixelBuffer(void *data, size_t data_size, size_t rowbytes, size_t width, size_t height, uint32_t pixel_format, CFDictionaryRef attachments, uint32_t flags);
+
+ uint32_t flags() const;
+ void setFlags(uint32_t mask, uint32_t flags);
+
+ CFTypeRef get();
+
+private:
+ WKCAImageQueue(const WKCAImageQueue&);
+ WKCAImageQueue& operator=(const WKCAImageQueue&);
+ OwnPtr<WKCAImageQueuePrivate> m_private;
+};
+
+}
+
+#endif
+
+#endif
diff --git a/Source/WebCore/platform/graphics/win/WebLayer.cpp b/Source/WebCore/platform/graphics/win/WebLayer.cpp
new file mode 100644
index 0000000..ecda294
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WebLayer.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2009 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 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 USE(ACCELERATED_COMPOSITING)
+
+#include "WebLayer.h"
+
+#include "Font.h"
+#include "GraphicsLayer.h"
+
+namespace WebCore {
+
+using namespace std;
+
+void WebLayer::internalSetNeedsDisplay(const CGRect* dirtyRect)
+{
+ if (m_owner) {
+ if (m_owner->showRepaintCounter()) {
+ CGRect layerBounds = bounds();
+ CGRect repaintCounterRect = layerBounds;
+ // We assume a maximum of 4 digits and a font size of 18.
+ repaintCounterRect.size.width = 80;
+ repaintCounterRect.size.height = 22;
+ if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown)
+ repaintCounterRect.origin.y = layerBounds.size.height - (layerBounds.origin.y + repaintCounterRect.size.height);
+ WKCACFLayer::internalSetNeedsDisplay(&repaintCounterRect);
+ }
+ if (dirtyRect && m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ CGRect flippedDirtyRect = *dirtyRect;
+ flippedDirtyRect.origin.y = bounds().size.height - (flippedDirtyRect.origin.y + flippedDirtyRect.size.height);
+ WKCACFLayer::internalSetNeedsDisplay(&flippedDirtyRect);
+ return;
+ }
+ }
+
+ WKCACFLayer::internalSetNeedsDisplay(dirtyRect);
+}
+
+void WebLayer::drawInContext(PlatformGraphicsContext* context)
+{
+ if (!m_owner)
+ return;
+
+ CGContextSaveGState(context);
+
+ CGRect layerBounds = bounds();
+ if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ CGContextScaleCTM(context, 1, -1);
+ CGContextTranslateCTM(context, 0, -layerBounds.size.height);
+ }
+
+ if (m_owner->client()) {
+ GraphicsContext graphicsContext(context);
+
+ // It's important to get the clip from the context, because it may be significantly
+ // smaller than the layer bounds (e.g. tiled layers)
+ CGRect clipBounds = CGContextGetClipBoundingBox(context);
+ IntRect clip(enclosingIntRect(clipBounds));
+ m_owner->paintGraphicsLayerContents(graphicsContext, clip);
+ }
+#ifndef NDEBUG
+ else {
+ ASSERT_NOT_REACHED();
+
+ // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
+ // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
+ CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
+ CGContextFillRect(context, layerBounds);
+ }
+#endif
+
+ if (m_owner->showRepaintCounter()) {
+ String text = String::number(m_owner->incrementRepaintCount());
+
+ CGContextSaveGState(context);
+
+ // Make the background of the counter the same as the border color,
+ // unless there is no border, then make it red
+ float borderWidth = CACFLayerGetBorderWidth(layer());
+ if (borderWidth > 0) {
+ CGColorRef borderColor = CACFLayerGetBorderColor(layer());
+ const CGFloat* colors = CGColorGetComponents(borderColor);
+ CGContextSetRGBFillColor(context, colors[0], colors[1], colors[2], colors[3]);
+ } else
+ CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
+
+ CGRect aBounds = layerBounds;
+
+ aBounds.size.width = 10 + 10 * text.length();
+ aBounds.size.height = 22;
+ CGContextFillRect(context, aBounds);
+
+ FontDescription desc;
+
+ NONCLIENTMETRICS metrics;
+ metrics.cbSize = sizeof(metrics);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
+ FontFamily family;
+ family.setFamily(metrics.lfSmCaptionFont.lfFaceName);
+ desc.setFamily(family);
+
+ desc.setComputedSize(18);
+
+ Font font = Font(desc, 0, 0);
+ font.update(0);
+
+ GraphicsContext cg(context);
+ cg.setFillColor(Color::black, ColorSpaceDeviceRGB);
+ cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 5, aBounds.origin.y + 17));
+
+ CGContextRestoreGState(context);
+ }
+
+ CGContextRestoreGState(context);
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WebLayer.h b/Source/WebCore/platform/graphics/win/WebLayer.h
new file mode 100644
index 0000000..8dab5cc
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WebLayer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 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 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 WebLayer_h
+#define WebLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WKCACFLayer.h"
+
+namespace WebCore {
+
+class GraphicsLayer;
+
+class WebLayer : public WKCACFLayer {
+public:
+ static PassRefPtr<WKCACFLayer> create(LayerType layerType, GraphicsLayer* owner)
+ {
+ return adoptRef(new WebLayer(layerType, owner));
+ }
+
+ virtual void drawInContext(PlatformGraphicsContext*);
+
+protected:
+ WebLayer(LayerType layerType, GraphicsLayer* owner)
+ : WKCACFLayer(layerType)
+ , m_owner(owner)
+ {
+ }
+
+ virtual void internalSetNeedsDisplay(const CGRect* dirtyRect);
+
+ GraphicsLayer* m_owner;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebLayer_h
diff --git a/Source/WebCore/platform/graphics/win/WebTiledLayer.cpp b/Source/WebCore/platform/graphics/win/WebTiledLayer.cpp
new file mode 100644
index 0000000..4705033
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WebTiledLayer.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2009 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 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 USE(ACCELERATED_COMPOSITING)
+
+#include "WebTiledLayer.h"
+
+#include "GraphicsLayer.h"
+#include "WKCACFLayerRenderer.h"
+
+namespace WebCore {
+
+using namespace std;
+
+#ifndef NDEBUG
+void WebTiledLayer::internalCheckLayerConsistency()
+{
+ WKCACFLayer::internalCheckLayerConsistency();
+
+ // Additionally make sure the tiled parent is valid
+ CFArrayRef sublayers = CACFLayerGetSublayers(layer());
+
+ // Make sure there is a tile parent and it is the same as we remember
+ size_t n = CFArrayGetCount(sublayers);
+ ASSERT(n > 0);
+ const void* element = CFArrayGetValueAtIndex(sublayers, 0);
+ ASSERT(m_tileParent.get() == element);
+
+ // Make sure the tile parent doesn't have user data. If it does, it is probably
+ // a WKCACFLayer in the wrong place.
+ ASSERT(!layer(m_tileParent.get()));
+}
+#endif
+
+void WebTiledLayer::tileDisplayCallback(CACFLayerRef layer, CGContextRef context)
+{
+ static_cast<WebTiledLayer*>(CACFLayerGetUserData(layer))->drawTile(layer, context);
+}
+
+PassRefPtr<WebTiledLayer> WebTiledLayer::create(const CGSize& tileSize, GraphicsLayer* owner)
+{
+ ASSERT(WKCACFLayerRenderer::acceleratedCompositingAvailable());
+ return adoptRef(new WebTiledLayer(tileSize, owner));
+}
+
+WebTiledLayer::WebTiledLayer(const CGSize& tileSize, GraphicsLayer* owner)
+ : WebLayer(WKCACFLayer::Layer, owner)
+ , m_tileSize(tileSize)
+ , m_constrainedSize(constrainedSize(bounds().size))
+{
+ // Tiled layers are placed in a child layer that is always the first child of the TiledLayer
+ m_tileParent.adoptCF(CACFLayerCreate(kCACFLayer));
+ CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0);
+
+ updateTiles();
+}
+
+WebTiledLayer::~WebTiledLayer()
+{
+}
+
+void WebTiledLayer::setBounds(const CGRect& rect)
+{
+ if (CGRectEqualToRect(rect, bounds()))
+ return;
+
+ WebLayer::setBounds(rect);
+ m_constrainedSize = constrainedSize(rect.size);
+ updateTiles();
+}
+
+void WebTiledLayer::setFrame(const CGRect& rect)
+{
+ if (CGRectEqualToRect(rect, frame()))
+ return;
+
+ WebLayer::setFrame(rect);
+ updateTiles();
+}
+
+void WebTiledLayer::internalSetNeedsDisplay(const CGRect* dirtyRect)
+{
+ // FIXME: Only setNeedsDisplay for tiles that are currently visible
+ int numTileLayers = tileCount();
+ for (int i = 0; i < numTileLayers; ++i)
+ CACFLayerSetNeedsDisplay(tileAtIndex(i), dirtyRect);
+
+ if (m_owner->showRepaintCounter()) {
+ CGRect layerBounds = bounds();
+ CGRect indicatorRect = CGRectMake(layerBounds.origin.x, layerBounds.origin.y, 80, 25);
+ CACFLayerSetNeedsDisplay(tileAtIndex(0), &indicatorRect);
+ }
+}
+
+size_t WebTiledLayer::internalSublayerCount() const
+{
+ ASSERT(WebLayer::internalSublayerCount() > 0);
+
+ // Subtract 1 to account for the tile parent layer
+ return WebLayer::internalSublayerCount() - 1;
+}
+
+void WebTiledLayer::internalRemoveAllSublayers()
+{
+ // Restore the tile parent after removal
+ WebLayer::internalRemoveAllSublayers();
+ CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0);
+}
+
+void WebTiledLayer::internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers)
+{
+ // Preserve the tile parent after set
+ WebLayer::internalSetSublayers(sublayers);
+ CACFLayerInsertSublayer(layer(), m_tileParent.get(), 0);
+}
+
+void WebTiledLayer::internalInsertSublayer(PassRefPtr<WKCACFLayer> layer, size_t index)
+{
+ // Add 1 to account for the tile parent layer
+ WebLayer::internalInsertSublayer(layer, index + 1);
+}
+
+WKCACFLayer* WebTiledLayer::internalSublayerAtIndex(int i) const
+{
+ // Add 1 to account for the tile parent layer
+ return WebLayer::internalSublayerAtIndex(i + 1);
+}
+
+int WebTiledLayer::internalIndexOfSublayer(const WKCACFLayer* layer)
+{
+ int i = WebLayer::internalIndexOfSublayer(layer);
+
+ // Add 1 to account for the tile parent layer (but be safe about it)
+ return (i > 0) ? i - 1 : -1;
+}
+
+CGSize WebTiledLayer::constrainedSize(const CGSize& size) const
+{
+ const int cMaxTileCount = 512;
+ const float cSqrtMaxTileCount = sqrtf(cMaxTileCount);
+
+ CGSize constrainedSize = size;
+
+ int tileColumns = ceilf(constrainedSize.width / m_tileSize.width);
+ int tileRows = ceilf(constrainedSize.height / m_tileSize.height);
+ int numTiles = tileColumns * tileRows;
+
+ // If number of tiles vertically or horizontally is < sqrt(cMaxTileCount)
+ // just shorten the longer dimension. Otherwise shorten both dimensions
+ // according to the ratio of width to height
+
+ if (numTiles > cMaxTileCount) {
+ if (tileRows < cSqrtMaxTileCount)
+ tileColumns = floorf(cMaxTileCount / tileRows);
+ else if (tileColumns < cSqrtMaxTileCount)
+ tileRows = floorf(cMaxTileCount / tileColumns);
+ else {
+ tileRows = ceilf(sqrtf(cMaxTileCount * constrainedSize.height / constrainedSize.width));
+ tileColumns = floorf(cMaxTileCount / tileRows);
+ }
+
+ constrainedSize.width = tileColumns * m_tileSize.width;
+ constrainedSize.height = tileRows * m_tileSize.height;
+ }
+
+ return constrainedSize;
+}
+
+void WebTiledLayer::addTile()
+{
+ RetainPtr<CACFLayerRef> newLayer(AdoptCF, CACFLayerCreate(kCACFLayer));
+ CACFLayerSetAnchorPoint(newLayer.get(), CGPointMake(0, 1));
+ CACFLayerSetUserData(newLayer.get(), this);
+ CACFLayerSetDisplayCallback(newLayer.get(), tileDisplayCallback);
+
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ CACFLayerInsertSublayer(m_tileParent.get(), newLayer.get(), sublayers ? CFArrayGetCount(sublayers) : 0);
+
+ if (m_owner->showDebugBorders()) {
+ CGColorRef borderColor = CGColorCreateGenericRGB(0.5, 0, 0.5, 0.7);
+ CACFLayerSetBorderColor(newLayer.get(), borderColor);
+ CGColorRelease(borderColor);
+ CACFLayerSetBorderWidth(newLayer.get(), 2);
+ }
+}
+
+void WebTiledLayer::removeTile()
+{
+ CACFLayerRemoveFromSuperlayer(tileAtIndex(tileCount() - 1));
+}
+
+CACFLayerRef WebTiledLayer::tileAtIndex(int index)
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ if (!sublayers || index < 0 || index >= tileCount() )
+ return 0;
+
+ return static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(sublayers, index)));
+}
+
+int WebTiledLayer::tileCount() const
+{
+ CFArrayRef sublayers = CACFLayerGetSublayers(m_tileParent.get());
+ return sublayers ? CFArrayGetCount(sublayers) : 0;
+}
+
+void WebTiledLayer::updateTiles()
+{
+ // FIXME: In addition to redoing the number of tiles, we need to only render and have backing
+ // store for visible layers
+ int numTilesHorizontal = ceil(m_constrainedSize.width / m_tileSize.width);
+ int numTilesVertical = ceil(m_constrainedSize.height / m_tileSize.height);
+ int numTilesTotal = numTilesHorizontal * numTilesVertical;
+
+ int numTilesToChange = numTilesTotal - tileCount();
+ if (numTilesToChange >= 0) {
+ // Add new tiles
+ for (int i = 0; i < numTilesToChange; ++i)
+ addTile();
+ } else {
+ // Remove old tiles
+ numTilesToChange = -numTilesToChange;
+ for (int i = 0; i < numTilesToChange; ++i)
+ removeTile();
+ }
+
+ // Set coordinates for all tiles
+ CFArrayRef tileArray = CACFLayerGetSublayers(m_tileParent.get());
+
+ for (int i = 0; i < numTilesHorizontal; ++i) {
+ for (int j = 0; j < numTilesVertical; ++j) {
+ CACFLayerRef tile = static_cast<CACFLayerRef>(const_cast<void*>(CFArrayGetValueAtIndex(tileArray, i * numTilesVertical + j)));
+ CACFLayerSetPosition(tile, CGPointMake(i * m_tileSize.width, j * m_tileSize.height));
+ int width = min(m_tileSize.width, m_constrainedSize.width - i * m_tileSize.width);
+ int height = min(m_tileSize.height, m_constrainedSize.height - j * m_tileSize.height);
+ CACFLayerSetBounds(tile, CGRectMake(i * m_tileSize.width, j * m_tileSize.height, width, height));
+
+ // Flip Y to compensate for the flipping that happens during render to match the CG context coordinate space
+ CATransform3D transform = CATransform3DMakeScale(1, -1, 1);
+ CATransform3DTranslate(transform, 0, height, 0);
+ CACFLayerSetTransform(tile, transform);
+
+#ifndef NDEBUG
+ String name = "Tile (" + String::number(i) + "," + String::number(j) + ")";
+ CACFLayerSetName(tile, RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get());
+#endif
+ }
+ }
+}
+
+void WebTiledLayer::drawTile(CACFLayerRef tile, CGContextRef context)
+{
+ CGPoint tilePosition = CACFLayerGetPosition(tile);
+ CGRect tileBounds = CACFLayerGetBounds(tile);
+
+ CGContextSaveGState(context);
+
+ // Transform context to be at the origin of the parent layer
+ CGContextTranslateCTM(context, -tilePosition.x, -tilePosition.y);
+
+ // Set the context clipping rectangle to the current tile
+ CGContextClipToRect(context, CGRectMake(tilePosition.x, tilePosition.y, tileBounds.size.width, tileBounds.size.height));
+
+ if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) {
+ // If the layer is rendering top-down, it will flip the coordinates in y. Tiled layers are
+ // already flipping, so we need to undo that here.
+ CGContextTranslateCTM(context, 0, bounds().size.height);
+ CGContextScaleCTM(context, 1, -1);
+ }
+
+ // Draw the tile
+ drawInContext(context);
+
+ CGContextRestoreGState(context);
+}
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/win/WebTiledLayer.h b/Source/WebCore/platform/graphics/win/WebTiledLayer.h
new file mode 100644
index 0000000..b8ae320
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/WebTiledLayer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 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 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 WebTiledLayer_h
+#define WebTiledLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "WebLayer.h"
+
+namespace WebCore {
+
+class WebTiledLayer : public WebLayer {
+public:
+ static PassRefPtr<WebTiledLayer> create(const CGSize& tileSize, GraphicsLayer* owner);
+
+ virtual ~WebTiledLayer();
+
+ virtual void setBounds(const CGRect&);
+ virtual void setFrame(const CGRect&);
+
+protected:
+ WebTiledLayer(const CGSize& tileSize, GraphicsLayer* owner);
+
+ // Overridden from WKCACFLayer
+ virtual WKCACFLayer* internalSublayerAtIndex(int) const;
+ virtual int internalIndexOfSublayer(const WKCACFLayer*);
+
+ virtual size_t internalSublayerCount() const;
+ virtual void internalInsertSublayer(PassRefPtr<WKCACFLayer>, size_t index);
+
+ virtual void internalRemoveAllSublayers();
+ virtual void internalSetSublayers(const Vector<RefPtr<WKCACFLayer> >&);
+
+ virtual void internalSetNeedsDisplay(const CGRect* dirtyRect);
+
+#ifndef NDEBUG
+ virtual void internalCheckLayerConsistency();
+#endif
+
+private:
+ static void tileDisplayCallback(CACFLayerRef, CGContextRef);
+ void drawTile(CACFLayerRef, CGContextRef);
+
+ CGSize constrainedSize(const CGSize& size) const;
+
+ void addTile();
+ void removeTile();
+ CACFLayerRef tileAtIndex(int);
+ int tileCount() const;
+
+ void updateTiles();
+
+ CGSize m_tileSize;
+ CGSize m_constrainedSize;
+ RetainPtr<CACFLayerRef> m_tileParent;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebTiledLayer_h
diff --git a/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h b/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h
new file mode 100644
index 0000000..d8f538a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2010 Brent Fulgham <bfulgham@webkit.org>
+ * 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 FontPlatformDataCairoWin_h
+#define FontPlatformDataCairoWin_h
+
+#include "FontOrientation.h"
+#include "GlyphBuffer.h"
+#include "RefCountedGDIHandle.h"
+#include "StringImpl.h"
+#include <cairo-win32.h>
+#include <cairo.h>
+#include <wtf/Forward.h>
+
+typedef struct HFONT__* HFONT;
+
+namespace WebCore {
+
+class FontDescription;
+
+class FontPlatformData {
+public:
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_fontFace(0)
+ , m_useGDI(false)
+ , m_font(WTF::HashTableDeletedValue)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData()
+ : m_fontFace(0)
+ , m_useGDI(false)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI);
+ FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic);
+ FontPlatformData(float size, bool bold, bool italic);
+ FontPlatformData(const FontPlatformData&);
+ ~FontPlatformData();
+
+ HFONT hfont() const { return m_font->handle(); }
+ bool useGDI() const { return m_useGDI; }
+ cairo_font_face_t* fontFace() const { return m_fontFace; }
+
+ bool isFixedPitch();
+ 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; }
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+ cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
+
+ unsigned hash() const
+ {
+ return m_font->hash();
+ }
+
+ bool operator==(const FontPlatformData&) const;
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool isHashTableDeletedValue() const
+ {
+ return m_font.isHashTableDeletedValue();
+ }
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+private:
+ void platformDataInit(HFONT, float size, HDC, WCHAR* faceName);
+
+ RefPtr<RefCountedGDIHandle<HFONT> > m_font;
+ cairo_font_face_t* m_fontFace;
+ bool m_useGDI;
+ float m_size;
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+ cairo_scaled_font_t* m_scaledFont;
+};
+
+}
+
+#endif // FontPlatformDataCairoWin_h