From cad810f21b803229eb11403f9209855525a25d57 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Fri, 6 May 2011 11:45:16 +0100 Subject: Merge WebKit at r75315: Initial merge by git. Change-Id: I570314b346ce101c935ed22a626b48c2af266b84 --- Source/WebCore/platform/graphics/win/FontCGWin.cpp | 392 ++++++ .../WebCore/platform/graphics/win/FontCacheWin.cpp | 603 ++++++++++ .../graphics/win/FontCustomPlatformData.cpp | 219 ++++ .../platform/graphics/win/FontCustomPlatformData.h | 58 + .../graphics/win/FontCustomPlatformDataCairo.cpp | 66 ++ .../graphics/win/FontCustomPlatformDataCairo.h | 54 + .../graphics/win/FontPlatformDataCGWin.cpp | 131 ++ .../graphics/win/FontPlatformDataCairoWin.cpp | 143 +++ .../platform/graphics/win/FontPlatformDataWin.cpp | 95 ++ Source/WebCore/platform/graphics/win/FontWin.cpp | 142 +++ Source/WebCore/platform/graphics/win/GDIExtras.cpp | 43 + Source/WebCore/platform/graphics/win/GDIExtras.h | 65 + .../graphics/win/GlyphPageTreeNodeCGWin.cpp | 59 + .../graphics/win/GlyphPageTreeNodeCairoWin.cpp | 72 ++ .../platform/graphics/win/GraphicsContextCGWin.cpp | 261 ++++ .../graphics/win/GraphicsContextCairoWin.cpp | 169 +++ .../platform/graphics/win/GraphicsContextWin.cpp | 200 ++++ .../platform/graphics/win/GraphicsLayerCACF.cpp | 757 ++++++++++++ .../platform/graphics/win/GraphicsLayerCACF.h | 139 +++ Source/WebCore/platform/graphics/win/IconWin.cpp | 99 ++ .../WebCore/platform/graphics/win/ImageCGWin.cpp | 108 ++ .../platform/graphics/win/ImageCairoWin.cpp | 114 ++ Source/WebCore/platform/graphics/win/ImageWin.cpp | 58 + .../WebCore/platform/graphics/win/IntPointWin.cpp | 57 + .../WebCore/platform/graphics/win/IntRectWin.cpp | 45 + .../WebCore/platform/graphics/win/IntSizeWin.cpp | 45 + .../platform/graphics/win/LocalWindowsContext.h | 61 + .../win/MediaPlayerPrivateFullscreenWindow.cpp | 183 +++ .../win/MediaPlayerPrivateFullscreenWindow.h | 82 ++ .../MediaPlayerPrivateQuickTimeVisualContext.cpp | 1252 ++++++++++++++++++++ .../win/MediaPlayerPrivateQuickTimeVisualContext.h | 211 ++++ .../win/MediaPlayerPrivateQuickTimeWin.cpp | 933 +++++++++++++++ .../graphics/win/MediaPlayerPrivateQuickTimeWin.h | 193 +++ .../graphics/win/MediaPlayerPrivateTaskTimer.cpp | 65 + .../graphics/win/MediaPlayerPrivateTaskTimer.h | 48 + .../platform/graphics/win/QTCFDictionary.cpp | 61 + .../WebCore/platform/graphics/win/QTCFDictionary.h | 44 + .../graphics/win/QTDecompressionSession.cpp | 170 +++ .../platform/graphics/win/QTDecompressionSession.h | 64 + Source/WebCore/platform/graphics/win/QTMovie.cpp | 942 +++++++++++++++ Source/WebCore/platform/graphics/win/QTMovie.h | 125 ++ .../platform/graphics/win/QTMovieGWorld.cpp | 465 ++++++++ .../WebCore/platform/graphics/win/QTMovieGWorld.h | 84 ++ .../WebCore/platform/graphics/win/QTMovieTask.cpp | 105 ++ Source/WebCore/platform/graphics/win/QTMovieTask.h | 69 ++ .../platform/graphics/win/QTMovieVisualContext.cpp | 223 ++++ .../platform/graphics/win/QTMovieVisualContext.h | 79 ++ .../platform/graphics/win/QTMovieWinTimer.cpp | 137 +++ .../platform/graphics/win/QTMovieWinTimer.h | 39 + .../platform/graphics/win/QTPixelBuffer.cpp | 256 ++++ .../WebCore/platform/graphics/win/QTPixelBuffer.h | 100 ++ Source/WebCore/platform/graphics/win/QTTrack.cpp | 119 ++ Source/WebCore/platform/graphics/win/QTTrack.h | 66 ++ .../platform/graphics/win/RefCountedGDIHandle.h | 70 ++ .../platform/graphics/win/SimpleFontDataCGWin.cpp | 161 +++ .../graphics/win/SimpleFontDataCairoWin.cpp | 130 ++ .../platform/graphics/win/SimpleFontDataWin.cpp | 259 ++++ .../graphics/win/TransformationMatrixWin.cpp | 46 + .../platform/graphics/win/UniscribeController.cpp | 465 ++++++++ .../platform/graphics/win/UniscribeController.h | 90 ++ .../platform/graphics/win/WKCACFContextFlusher.cpp | 79 ++ .../platform/graphics/win/WKCACFContextFlusher.h | 60 + .../WebCore/platform/graphics/win/WKCACFLayer.cpp | 572 +++++++++ Source/WebCore/platform/graphics/win/WKCACFLayer.h | 299 +++++ .../platform/graphics/win/WKCACFLayerRenderer.cpp | 614 ++++++++++ .../platform/graphics/win/WKCACFLayerRenderer.h | 129 ++ .../platform/graphics/win/WKCAImageQueue.cpp | 104 ++ .../WebCore/platform/graphics/win/WKCAImageQueue.h | 92 ++ Source/WebCore/platform/graphics/win/WebLayer.cpp | 143 +++ Source/WebCore/platform/graphics/win/WebLayer.h | 62 + .../platform/graphics/win/WebTiledLayer.cpp | 303 +++++ .../WebCore/platform/graphics/win/WebTiledLayer.h | 85 ++ .../platform/graphics/win/cairo/FontPlatformData.h | 114 ++ 73 files changed, 14247 insertions(+) create mode 100644 Source/WebCore/platform/graphics/win/FontCGWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/FontCacheWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/FontCustomPlatformData.cpp create mode 100644 Source/WebCore/platform/graphics/win/FontCustomPlatformData.h create mode 100644 Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp create mode 100644 Source/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h create mode 100644 Source/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/FontWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/GDIExtras.cpp create mode 100644 Source/WebCore/platform/graphics/win/GDIExtras.h create mode 100644 Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp create mode 100644 Source/WebCore/platform/graphics/win/GraphicsLayerCACF.h create mode 100644 Source/WebCore/platform/graphics/win/IconWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/ImageCGWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/ImageCairoWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/ImageWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/IntPointWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/IntRectWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/IntSizeWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/LocalWindowsContext.h create mode 100644 Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp create mode 100644 Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.h create mode 100644 Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp create mode 100644 Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h create mode 100644 Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h create mode 100644 Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp create mode 100644 Source/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h create mode 100644 Source/WebCore/platform/graphics/win/QTCFDictionary.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTCFDictionary.h create mode 100644 Source/WebCore/platform/graphics/win/QTDecompressionSession.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTDecompressionSession.h create mode 100644 Source/WebCore/platform/graphics/win/QTMovie.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTMovie.h create mode 100644 Source/WebCore/platform/graphics/win/QTMovieGWorld.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTMovieGWorld.h create mode 100644 Source/WebCore/platform/graphics/win/QTMovieTask.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTMovieTask.h create mode 100644 Source/WebCore/platform/graphics/win/QTMovieVisualContext.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTMovieVisualContext.h create mode 100644 Source/WebCore/platform/graphics/win/QTMovieWinTimer.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTMovieWinTimer.h create mode 100644 Source/WebCore/platform/graphics/win/QTPixelBuffer.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTPixelBuffer.h create mode 100644 Source/WebCore/platform/graphics/win/QTTrack.cpp create mode 100644 Source/WebCore/platform/graphics/win/QTTrack.h create mode 100644 Source/WebCore/platform/graphics/win/RefCountedGDIHandle.h create mode 100644 Source/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/TransformationMatrixWin.cpp create mode 100644 Source/WebCore/platform/graphics/win/UniscribeController.cpp create mode 100644 Source/WebCore/platform/graphics/win/UniscribeController.h create mode 100644 Source/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp create mode 100644 Source/WebCore/platform/graphics/win/WKCACFContextFlusher.h create mode 100644 Source/WebCore/platform/graphics/win/WKCACFLayer.cpp create mode 100644 Source/WebCore/platform/graphics/win/WKCACFLayer.h create mode 100644 Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp create mode 100644 Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h create mode 100644 Source/WebCore/platform/graphics/win/WKCAImageQueue.cpp create mode 100644 Source/WebCore/platform/graphics/win/WKCAImageQueue.h create mode 100644 Source/WebCore/platform/graphics/win/WebLayer.cpp create mode 100644 Source/WebCore/platform/graphics/win/WebLayer.h create mode 100644 Source/WebCore/platform/graphics/win/WebTiledLayer.cpp create mode 100644 Source/WebCore/platform/graphics/win/WebTiledLayer.h create mode 100644 Source/WebCore/platform/graphics/win/cairo/FontPlatformData.h (limited to 'Source/WebCore/platform/graphics/win') 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 +#include +#include + +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 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(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(reinterpret_cast(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 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 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(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(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 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 +#include "FontCache.h" +#include "Font.h" +#include "SimpleFontData.h" +#include "UnicodeRange.h" +#include +#include +#include +#include +#if PLATFORM(CG) +#include +#include +#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(record); + *reinterpret_cast(logFont) = createFontRecord->elfw.elfLogFont; + } + return true; +} + +static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM hfont) +{ + *reinterpret_cast(hfont) = CreateFontIndirect(logFont); + return false; +} + +static const Vector* getLinkedFonts(String& family) +{ + static HashMap*> systemLinkMap; + Vector* result = systemLinkMap.get(family); + if (result) + return result; + + result = new Vector; + 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(malloc(linkedFontsBufferSize)); + if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, reinterpret_cast(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& 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 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(&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 glyphsetBuffer; + glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); + GLYPHSET* glyphset = reinterpret_cast(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& 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* 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(&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(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(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(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(&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 m_traitsMasks; +}; + +static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) +{ + TraitsInFamilyProcData* procData = reinterpret_cast(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& traitsMasks) +{ + HDC hdc = GetDC(0); + + LOGFONT logFont; + logFont.lfCharSet = DEFAULT_CHARSET; + unsigned familyLength = min(familyName.length(), static_cast(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(&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 +#include +#include + +// 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(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(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 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(m_overlayDst - m_offset, 0); + size_t srcOffset = max(0, m_offset - m_overlayDst); + size_t bytesToCopy = min(bytesFromData - dstOffset, m_overlayLength - srcOffset); + memcpy(reinterpret_cast(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(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 fontUuid(sizeof(GUID)); + CoCreateGuid(reinterpret_cast(fontUuid.data())); + + Vector 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 sfntBuffer; + if (isWOFF(buffer)) { + Vector 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(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 +#include + +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 + +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(data)->deref(); +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + + buffer->ref(); + HFONT font = reinterpret_cast(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 + * + * 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 +#include + +#include + +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 +#include +#include +#include +#include +#include + +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 > nameMap; + + // Check our hash first. + String faceString(faceName); + RetainPtr 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 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::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 +#include +#include +#include + +#include + +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 +#include +#include +#include + +using std::min; + +namespace WebCore { + +FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI) + : m_font(RefCountedGDIHandle::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 + +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* fallbackFonts, GlyphOverflow* glyphOverflow) const +{ + UniscribeController controller(this, run, fallbackFonts); + controller.advance(run.length()); + if (glyphOverflow) { + glyphOverflow->top = max(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent()); + glyphOverflow->bottom = max(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent()); + glyphOverflow->left = max(0, ceilf(-controller.minGlyphBoundingBoxX())); + glyphOverflow->right = max(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(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 + * + * 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 + * + * 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 + +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 + +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(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 +#include +#include "GraphicsContextPlatformPrivateCG.h" + +using namespace std; + +namespace WebCore { + +static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha) +{ + HBITMAP bitmap = static_cast(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(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 + RetainPtr imageData(AdoptCF, CFDataCreate(kCFAllocatorDefault, image->buffer(), image->bufferLength())); + RetainPtr dataProvider(AdoptCF, CGDataProviderCreateWithCFData(imageData.get())); + RetainPtr 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& 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 +#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(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(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(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 + +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(&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 +#include +#include + +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::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& 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 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 > 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& childLayers = children(); + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCACF* curChild = static_cast(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 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 + +namespace WebCore { + +class WKCACFLayer; + +class GraphicsLayerCACF : public GraphicsLayer { +public: + + GraphicsLayerCACF(GraphicsLayerClient*); + virtual ~GraphicsLayerCACF(); + + virtual void setName(const String& inName); + + virtual bool setChildren(const Vector&); + 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 m_layer; + RefPtr m_transformLayer; + RefPtr m_contentsLayer; + + enum ContentsLayerPurpose { + NoContentsLayer = 0, + ContentsLayerForImage, + ContentsLayerForMedia + }; + + ContentsLayerPurpose m_contentsLayerPurpose; + bool m_contentsLayerHasBackgroundColor : 1; + RetainPtr 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 +#include + +#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::createIconForFiles(const Vector& 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 +#include +#include + +namespace WebCore { + +PassRefPtr 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 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(srcSize.height()) && CGImageGetWidth(image) == static_cast(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 +#include + +#include +#include "PlatformString.h" + +namespace WebCore { + +PassRefPtr 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(srcSize.height()) && cairo_image_surface_get_width(image) == static_cast(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 loadResourceIntoBuffer(const char*); + +namespace WebCore { + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +PassRefPtr Image::loadPlatformResource(const char *name) +{ + RefPtr buffer = loadResourceIntoBuffer(name); + RefPtr 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 + +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 + +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 + +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 + +#if PLATFORM(CG) +#include +#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 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 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(lParam); + longPtr = reinterpret_cast(lpcs->lpCreateParams); + ::SetWindowLongPtr(hWnd, GWLP_USERDATA, longPtr); + } + + if (MediaPlayerPrivateFullscreenWindow* window = reinterpret_cast(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(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 + +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); +#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 m_layerRenderer; + RefPtr 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 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*) +{ + 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 MediaPlayerPrivateQuickTimeVisualContext::buffered() const +{ + RefPtr 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