diff options
Diffstat (limited to 'WebCore/platform/graphics')
77 files changed, 4341 insertions, 787 deletions
diff --git a/WebCore/platform/graphics/FloatPoint3D.cpp b/WebCore/platform/graphics/FloatPoint3D.cpp index 8c21ef3..3d37eea 100644 --- a/WebCore/platform/graphics/FloatPoint3D.cpp +++ b/WebCore/platform/graphics/FloatPoint3D.cpp @@ -22,32 +22,10 @@ #include "config.h" #include <math.h> -#include "FloatPoint.h" #include "FloatPoint3D.h" namespace WebCore { -FloatPoint3D::FloatPoint3D() - : m_x(0) - , m_y(0) - , m_z(0) -{ -} - -FloatPoint3D::FloatPoint3D(float x, float y, float z) - : m_x(x) - , m_y(y) - , m_z(z) -{ -} - -FloatPoint3D::FloatPoint3D(const FloatPoint& p) - : m_x(p.x()) - , m_y(p.y()) - , m_z(0) -{ -} - void FloatPoint3D::normalize() { float length = sqrtf(m_x * m_x + m_y * m_y + m_z * m_z); diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h index 73c3a37..d10e3c1 100644 --- a/WebCore/platform/graphics/FloatPoint3D.h +++ b/WebCore/platform/graphics/FloatPoint3D.h @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org> 2004, 2005 Rob Buis <buis@kde.org> 2005 Eric Seidel <eric@webkit.org> + 2010 Zoltan Herczeg <zherczeg@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -22,15 +23,39 @@ #ifndef FloatPoint3D_h #define FloatPoint3D_h -namespace WebCore { +#include "FloatPoint.h" -class FloatPoint; +namespace WebCore { class FloatPoint3D { public: - FloatPoint3D(); - FloatPoint3D(float x, float y, float z); - FloatPoint3D(const FloatPoint&); + FloatPoint3D() + : m_x(0) + , m_y(0) + , m_z(0) + { + } + + FloatPoint3D(float x, float y, float z) + : m_x(x) + , m_y(y) + , m_z(z) + { + } + + FloatPoint3D(const FloatPoint& p) + : m_x(p.x()) + , m_y(p.y()) + , m_z(0) + { + } + + FloatPoint3D(const FloatPoint3D& p) + : m_x(p.x()) + , m_y(p.y()) + , m_z(p.z()) + { + } float x() const { return m_x; } void setX(float x) { m_x = x; } @@ -59,6 +84,12 @@ inline bool operator!=(const FloatPoint3D& a, const FloatPoint3D& b) return a.x() != b.x() || a.y() != b.y() || a.z() != b.z(); } +inline float operator*(const FloatPoint3D& a, const FloatPoint3D& b) +{ + // dot product + return a.x() * b.x() + a.y() * b.y() + a.z() * b.z(); +} + } // namespace WebCore #endif // FloatPoint3D_h diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp index 21380be..2f7c216 100644 --- a/WebCore/platform/graphics/Font.cpp +++ b/WebCore/platform/graphics/Font.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 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 @@ -26,7 +26,6 @@ #include "FloatRect.h" #include "FontCache.h" -#include "FontFallbackList.h" #include "IntPoint.h" #include "GlyphBuffer.h" #include "WidthIterator.h" @@ -101,10 +100,6 @@ Font& Font::operator=(const Font& other) return *this; } -Font::~Font() -{ -} - bool Font::operator==(const Font& other) const { // Our FontData don't have to be checked, since checking the font description will be fine. @@ -123,24 +118,6 @@ bool Font::operator==(const Font& other) const && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0); } -const SimpleFontData* Font::primaryFont() const -{ - ASSERT(m_fontList); - return m_fontList->primarySimpleFontData(this); -} - -const FontData* Font::fontDataAt(unsigned index) const -{ - ASSERT(m_fontList); - return m_fontList->fontDataAt(this, index); -} - -const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const -{ - ASSERT(m_fontList); - return m_fontList->fontDataForCharacters(this, characters, length); -} - void Font::update(PassRefPtr<FontSelector> fontSelector) const { // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up @@ -153,12 +130,6 @@ void Font::update(PassRefPtr<FontSelector> fontSelector) const m_fontList->invalidate(fontSelector); } -bool Font::isFixedPitch() const -{ - ASSERT(m_fontList); - return m_fontList->isFixedPitch(this); -} - void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { // Don't draw anything while we are using custom fonts that are in the process of loading. @@ -261,11 +232,6 @@ bool Font::isSVGFont() const } #endif -FontSelector* Font::fontSelector() const -{ - return m_fontList ? m_fontList->fontSelector() : 0; -} - String Font::normalizeSpaces(const String& string) { const UChar* characters = string.characters(); diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h index da546f0..ef305c5 100644 --- a/WebCore/platform/graphics/Font.h +++ b/WebCore/platform/graphics/Font.h @@ -2,7 +2,7 @@ * Copyright (C) 2000 Lars Knoll (knoll@kde.org) * (C) 2000 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006, 2007 Apple Computer, Inc. + * Copyright (C) 2003, 2006, 2007, 2010 Apple Inc. All rights reserved. * Copyright (C) 2008 Holger Hans Peter Freyther * * This library is free software; you can redistribute it and/or @@ -27,6 +27,7 @@ #include "CharacterNames.h" #include "FontDescription.h" +#include "FontFallbackList.h" #include "SimpleFontData.h" #include "TextRun.h" #include "TypesettingFeatures.h" @@ -226,6 +227,39 @@ private: bool m_isPlatformFont; }; +inline Font::~Font() +{ +} + +inline const SimpleFontData* Font::primaryFont() const +{ + ASSERT(m_fontList); + return m_fontList->primarySimpleFontData(this); +} + +inline const FontData* Font::fontDataAt(unsigned index) const +{ + ASSERT(m_fontList); + return m_fontList->fontDataAt(this, index); +} + +inline const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const +{ + ASSERT(m_fontList); + return m_fontList->fontDataForCharacters(this, characters, length); +} + +inline bool Font::isFixedPitch() const +{ + ASSERT(m_fontList); + return m_fontList->isFixedPitch(this); +} + +inline FontSelector* Font::fontSelector() const +{ + return m_fontList ? m_fontList->fontSelector() : 0; +} + } #endif diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp index b3eca85..cb54cdd 100644 --- a/WebCore/platform/graphics/FontCache.cpp +++ b/WebCore/platform/graphics/FontCache.cpp @@ -56,9 +56,9 @@ FontCache::FontCache() struct FontPlatformDataCacheKey : FastAllocBase { FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false, bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode) - : m_family(family) - , m_size(size) + : m_size(size) , m_weight(weight) + , m_family(family) , m_italic(italic) , m_printerFont(isPrinterFont) , m_renderingMode(renderingMode) @@ -75,9 +75,9 @@ struct FontPlatformDataCacheKey : FastAllocBase { m_renderingMode == other.m_renderingMode; } - AtomicString m_family; unsigned m_size; unsigned m_weight; + AtomicString m_family; bool m_italic; bool m_printerFont; FontRenderingMode m_renderingMode; diff --git a/WebCore/platform/graphics/FontFallbackList.h b/WebCore/platform/graphics/FontFallbackList.h index 14ebbe4..a10f5af 100644 --- a/WebCore/platform/graphics/FontFallbackList.h +++ b/WebCore/platform/graphics/FontFallbackList.h @@ -1,8 +1,5 @@ /* - * 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 Apple Computer, Inc. + * Copyright (C) 2006, 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 @@ -21,8 +18,8 @@ * */ -// This file has no guards on purpose in order to detect redundant includes. This is a private header -// and so this may catch someone trying to include this file in public cpp files. +#ifndef FontFallbackList_h +#define FontFallbackList_h #include "FontSelector.h" #include "SimpleFontData.h" @@ -89,3 +86,4 @@ private: } +#endif diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.h b/WebCore/platform/graphics/GlyphPageTreeNode.h index 7918ac5..b68c0ed 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.h +++ b/WebCore/platform/graphics/GlyphPageTreeNode.h @@ -172,8 +172,8 @@ public: : m_parent(0) , m_level(0) , m_isSystemFallback(false) - , m_systemFallbackChild(0) , m_customFontCount(0) + , m_systemFallbackChild(0) #ifndef NDEBUG , m_pageNumber(0) #endif @@ -221,11 +221,11 @@ private: GlyphPageTreeNode* m_parent; RefPtr<GlyphPage> m_page; - unsigned m_level; - bool m_isSystemFallback; + unsigned m_level : 31; + bool m_isSystemFallback : 1; + unsigned m_customFontCount; HashMap<const FontData*, GlyphPageTreeNode*> m_children; GlyphPageTreeNode* m_systemFallbackChild; - unsigned m_customFontCount; #ifndef NDEBUG unsigned m_pageNumber; diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index b64e9d3..b62f52c 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -60,12 +60,12 @@ const Platform3DObject NullPlatform3DObject = 0; namespace WebCore { class WebGLActiveInfo; - class WebGLArray; + class ArrayBufferView; class WebGLBuffer; - class WebGLUnsignedByteArray; - class WebGLFloatArray; + class Uint8Array; + class FloatArray; class WebGLFramebuffer; - class WebGLIntArray; + class Int32Array; class WebGLProgram; class WebGLRenderbuffer; class WebGLRenderingContext; @@ -499,8 +499,8 @@ namespace WebCore { void blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha); void bufferData(unsigned long target, int size, unsigned long usage); - void bufferData(unsigned long target, WebGLArray* data, unsigned long usage); - void bufferSubData(unsigned long target, long offset, WebGLArray* data); + void bufferData(unsigned long target, ArrayBufferView* data, unsigned long usage); + void bufferSubData(unsigned long target, long offset, ArrayBufferView* data); unsigned long checkFramebufferStatus(unsigned long target); void clear(unsigned long mask); diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index b7567bf..c1e2ed6 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -465,17 +465,21 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBe } ts << ")\n"; - writeIndent(ts, indent + 1); - ts << "(childrenTransform "; - if (m_childrenTransform.isIdentity()) - ts << "identity"; - else { - ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] "; - ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] "; - ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] "; - ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "]"; + // Avoid dumping the sublayer transform on the root layer, because it's used for geometry flipping, whose behavior + // differs between platforms. + if (parent()) { + writeIndent(ts, indent + 1); + ts << "(childrenTransform "; + if (m_childrenTransform.isIdentity()) + ts << "identity"; + else { + ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] "; + ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] "; + ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] "; + ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "]"; + } + ts << ")\n"; } - ts << ")\n"; if (m_replicaLayer) { writeIndent(ts, indent + 1); diff --git a/WebCore/platform/graphics/ImageBuffer.cpp b/WebCore/platform/graphics/ImageBuffer.cpp index 55305d1..71b8189 100644 --- a/WebCore/platform/graphics/ImageBuffer.cpp +++ b/WebCore/platform/graphics/ImageBuffer.cpp @@ -42,7 +42,6 @@ void ImageBuffer::transformColorSpace(ImageColorSpace srcColorSpace, ImageColorS (dstColorSpace != LinearRGB && dstColorSpace != DeviceRGB)) return; - Vector<int> lookUpTable; if (dstColorSpace == LinearRGB) { if (m_linearRgbLUT.isEmpty()) { for (unsigned i = 0; i < 256; i++) { @@ -57,8 +56,8 @@ void ImageBuffer::transformColorSpace(ImageColorSpace srcColorSpace, ImageColorS } else if (dstColorSpace == DeviceRGB) { if (m_deviceRgbLUT.isEmpty()) { for (unsigned i = 0; i < 256; i++) { - float color = i / 255.0f; - color = pow(1.055f * color, 1.0f / 2.4f) - 0.055f; + float color = i / 255.0f; + color = (powf(color, 1.0f / 2.4f) * 1.055f) - 0.055f; color = std::max(0.0f, color); color = std::min(1.0f, color); m_deviceRgbLUT.append(static_cast<int>(color * 255)); diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h index cc40f5e..5c6d75e 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -68,6 +68,11 @@ class String; #if PLATFORM(CG) typedef CGImageSourceRef NativeImageSourcePtr; typedef CGImageRef NativeImagePtr; +#elif PLATFORM(OPENVG) +class ImageDecoder; +class TiledImageOpenVG; +typedef ImageDecoder* NativeImageSourcePtr; +typedef TiledImageOpenVG* NativeImagePtr; #elif PLATFORM(QT) class ImageDecoderQt; typedef ImageDecoderQt* NativeImageSourcePtr; diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index ee82083..ab88987 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -27,14 +27,14 @@ #if ENABLE(VIDEO) #include "MediaPlayer.h" -#include "MediaPlayerPrivate.h" #include "ContentType.h" +#include "Document.h" +#include "Frame.h" +#include "FrameView.h" #include "IntRect.h" #include "MIMETypeRegistry.h" -#include "FrameView.h" -#include "Frame.h" -#include "Document.h" +#include "MediaPlayerPrivate.h" #include "TimeRanges.h" #if PLATFORM(QT) @@ -46,7 +46,8 @@ #elif OS(WINCE) && !PLATFORM(QT) #include "MediaPlayerPrivateWince.h" #elif PLATFORM(WIN) -#include "MediaPlayerPrivateQuickTimeWin.h" +#include "MediaPlayerPrivateQuickTimeVisualContext.h" +#include "MediaPlayerPrivateQuicktimeWin.h" #elif PLATFORM(GTK) #include "MediaPlayerPrivateGStreamer.h" #elif PLATFORM(QT) @@ -64,6 +65,8 @@ namespace WebCore { +const PlatformMedia NoPlatformMedia = { PlatformMedia::None, {0} }; + // a null player to make MediaPlayer logic simpler class NullMediaPlayerPrivate : public MediaPlayerPrivateInterface { @@ -165,6 +168,9 @@ static Vector<MediaPlayerFactory*>& installedMediaEngines() #if USE(GSTREAMER) MediaPlayerPrivateGStreamer::registerMediaEngine(addMediaEngine); #else +#if PLATFORM(WIN) + MediaPlayerPrivateQuickTimeVisualContext::registerMediaEngine(addMediaEngine); +#endif // FIXME: currently all the MediaEngines are named // MediaPlayerPrivate. This code will need an update when bug // 36663 is adressed. diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 89021c3..9abbb15 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -49,6 +49,8 @@ #else class QTMovie; #endif +class QTMovieGWorld; +class QTMovieVisualContext; namespace WebCore { @@ -56,11 +58,22 @@ namespace WebCore { // types supported by the current media player. // We have to do that has multiple media players // backend can live at runtime. -typedef struct PlatformMedia { - QTMovie* qtMovie; -} PlatformMedia; +struct PlatformMedia { + enum { + None, + QTMovieType, + QTMovieGWorldType, + QTMovieVisualContextType + } type; + + union { + QTMovie* qtMovie; + QTMovieGWorld* qtMovieGWorld; + QTMovieVisualContext* qtMovieVisualContext; + } media; +}; -static const PlatformMedia NoPlatformMedia = { 0 }; +extern const PlatformMedia NoPlatformMedia; class ContentType; class FrameView; diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h index 4c34f2b..bc897be 100644 --- a/WebCore/platform/graphics/SimpleFontData.h +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -191,7 +191,7 @@ private: FontPlatformData m_platformData; - mutable GlyphMetricsMap<FloatRect> m_glyphToBoundsMap; + mutable OwnPtr<GlyphMetricsMap<FloatRect> > m_glyphToBoundsMap; mutable GlyphMetricsMap<float> m_glyphToWidthMap; bool m_treatAsFixedPitch; @@ -255,12 +255,17 @@ ALWAYS_INLINE FloatRect SimpleFontData::boundsForGlyph(Glyph glyph) const if (glyph == m_zeroWidthSpaceGlyph && glyph) return FloatRect(); - FloatRect bounds = m_glyphToBoundsMap.metricsForGlyph(glyph); - if (bounds.width() != cGlyphSizeUnknown) - return bounds; + FloatRect bounds; + if (m_glyphToBoundsMap) { + bounds = m_glyphToBoundsMap->metricsForGlyph(glyph); + if (bounds.width() != cGlyphSizeUnknown) + return bounds; + } bounds = platformBoundsForGlyph(glyph); - m_glyphToBoundsMap.setMetricsForGlyph(glyph, bounds); + if (!m_glyphToBoundsMap) + m_glyphToBoundsMap.set(new GlyphMetricsMap<FloatRect>()); + m_glyphToBoundsMap->setMetricsForGlyph(glyph, bounds); return bounds; } diff --git a/WebCore/platform/graphics/TiledBackingStore.cpp b/WebCore/platform/graphics/TiledBackingStore.cpp index 6214f1b..0250061 100644 --- a/WebCore/platform/graphics/TiledBackingStore.cpp +++ b/WebCore/platform/graphics/TiledBackingStore.cpp @@ -120,22 +120,23 @@ void TiledBackingStore::paint(GraphicsContext* context, const IntRect& rect) if (currentTile && currentTile->isReadyToPaint()) currentTile->paint(context, dirtyRect); else { - FloatRect tileRect = tileRectForCoordinate(currentCoordinate); - FloatRect target = intersection(tileRect, FloatRect(rect)); - Tile::paintCheckerPattern(context, target); + IntRect tileRect = tileRectForCoordinate(currentCoordinate); + IntRect target = intersection(tileRect, dirtyRect); + if (target.isEmpty()) + continue; + Tile::paintCheckerPattern(context, FloatRect(target)); } } } context->restore(); } -void TiledBackingStore::viewportChanged(const IntRect& contentsViewport) +void TiledBackingStore::adjustVisibleRect() { - IntRect viewport = mapFromContents(contentsViewport); - if (m_viewport == viewport) + IntRect visibleRect = mapFromContents(m_client->tiledBackingStoreVisibleRect()); + if (m_previousVisibleRect == visibleRect) return; - - m_viewport = viewport; + m_previousVisibleRect = visibleRect; startTileCreationTimer(); } @@ -177,24 +178,27 @@ void TiledBackingStore::createTiles() { if (m_contentsFrozen) return; + + IntRect visibleRect = mapFromContents(m_client->tiledBackingStoreVisibleRect()); + m_previousVisibleRect = visibleRect; - if (m_viewport.isEmpty()) + if (visibleRect.isEmpty()) return; // Remove tiles that extend outside the current contents rect. dropOverhangingTiles(); // FIXME: Make configurable/adapt to memory. - IntRect keepRect = m_viewport; - keepRect.inflateX(m_viewport.width()); - keepRect.inflateY(3 * m_viewport.height()); + IntRect keepRect = visibleRect; + keepRect.inflateX(visibleRect.width()); + keepRect.inflateY(3 * visibleRect.height()); keepRect.intersect(contentsRect()); dropTilesOutsideRect(keepRect); - IntRect coverRect = m_viewport; - coverRect.inflateX(m_viewport.width() / 2); - coverRect.inflateY(2 * m_viewport.height()); + IntRect coverRect = visibleRect; + coverRect.inflateX(visibleRect.width() / 2); + coverRect.inflateY(2 * visibleRect.height()); coverRect.intersect(contentsRect()); // Search for the tile position closest to the viewport center that does not yet contain a tile. @@ -211,7 +215,7 @@ void TiledBackingStore::createTiles() continue; ++requiredTileCount; // Distance is 0 for all currently visible tiles. - double distance = tileDistance(m_viewport, currentCoordinate); + double distance = tileDistance(visibleRect, currentCoordinate); if (distance > shortestDistance) continue; if (distance < shortestDistance) { diff --git a/WebCore/platform/graphics/TiledBackingStore.h b/WebCore/platform/graphics/TiledBackingStore.h index 8ed4336..d12f191 100644 --- a/WebCore/platform/graphics/TiledBackingStore.h +++ b/WebCore/platform/graphics/TiledBackingStore.h @@ -41,7 +41,7 @@ public: TiledBackingStore(TiledBackingStoreClient*); ~TiledBackingStore(); - void viewportChanged(const IntRect& viewportRect); + void adjustVisibleRect(); float contentsScale() { return m_contentsScale; } void setContentsScale(float); @@ -95,7 +95,7 @@ private: IntSize m_tileSize; - IntRect m_viewport; + IntRect m_previousVisibleRect; float m_contentsScale; float m_pendingScale; diff --git a/WebCore/platform/graphics/TiledBackingStoreClient.h b/WebCore/platform/graphics/TiledBackingStoreClient.h index 4adbbab..c5845b9 100644 --- a/WebCore/platform/graphics/TiledBackingStoreClient.h +++ b/WebCore/platform/graphics/TiledBackingStoreClient.h @@ -29,6 +29,7 @@ public: virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&) = 0; virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea) = 0; virtual IntRect tiledBackingStoreContentsRect() = 0; + virtual IntRect tiledBackingStoreVisibleRect() = 0; }; #else diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index c2aae49..71a2430 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -138,12 +138,14 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } } else if (context->fillPattern()) { AffineTransform affine; - cairo_set_source(cr, context->fillPattern()->createPlatformPattern(affine)); + cairo_pattern_t* pattern = context->fillPattern()->createPlatformPattern(affine); + cairo_set_source(cr, pattern); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } + cairo_pattern_destroy(pattern); } else { float red, green, blue, alpha; fillColor.getRGBA(red, green, blue, alpha); @@ -172,12 +174,14 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } } else if (context->strokePattern()) { AffineTransform affine; - cairo_set_source(cr, context->strokePattern()->createPlatformPattern(affine)); + cairo_pattern_t* pattern = context->strokePattern()->createPlatformPattern(affine); + cairo_set_source(cr, pattern); if (context->getAlpha() < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, context->getAlpha()); cairo_pop_group_to_source(cr); } + cairo_pattern_destroy(pattern); } else { Color strokeColor = context->strokeColor(); float red, green, blue, alpha; diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 0aa6b83..a2dcbaf 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -75,10 +75,12 @@ static inline void setColor(cairo_t* cr, const Color& col) static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) { + cairo_pattern_t* pattern = 0; cairo_save(cr); if (gcp->state.fillPattern) { AffineTransform affine; - cairo_set_source(cr, gcp->state.fillPattern->createPlatformPattern(affine)); + pattern = gcp->state.fillPattern->createPlatformPattern(affine); + cairo_set_source(cr, pattern); } else if (gcp->state.fillGradient) cairo_set_source(cr, gcp->state.fillGradient->platformGradient()); else @@ -86,14 +88,18 @@ static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr, Graphi cairo_clip_preserve(cr); cairo_paint_with_alpha(cr, gcp->state.globalAlpha); cairo_restore(cr); + if (pattern) + cairo_pattern_destroy(pattern); } static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) { + cairo_pattern_t* pattern = 0; cairo_save(cr); if (gcp->state.strokePattern) { AffineTransform affine; - cairo_set_source(cr, gcp->state.strokePattern->createPlatformPattern(affine)); + pattern = gcp->state.strokePattern->createPlatformPattern(affine); + cairo_set_source(cr, pattern); } else if (gcp->state.strokeGradient) cairo_set_source(cr, gcp->state.strokeGradient->platformGradient()); else { @@ -107,6 +113,8 @@ static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr, Grap } cairo_stroke_preserve(cr); cairo_restore(cr); + if (pattern) + cairo_pattern_destroy(pattern); } // A fillRect helper diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp index 1227a6a..259cc0c 100644 --- a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -311,7 +311,23 @@ void GraphicsLayerChromium::setContentsRect(const IntRect& rect) void GraphicsLayerChromium::setContentsToImage(Image* image) { - // FIXME: Implement + 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(); + + if (childrenChanged) + updateSublayerList(); } void GraphicsLayerChromium::setContentsToVideo(PlatformLayer* videoLayer) @@ -489,7 +505,22 @@ void GraphicsLayerChromium::updateLayerBackgroundColor() void GraphicsLayerChromium::updateContentsImage() { - // FIXME: Implement + if (m_pendingContentsImage) { + if (!m_contentsLayer.get()) { + RefPtr<LayerChromium> imageLayer = LayerChromium::create(LayerChromium::Layer, this); + + setupContentsLayer(imageLayer.get()); + m_contentsLayer = imageLayer; + // m_contentsLayer will be parented by updateSublayerList. + } + m_contentsLayer->setContents(m_pendingContentsImage); + m_pendingContentsImage = 0; + + updateContentsRect(); + } else { + // No image. m_contentsLayer will be removed via updateSublayerList. + m_contentsLayer = 0; + } } void GraphicsLayerChromium::updateContentsVideo() diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h index 03a6d41..bc86799 100644 --- a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h @@ -140,6 +140,8 @@ private: ContentsLayerPurpose m_contentsLayerPurpose; bool m_contentsLayerHasBackgroundColor : 1; + + NativeImagePtr m_pendingContentsImage; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/LayerChromium.cpp b/WebCore/platform/graphics/chromium/LayerChromium.cpp index 4540ac1..05be15c 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -69,13 +69,15 @@ LayerChromium::LayerChromium(LayerType type, GraphicsLayerChromium* owner) , m_skiaContext(0) , m_graphicsContext(0) , m_geometryFlipped(false) + , m_contents(0) { updateGraphicsContext(m_backingStoreRect); } LayerChromium::~LayerChromium() { - // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer. + // Our superlayer should be holding a reference to us so there should be no + // way for us to be destroyed while we still have a superlayer. ASSERT(!superlayer()); } @@ -120,10 +122,18 @@ void LayerChromium::drawDebugBorder() m_graphicsContext->drawLine(IntPoint(0, m_bounds.height()), IntPoint(m_bounds.width(), m_bounds.height())); } +void LayerChromium::setContents(NativeImagePtr contents) +{ + // Check if the image has changed. + if (m_contents == contents) + return; + m_contents = contents; +} + void LayerChromium::setNeedsCommit() { // Call notifySyncRequired(), which in this implementation plumbs through to - // call setRootLayerNeedsDisplay() on the WebView, which will cause LayerRendererSkia + // call setRootLayerNeedsDisplay() on the WebView, which will cause LayerRendererChromium // to render a frame. if (m_owner) m_owner->notifySyncRequired(); @@ -137,18 +147,16 @@ void LayerChromium::addSublayer(PassRefPtr<LayerChromium> sublayer) void LayerChromium::insertSublayer(PassRefPtr<LayerChromium> sublayer, size_t index) { index = min(index, m_sublayers.size()); - m_sublayers.insert(index, sublayer); + sublayer->removeFromSuperlayer(); sublayer->setSuperlayer(this); + m_sublayers.insert(index, sublayer); setNeedsCommit(); } void LayerChromium::removeFromSuperlayer() { - LayerChromium* superlayer = this->superlayer(); - if (!superlayer) - return; - - superlayer->removeSublayer(this); + if (m_superlayer) + m_superlayer->removeSublayer(this); } void LayerChromium::removeSublayer(LayerChromium* sublayer) @@ -157,11 +165,33 @@ void LayerChromium::removeSublayer(LayerChromium* sublayer) if (foundIndex == -1) return; - m_sublayers.remove(foundIndex); sublayer->setSuperlayer(0); + m_sublayers.remove(foundIndex); setNeedsCommit(); } +void LayerChromium::replaceSublayer(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer) +{ + ASSERT_ARG(reference, reference); + ASSERT_ARG(reference, reference->superlayer() == this); + + if (reference == newLayer) + return; + + int referenceIndex = indexOfSublayer(reference); + if (referenceIndex == -1) { + ASSERT_NOT_REACHED(); + return; + } + + reference->removeFromSuperlayer(); + + if (newLayer) { + newLayer->removeFromSuperlayer(); + insertSublayer(newLayer, referenceIndex); + } +} + int LayerChromium::indexOfSublayer(const LayerChromium* reference) { for (size_t i = 0; i < m_sublayers.size(); i++) { @@ -214,18 +244,23 @@ const LayerChromium* LayerChromium::rootLayer() const void LayerChromium::removeAllSublayers() { - m_sublayers.clear(); + while (m_sublayers.size()) { + LayerChromium* layer = m_sublayers[0].get(); + ASSERT(layer->superlayer()); + layer->removeFromSuperlayer(); + } setNeedsCommit(); } void LayerChromium::setSublayers(const Vector<RefPtr<LayerChromium> >& sublayers) { - m_sublayers = sublayers; -} + if (sublayers == m_sublayers) + return; -void LayerChromium::setSuperlayer(LayerChromium* superlayer) -{ - m_superlayer = superlayer; + removeAllSublayers(); + size_t listSize = sublayers.size(); + for (size_t i = 0; i < listSize; i++) + addSublayer(sublayers[i]); } LayerChromium* LayerChromium::superlayer() const diff --git a/WebCore/platform/graphics/chromium/LayerChromium.h b/WebCore/platform/graphics/chromium/LayerChromium.h index 55b1288..5b93f77 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/WebCore/platform/graphics/chromium/LayerChromium.h @@ -67,6 +67,7 @@ public: void addSublayer(PassRefPtr<LayerChromium>); void insertSublayer(PassRefPtr<LayerChromium>, size_t index); + void replaceSublayer(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer); void removeFromSuperlayer(); void setAnchorPoint(const FloatPoint& anchorPoint) { m_anchorPoint = anchorPoint; setNeedsCommit(); } @@ -140,7 +141,6 @@ public: void setSublayerTransform(const TransformationMatrix& transform) { m_sublayerTransform = transform; setNeedsCommit(); } const TransformationMatrix& sublayerTransform() const { return m_sublayerTransform; } - void setSuperlayer(LayerChromium* superlayer); LayerChromium* superlayer() const; @@ -152,6 +152,9 @@ public: void updateContents(); + void setContents(NativeImagePtr contents); + NativeImagePtr contents() const { return m_contents; } + skia::PlatformCanvas* platformCanvas() { return m_canvas.get(); } GraphicsContext* graphicsContext() { return m_graphicsContext.get(); } @@ -164,6 +167,8 @@ private: void setNeedsCommit(); + void setSuperlayer(LayerChromium* superlayer) { m_superlayer = superlayer; } + void paintMe(); size_t numSublayers() const @@ -177,17 +182,19 @@ private: // This should only be called from removeFromSuperlayer. void removeSublayer(LayerChromium*); - // Re-create the canvas and graphics context. This method - // must be called every time the layer is resized. + // Re-creates the canvas and graphics context. This method + // must be called every time the layer is resized. Only layers void updateGraphicsContext(const IntSize&); Vector<RefPtr<LayerChromium> > m_sublayers; LayerChromium* m_superlayer; GraphicsLayerChromium* m_owner; +#if PLATFORM(SKIA) OwnPtr<skia::PlatformCanvas> m_canvas; OwnPtr<PlatformContextSkia> m_skiaContext; OwnPtr<GraphicsContext> m_graphicsContext; +#endif LayerType m_layerType; @@ -217,6 +224,7 @@ private: bool m_needsDisplayOnBoundsChange; ContentsGravityType m_contentsGravity; + NativeImagePtr m_contents; String m_name; }; diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index f362148..99c0ae7 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -145,6 +145,42 @@ void FEBlend::dump() { } +static TextStream& operator<<(TextStream& ts, const BlendModeType& type) +{ + switch (type) { + case FEBLEND_MODE_UNKNOWN: + ts << "UNKNOWN"; + break; + case FEBLEND_MODE_NORMAL: + ts << "NORMAL"; + break; + case FEBLEND_MODE_MULTIPLY: + ts << "MULTIPLY"; + break; + case FEBLEND_MODE_SCREEN: + ts << "SCREEN"; + break; + case FEBLEND_MODE_DARKEN: + ts << "DARKEN"; + break; + case FEBLEND_MODE_LIGHTEN: + ts << "LIGHTEN"; + break; + } + return ts; +} + +TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feBlend"; + FilterEffect::externalRepresentation(ts); + ts << " mode=\"" << m_mode << "\"]\n"; + m_in->externalRepresentation(ts, indent + 1); + m_in2->externalRepresentation(ts, indent + 1); + return ts; +} + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEBlend.h b/WebCore/platform/graphics/filters/FEBlend.h index 31c625f..a387814 100644 --- a/WebCore/platform/graphics/filters/FEBlend.h +++ b/WebCore/platform/graphics/filters/FEBlend.h @@ -51,6 +51,7 @@ namespace WebCore { virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get(), m_in2.get()); } void apply(Filter*); void dump(); + TextStream& externalRepresentation(TextStream&, int indent) const; private: FEBlend(FilterEffect*, FilterEffect*, BlendModeType); diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index bd19d14..c5ae3b9 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -195,6 +195,51 @@ void FEColorMatrix::dump() { } +static TextStream& operator<<(TextStream& ts, const ColorMatrixType& type) +{ + switch (type) { + case FECOLORMATRIX_TYPE_UNKNOWN: + ts << "UNKNOWN"; + break; + case FECOLORMATRIX_TYPE_MATRIX: + ts << "MATRIX"; + break; + case FECOLORMATRIX_TYPE_SATURATE: + ts << "SATURATE"; + break; + case FECOLORMATRIX_TYPE_HUEROTATE: + ts << "HUEROTATE"; + break; + case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: + ts << "LUMINANCETOALPHA"; + break; + } + return ts; +} + +TextStream& FEColorMatrix::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feColorMatrix"; + FilterEffect::externalRepresentation(ts); + ts << " type=\"" << m_type << "\""; + if (!m_values.isEmpty()) { + ts << " values=\""; + Vector<float>::const_iterator ptr = m_values.begin(); + const Vector<float>::const_iterator end = m_values.end(); + while (ptr < end) { + ts << *ptr; + ++ptr; + if (ptr < end) + ts << " "; + } + ts << "\""; + } + ts << "]\n"; + m_in->externalRepresentation(ts, indent + 1); + return ts; +} + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.h b/WebCore/platform/graphics/filters/FEColorMatrix.h index 106b2fa..104a2e8 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.h +++ b/WebCore/platform/graphics/filters/FEColorMatrix.h @@ -51,6 +51,7 @@ namespace WebCore { virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); } void apply(Filter*); void dump(); + TextStream& externalRepresentation(TextStream&, int indent) const; private: FEColorMatrix(FilterEffect*, ColorMatrixType, const Vector<float>&); diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index f9aa011..19df970 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -185,6 +185,60 @@ void FEComponentTransfer::dump() { } +static TextStream& operator<<(TextStream& ts, const ComponentTransferType& type) +{ + switch (type) { + case FECOMPONENTTRANSFER_TYPE_UNKNOWN: + ts << "UNKNOWN"; + break; + case FECOMPONENTTRANSFER_TYPE_IDENTITY: + ts << "IDENTITY"; + break; + case FECOMPONENTTRANSFER_TYPE_TABLE: + ts << "TABLE"; + break; + case FECOMPONENTTRANSFER_TYPE_DISCRETE: + ts << "DISCRETE"; + break; + case FECOMPONENTTRANSFER_TYPE_LINEAR: + ts << "LINEAR"; + break; + case FECOMPONENTTRANSFER_TYPE_GAMMA: + ts << "GAMMA"; + break; + } + return ts; +} + +static TextStream& operator<<(TextStream& ts, const ComponentTransferFunction& function) +{ + ts << "type=\"" << function.type + << "\" slope=\"" << function.slope + << "\" intercept=\"" << function.intercept + << "\" amplitude=\"" << function.amplitude + << "\" exponent=\"" << function.exponent + << "\" offset=\"" << function.offset << "\""; + return ts; +} + +TextStream& FEComponentTransfer::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feComponentTransfer"; + FilterEffect::externalRepresentation(ts); + ts << " \n"; + writeIndent(ts, indent + 2); + ts << "{red: " << m_redFunc << "}\n"; + writeIndent(ts, indent + 2); + ts << "{green: " << m_greenFunc << "}\n"; + writeIndent(ts, indent + 2); + ts << "{blue: " << m_blueFunc << "}\n"; + writeIndent(ts, indent + 2); + ts << "{alpha: " << m_alphaFunc << "}]\n"; + m_in->externalRepresentation(ts, indent + 1); + return ts; +} + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.h b/WebCore/platform/graphics/filters/FEComponentTransfer.h index ab84cf0..a79e5df 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.h +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.h @@ -81,6 +81,7 @@ namespace WebCore { virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); } void apply(Filter*); void dump(); + TextStream& externalRepresentation(TextStream&, int indent) const; private: FEComponentTransfer(FilterEffect*,const ComponentTransferFunction&, const ComponentTransferFunction&, diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index 67d3d27..18df3b2 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -173,6 +173,48 @@ void FEComposite::dump() { } +static TextStream& operator<<(TextStream& ts, const CompositeOperationType& type) +{ + switch (type) { + case FECOMPOSITE_OPERATOR_UNKNOWN: + ts << "UNKNOWN"; + break; + case FECOMPOSITE_OPERATOR_OVER: + ts << "OVER"; + break; + case FECOMPOSITE_OPERATOR_IN: + ts << "IN"; + break; + case FECOMPOSITE_OPERATOR_OUT: + ts << "OUT"; + break; + case FECOMPOSITE_OPERATOR_ATOP: + ts << "ATOP"; + break; + case FECOMPOSITE_OPERATOR_XOR: + ts << "XOR"; + break; + case FECOMPOSITE_OPERATOR_ARITHMETIC: + ts << "ARITHMETIC"; + break; + } + return ts; +} + +TextStream& FEComposite::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feComposite"; + FilterEffect::externalRepresentation(ts); + ts << " operation=\"" << m_type << "\""; + if (m_type == FECOMPOSITE_OPERATOR_ARITHMETIC) + ts << " k1=\"" << m_k1 << "\" k2=\"" << m_k2 << "\" k3=\"" << m_k3 << "\" k4=\"" << m_k4 << "\""; + ts << "]\n"; + m_in->externalRepresentation(ts, indent + 1); + m_in2->externalRepresentation(ts, indent + 1); + return ts; +} + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEComposite.h b/WebCore/platform/graphics/filters/FEComposite.h index ad096f2..b05cc66 100644 --- a/WebCore/platform/graphics/filters/FEComposite.h +++ b/WebCore/platform/graphics/filters/FEComposite.h @@ -30,52 +30,53 @@ namespace WebCore { - enum CompositeOperationType { - FECOMPOSITE_OPERATOR_UNKNOWN = 0, - FECOMPOSITE_OPERATOR_OVER = 1, - FECOMPOSITE_OPERATOR_IN = 2, - FECOMPOSITE_OPERATOR_OUT = 3, - FECOMPOSITE_OPERATOR_ATOP = 4, - FECOMPOSITE_OPERATOR_XOR = 5, - FECOMPOSITE_OPERATOR_ARITHMETIC = 6 - }; - - class FEComposite : public FilterEffect { - public: - static PassRefPtr<FEComposite> create(FilterEffect*, FilterEffect*, const CompositeOperationType&, - const float&, const float&, const float&, const float&); - - CompositeOperationType operation() const; - void setOperation(CompositeOperationType); - - float k1() const; - void setK1(float); - - float k2() const; - void setK2(float); - - float k3() const; - void setK3(float); - - float k4() const; - void setK4(float); - - virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get(), m_in2.get()); } - void apply(Filter*); - void dump(); - - private: - FEComposite(FilterEffect*, FilterEffect*, const CompositeOperationType&, - const float&, const float&, const float&, const float&); - - RefPtr<FilterEffect> m_in; - RefPtr<FilterEffect> m_in2; - CompositeOperationType m_type; - float m_k1; - float m_k2; - float m_k3; - float m_k4; - }; +enum CompositeOperationType { + FECOMPOSITE_OPERATOR_UNKNOWN = 0, + FECOMPOSITE_OPERATOR_OVER = 1, + FECOMPOSITE_OPERATOR_IN = 2, + FECOMPOSITE_OPERATOR_OUT = 3, + FECOMPOSITE_OPERATOR_ATOP = 4, + FECOMPOSITE_OPERATOR_XOR = 5, + FECOMPOSITE_OPERATOR_ARITHMETIC = 6 +}; + +class FEComposite : public FilterEffect { +public: + static PassRefPtr<FEComposite> create(FilterEffect*, FilterEffect*, const CompositeOperationType&, + const float&, const float&, const float&, const float&); + + CompositeOperationType operation() const; + void setOperation(CompositeOperationType); + + float k1() const; + void setK1(float); + + float k2() const; + void setK2(float); + + float k3() const; + void setK3(float); + + float k4() const; + void setK4(float); + + virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get(), m_in2.get()); } + void apply(Filter*); + void dump(); + TextStream& externalRepresentation(TextStream&, int indent) const; + +private: + FEComposite(FilterEffect*, FilterEffect*, const CompositeOperationType&, + const float&, const float&, const float&, const float&); + + RefPtr<FilterEffect> m_in; + RefPtr<FilterEffect> m_in2; + CompositeOperationType m_type; + float m_k1; + float m_k2; + float m_k3; + float m_k4; +}; } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp index 0b97e39..61aea90 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -139,6 +139,16 @@ void FEGaussianBlur::dump() { } +TextStream& FEGaussianBlur::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[feGaussianBlur"; + FilterEffect::externalRepresentation(ts); + ts << " stdDeviation=\"" << m_x << ", " << m_y << "\"]\n"; + m_in->externalRepresentation(ts, indent + 1); + return ts; +} + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.h b/WebCore/platform/graphics/filters/FEGaussianBlur.h index ecdb9e3..bcc030e 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.h +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.h @@ -28,27 +28,28 @@ namespace WebCore { - class FEGaussianBlur : public FilterEffect { - public: - static PassRefPtr<FEGaussianBlur> create(FilterEffect*, const float&, const float&); +class FEGaussianBlur : public FilterEffect { +public: + static PassRefPtr<FEGaussianBlur> create(FilterEffect*, const float&, const float&); - float stdDeviationX() const; - void setStdDeviationX(float); + float stdDeviationX() const; + void setStdDeviationX(float); - float stdDeviationY() const; - void setStdDeviationY(float); + float stdDeviationY() const; + void setStdDeviationY(float); - virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); } - void apply(Filter*); - void dump(); + virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); } + void apply(Filter*); + void dump(); + TextStream& externalRepresentation(TextStream&, int indent) const; - private: - FEGaussianBlur(FilterEffect*, const float&, const float&); +private: + FEGaussianBlur(FilterEffect*, const float&, const float&); - RefPtr<FilterEffect> m_in; - float m_x; - float m_y; - }; + RefPtr<FilterEffect> m_in; + float m_x; + float m_y; +}; } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index 5583813..4d7265c 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -77,8 +77,10 @@ GraphicsContext* FilterEffect::getEffectContext() return m_effectBuffer->context(); } -TextStream& FilterEffect::externalRepresentation(TextStream& ts) const +TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const { + // FIXME: We should dump the subRegions of the filter primitives here later. This isn't + // possible at the moment, because we need more detailed informations from the target object. return ts; } diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index a46d795..3b8b5a3 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -26,6 +26,7 @@ #include "FloatRect.h" #include "GraphicsContext.h" #include "ImageBuffer.h" +#include "RenderTreeAsText.h" #include "TextStream.h" #include <wtf/PassOwnPtr.h> @@ -84,7 +85,7 @@ namespace WebCore { virtual bool isSourceInput() { return false; } - virtual TextStream& externalRepresentation(TextStream&) const; + virtual TextStream& externalRepresentation(TextStream&, int indention = 0) const; protected: FilterEffect(); diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index 539bb44..eb23814 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -74,6 +74,13 @@ void SourceAlpha::dump() { } +TextStream& SourceAlpha::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[SourceAlpha]\n"; + return ts; +} + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h index 172d05a..e5c6815 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.h +++ b/WebCore/platform/graphics/filters/SourceAlpha.h @@ -38,6 +38,7 @@ namespace WebCore { virtual FloatRect calculateEffectRect(Filter*); void apply(Filter*); void dump(); + TextStream& externalRepresentation(TextStream&, int indent) const; private: SourceAlpha() { } diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp index cc55618..a1864d6 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.cpp +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -67,6 +67,13 @@ void SourceGraphic::dump() { } +TextStream& SourceGraphic::externalRepresentation(TextStream& ts, int indent) const +{ + writeIndent(ts, indent); + ts << "[SourceGraphic]\n"; + return ts; +} + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h index 0c8095e..05238a2 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.h +++ b/WebCore/platform/graphics/filters/SourceGraphic.h @@ -39,6 +39,7 @@ namespace WebCore { virtual FloatRect calculateEffectRect(Filter*); void apply(Filter*); void dump(); + TextStream& externalRepresentation(TextStream&, int indent) const; private: SourceGraphic() { } diff --git a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp index 1d14b5a..75bf5e7 100644 --- a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp @@ -30,6 +30,6 @@ template <> void freeOwnedGPtr<GstElement>(GstElement* ptr) if (ptr) gst_object_unref(ptr); } -#endif } +#endif diff --git a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h index 7ea7d91..f5379b6 100644 --- a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h @@ -20,7 +20,6 @@ #ifndef _HAVE_WEBKIT_VIDEO_SINK_H #define _HAVE_WEBKIT_VIDEO_SINK_H -#include <cairo.h> #include <glib-object.h> #include <gst/video/gstvideosink.h> diff --git a/WebCore/platform/graphics/mac/ComplexTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp index efb92f8..61d5518 100644 --- a/WebCore/platform/graphics/mac/ComplexTextController.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -280,7 +280,7 @@ void ComplexTextController::collectComplexTextRuns() static inline bool shouldUseATSUIAPI() { enum TypeRenderingAPIToUse { UnInitialized, UseATSUI, UseCoreText }; - DEFINE_STATIC_LOCAL(TypeRenderingAPIToUse, apiToUse, (UnInitialized)); + static TypeRenderingAPIToUse apiToUse = UnInitialized; if (UNLIKELY(apiToUse == UnInitialized)) { if (&CTGetCoreTextVersion != 0 && CTGetCoreTextVersion() >= kCTVersionNumber10_6) diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp index af210df..3b3158f 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -33,16 +33,16 @@ #include "ImageBuffer.h" #include "NotImplemented.h" #include "WebGLActiveInfo.h" -#include "WebGLArray.h" +#include "ArrayBufferView.h" #include "WebGLBuffer.h" -#include "WebGLFloatArray.h" +#include "FloatArray.h" #include "WebGLFramebuffer.h" -#include "WebGLIntArray.h" +#include "Int32Array.h" #include "WebGLProgram.h" #include "WebGLRenderbuffer.h" #include "WebGLShader.h" #include "WebGLTexture.h" -#include "WebGLUnsignedByteArray.h" +#include "Uint8Array.h" #include <CoreGraphics/CGBitmapContext.h> #include <OpenGL/CGLRenderers.h> #include <OpenGL/gl.h> @@ -446,7 +446,7 @@ void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long ensureContext(m_contextObj); ::glBufferData(target, size, 0, usage); } -void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage) +void GraphicsContext3D::bufferData(unsigned long target, ArrayBufferView* array, unsigned long usage) { if (!array || !array->length()) return; @@ -455,7 +455,7 @@ void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsi ::glBufferData(target, array->byteLength(), array->baseAddress(), usage); } -void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array) +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, ArrayBufferView* array) { if (!array || !array->length()) return; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index c837b51..b49c52f 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -601,8 +601,10 @@ void MediaPlayerPrivate::prepareToPlay() PlatformMedia MediaPlayerPrivate::platformMedia() const { - PlatformMedia plaftformMedia = { m_qtMovie.get() }; - return plaftformMedia; + PlatformMedia pm; + pm.type = PlatformMedia::QTMovieType; + pm.media.qtMovie = m_qtMovie.get(); + return pm; } #if USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/openvg/ImageOpenVG.cpp b/WebCore/platform/graphics/openvg/ImageOpenVG.cpp new file mode 100644 index 0000000..4c1932a --- /dev/null +++ b/WebCore/platform/graphics/openvg/ImageOpenVG.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. 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 "Image.h" + +#include "AffineTransform.h" +#include "BitmapImage.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "ImageDecoder.h" +#include "ImageObserver.h" +#include "IntSize.h" +#include "NotImplemented.h" +#include "PainterOpenVG.h" +#include "SurfaceOpenVG.h" +#include "TiledImageOpenVG.h" +#include "VGUtils.h" + +#include <wtf/MathExtras.h> + +namespace WebCore { + +bool FrameData::clear(bool clearMetadata) +{ + if (clearMetadata) + m_haveMetadata = false; + + if (m_frame) { + delete m_frame; + m_frame = 0; + return true; + } + return false; +} + +BitmapImage::BitmapImage(TiledImageOpenVG* tiledImage, ImageObserver* observer) + : Image(observer) + , m_size(tiledImage->size()) + , m_currentFrame(0) + , m_frames(1) + , m_frameTimer(0) + , m_repetitionCount(cAnimationNone) + , m_repetitionCountStatus(Unknown) + , m_repetitionsComplete(0) + , m_desiredFrameStartTime(0) + , m_isSolidColor(false) + , m_checkedForSolidColor(false) + , m_animationFinished(false) + , m_allDataReceived(false) + , m_haveSize(true) + , m_sizeAvailable(true) + , m_hasUniformFrameSize(true) + , m_haveFrameCount(true) + , m_frameCount(1) +{ + initPlatformData(); + + ASSERT(m_size.width() > 0); + ASSERT(m_size.height() > 0); + + m_decodedSize = m_size.width() * m_size.height() * 4; + + m_frames[0].m_frame = tiledImage; + m_frames[0].m_hasAlpha = true; + m_frames[0].m_isComplete = true; + m_frames[0].m_haveMetadata = true; + checkForSolidColor(); +} + +void BitmapImage::checkForSolidColor() +{ + TiledImageOpenVG* tiledImage = 0; + + if (m_frameCount == 1 && m_size.width() == 1 && m_size.height() == 1) + tiledImage = nativeImageForCurrentFrame(); + + if (tiledImage) { + m_isSolidColor = true; + RGBA32 pixel; + vgGetImageSubData(tiledImage->tile(0, 0), &pixel, 0, VG_sARGB_8888, 0, 0, 1, 1); + ASSERT_VG_NO_ERROR(); + m_solidColor.setRGB(pixel); + } else + m_isSolidColor = false; + + m_checkedForSolidColor = true; +} + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) +static void adjustSourceRectForDownSampling(FloatRect& srcRect, const IntSize& origSize, const IntSize& scaledSize) +{ + // We assume down-sampling zoom rates in X direction and in Y direction are same. + if (origSize.width() == scaledSize.width()) + return; + + // Image has been down sampled. + double rate = static_cast<double>(scaledSize.width()) / origSize.width(); + double temp = srcRect.right() * rate; + srcRect.setX(srcRect.x() * rate); + srcRect.setWidth(temp - srcRect.x()); + temp = srcRect.bottom() * rate; + srcRect.setY(srcRect.y() * rate); + srcRect.setHeight(temp - srcRect.y()); +} +#endif + +void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) +{ + if (dst.isEmpty() || src.isEmpty()) + return; + + NativeImagePtr image = nativeImageForCurrentFrame(); + if (!image) + return; + + startAnimation(); + + if (mayFillWithSolidColor()) { + fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); + return; + } + + context->save(); + + // Set the compositing operation. + if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) + context->setCompositeOperation(CompositeCopy); + else + context->setCompositeOperation(op); + + FloatRect srcRectLocal(src); +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + adjustSourceRectForDownSampling(srcRectLocal, size(), image->size()); +#endif + + context->platformContext()->activePainter()->drawImage(image, dst, srcRectLocal); + context->restore(); + + if (imageObserver()) + imageObserver()->didDraw(this); +} + +void Image::drawPattern(GraphicsContext* context, const FloatRect& src, + const AffineTransform& patternTransformation, + const FloatPoint& phase, ColorSpace styleColorSpace, + CompositeOperator op, const FloatRect& dst) +{ + if (dst.isEmpty() || src.isEmpty()) + return; + + NativeImagePtr image = nativeImageForCurrentFrame(); + if (!image) + return; + + startAnimation(); + + if (mayFillWithSolidColor()) { + fillWithSolidColor(context, dst, solidColor(), styleColorSpace, op); + return; + } + + notImplemented(); + + if (imageObserver()) + imageObserver()->didDraw(this); +} + +PassRefPtr<Image> Image::loadPlatformResource(char const* name) +{ + notImplemented(); + return 0; +} + +} diff --git a/WebCore/platform/graphics/openvg/PainterOpenVG.cpp b/WebCore/platform/graphics/openvg/PainterOpenVG.cpp index 5842afd..7d60ca5 100644 --- a/WebCore/platform/graphics/openvg/PainterOpenVG.cpp +++ b/WebCore/platform/graphics/openvg/PainterOpenVG.cpp @@ -31,6 +31,7 @@ #include "NotImplemented.h" #include "PlatformPathOpenVG.h" #include "SurfaceOpenVG.h" +#include "TiledImageOpenVG.h" #include "VGUtils.h" #if PLATFORM(EGL) @@ -1085,6 +1086,49 @@ void PainterOpenVG::drawPolygon(size_t numPoints, const FloatPoint* points, VGbi ASSERT_VG_NO_ERROR(); } +void PainterOpenVG::drawImage(TiledImageOpenVG* tiledImage, const FloatRect& dst, const FloatRect& src) +{ + ASSERT(m_state); + m_surface->makeCurrent(); + + // If buffers can be larger than the maximum OpenVG image sizes, + // we split them into tiles. + IntRect drawnTiles = tiledImage->tilesInRect(src); + AffineTransform srcToDstTransformation = makeMapBetweenRects( + FloatRect(FloatPoint(0.0, 0.0), src.size()), dst); + srcToDstTransformation.translate(-src.x(), -src.y()); + + for (int yIndex = drawnTiles.y(); yIndex < drawnTiles.bottom(); ++yIndex) { + for (int xIndex = drawnTiles.x(); xIndex < drawnTiles.right(); ++xIndex) { + // The srcTile rectangle is an aligned tile cropped by the src rectangle. + FloatRect tile(tiledImage->tileRect(xIndex, yIndex)); + FloatRect srcTile = intersection(src, tile); + + save(); + + // If the image is drawn in full, all we need is the proper transformation + // in order to get it drawn at the right spot on the surface. + concatTransformation(AffineTransform(srcToDstTransformation).translate(tile.x(), tile.y())); + + // If only a part of the tile is drawn, we also need to clip the surface. + if (srcTile != tile) { + // Put boundaries relative to tile origin, as we already + // translated to (x, y) with the transformation matrix. + srcTile.move(-tile.x(), -tile.y()); + intersectClipRect(srcTile); + } + + VGImage image = tiledImage->tile(xIndex, yIndex); + if (image != VG_INVALID_HANDLE) { + vgDrawImage(image); + ASSERT_VG_NO_ERROR(); + } + + restore(); + } + } +} + #ifdef OPENVG_VERSION_1_1 void PainterOpenVG::drawText(VGFont vgFont, Vector<VGuint>& characters, VGfloat* adjustmentsX, VGfloat* adjustmentsY, const FloatPoint& point) { @@ -1137,6 +1181,48 @@ void PainterOpenVG::drawText(VGFont vgFont, Vector<VGuint>& characters, VGfloat* } #endif +TiledImageOpenVG* PainterOpenVG::asNewNativeImage(const IntRect& src, VGImageFormat format) +{ + ASSERT(m_state); + m_surface->sharedSurface()->makeCurrent(); + + const IntSize vgMaxImageSize(vgGeti(VG_MAX_IMAGE_WIDTH), vgGeti(VG_MAX_IMAGE_HEIGHT)); + ASSERT_VG_NO_ERROR(); + + const IntRect rect = intersection(src, IntRect(0, 0, m_surface->width(), m_surface->height())); + TiledImageOpenVG* tiledImage = new TiledImageOpenVG(rect.size(), vgMaxImageSize); + + const int numColumns = tiledImage->numColumns(); + const int numRows = tiledImage->numRows(); + + // Create the images as resources of the shared surface/context. + for (int yIndex = 0; yIndex < numRows; ++yIndex) { + for (int xIndex = 0; xIndex < numColumns; ++xIndex) { + IntRect tileRect = tiledImage->tileRect(xIndex, yIndex); + VGImage image = vgCreateImage(format, tileRect.width(), tileRect.height(), VG_IMAGE_QUALITY_FASTER); + ASSERT_VG_NO_ERROR(); + + tiledImage->setTile(xIndex, yIndex, image); + } + } + + // Fill the image contents with our own surface/context being current. + m_surface->makeCurrent(); + + for (int yIndex = 0; yIndex < numRows; ++yIndex) { + for (int xIndex = 0; xIndex < numColumns; ++xIndex) { + IntRect tileRect = tiledImage->tileRect(xIndex, yIndex); + + vgGetPixels(tiledImage->tile(xIndex, yIndex), 0, 0, + rect.x() + tileRect.x(), rect.y() + tileRect.y(), + tileRect.width(), tileRect.height()); + ASSERT_VG_NO_ERROR(); + } + } + + return tiledImage; +} + void PainterOpenVG::save(PainterOpenVG::SaveMode saveMode) { ASSERT(m_state); diff --git a/WebCore/platform/graphics/openvg/PainterOpenVG.h b/WebCore/platform/graphics/openvg/PainterOpenVG.h index 30cdf31..e4c6688 100644 --- a/WebCore/platform/graphics/openvg/PainterOpenVG.h +++ b/WebCore/platform/graphics/openvg/PainterOpenVG.h @@ -37,6 +37,7 @@ class IntRect; class IntSize; class Path; class SurfaceOpenVG; +class TiledImageOpenVG; struct PlatformPainterState; @@ -101,6 +102,7 @@ public: void drawArc(const IntRect& ellipseBounds, int startAngle, int angleSpan, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH)); void drawEllipse(const IntRect& bounds, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH)); void drawPolygon(size_t numPoints, const FloatPoint* points, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH)); + void drawImage(TiledImageOpenVG*, const FloatRect& dst, const FloatRect& src); #ifdef OPENVG_VERSION_1_1 void drawText(VGFont, Vector<VGuint>& characters, VGfloat* adjustmentsX, VGfloat* adjustmentsY, const FloatPoint&); #endif @@ -117,6 +119,8 @@ public: void intersectClipRect(const FloatRect&); void clipPath(const Path&, PainterOpenVG::ClipOperation, WindRule clipRule = RULE_NONZERO); + TiledImageOpenVG* asNewNativeImage(const IntRect& src, VGImageFormat); + void save(PainterOpenVG::SaveMode saveMode = CreateNewState); void restore(); diff --git a/WebCore/platform/graphics/openvg/TiledImageOpenVG.cpp b/WebCore/platform/graphics/openvg/TiledImageOpenVG.cpp new file mode 100644 index 0000000..64d94c9 --- /dev/null +++ b/WebCore/platform/graphics/openvg/TiledImageOpenVG.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. 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 "TiledImageOpenVG.h" + +#include "FloatRect.h" +#include "IntRect.h" +#include "VGUtils.h" + +namespace WebCore { + +TiledImageOpenVG::TiledImageOpenVG(const IntSize& size, const IntSize& tileSize) + : SharedResourceOpenVG() + , m_size(size) + , m_maxTileSize(tileSize) + , m_numColumns((m_size.width() - 1) / m_maxTileSize.width() + 1) + , m_tiles(((m_size.height() - 1) / m_maxTileSize.height() + 1) * m_numColumns, VG_INVALID_HANDLE) +{ +} + +TiledImageOpenVG::TiledImageOpenVG(const TiledImageOpenVG& other) + : SharedResourceOpenVG() + , m_size(other.m_size) + , m_maxTileSize(other.m_maxTileSize) + , m_numColumns(other.m_numColumns) + , m_tiles(other.m_tiles) +{ + detachTiles(); +} + +TiledImageOpenVG& TiledImageOpenVG::operator=(const TiledImageOpenVG& other) +{ + if (&other != this) { + destroyTiles(); + + m_size = other.m_size; + m_maxTileSize = other.m_maxTileSize; + m_numColumns = other.m_numColumns; + m_tiles = other.m_tiles; + + detachTiles(); + } + return *this; +} + +TiledImageOpenVG::~TiledImageOpenVG() +{ + destroyTiles(); +} + +int TiledImageOpenVG::numTiles() const +{ + return m_tiles.size(); +} + +int TiledImageOpenVG::numColumns() const +{ + return m_numColumns; +} + +int TiledImageOpenVG::numRows() const +{ + return m_tiles.size() / m_numColumns; +} + +void TiledImageOpenVG::setTile(int xIndex, int yIndex, VGImage image) +{ + ASSERT(xIndex < m_numColumns); + int i = (yIndex * m_numColumns) + xIndex; + ASSERT(i < m_tiles.size()); + m_tiles.at(i) = image; +} + +IntRect TiledImageOpenVG::tilesInRect(const FloatRect& rect) const +{ + int leftIndex = static_cast<int>(rect.x()) / m_maxTileSize.width(); + int topIndex = static_cast<int>(rect.y()) / m_maxTileSize.height(); + + if (leftIndex < 0) + leftIndex = 0; + if (topIndex < 0) + topIndex = 0; + + // Round rect edges up to get the outer pixel boundaries. + int rightIndex = (static_cast<int>(ceil(rect.right())) - 1) / m_maxTileSize.width(); + int bottomIndex = (static_cast<int>(ceil(rect.bottom())) - 1) / m_maxTileSize.height(); + int columns = (rightIndex - leftIndex) + 1; + int rows = (bottomIndex - topIndex) + 1; + + return IntRect(leftIndex, topIndex, + (columns <= m_numColumns) ? columns : m_numColumns, + (rows <= (m_tiles.size() / m_numColumns)) ? rows : (m_tiles.size() / m_numColumns)); +} + +VGImage TiledImageOpenVG::tile(int xIndex, int yIndex) const +{ + ASSERT(xIndex < m_numColumns); + int i = (yIndex * m_numColumns) + xIndex; + ASSERT(i < m_tiles.size()); + return m_tiles.at(i); +} + +IntRect TiledImageOpenVG::tileRect(int xIndex, int yIndex) const +{ + ASSERT(xIndex < m_numColumns); + ASSERT((yIndex * m_numColumns) + xIndex < m_tiles.size()); + + int x = xIndex * m_maxTileSize.width(); + int y = yIndex * m_maxTileSize.height(); + + return IntRect(x, y, + ((m_maxTileSize.width() < m_size.width() - x) ? m_maxTileSize.width() : (m_size.width() - x)), + ((m_maxTileSize.height() < m_size.height() - y) ? m_maxTileSize.height() : (m_size.height() - y))); +} + +void TiledImageOpenVG::detachTiles() +{ + makeSharedContextCurrent(); // because we create new images + + int numTiles = m_tiles.size(); + VGImage newTile, originalTile; + + for (int i = 0; i < numTiles; ++i) { + originalTile = m_tiles.at(i); + + if (originalTile == VG_INVALID_HANDLE) + continue; + + VGImageFormat format = (VGImageFormat) vgGetParameteri(originalTile, VG_IMAGE_FORMAT); + VGint width = vgGetParameteri(originalTile, VG_IMAGE_WIDTH); + VGint height = vgGetParameteri(originalTile, VG_IMAGE_HEIGHT); + ASSERT_VG_NO_ERROR(); + + newTile = vgCreateImage(format, width, height, VG_IMAGE_QUALITY_FASTER); + ASSERT_VG_NO_ERROR(); + + vgCopyImage(newTile, 0, 0, originalTile, 0, 0, width, height, VG_FALSE /* dither */); + ASSERT_VG_NO_ERROR(); + + m_tiles.at(i) = newTile; + } +} + +void TiledImageOpenVG::destroyTiles() +{ + makeCompatibleContextCurrent(); + + Vector<VGImage>::const_iterator it = m_tiles.begin(); + Vector<VGImage>::const_iterator end = m_tiles.end(); + + for (; it != end; ++it) { + if (*it != VG_INVALID_HANDLE) + vgDestroyImage(*it); + } + ASSERT_VG_NO_ERROR(); + + m_tiles.fill(VG_INVALID_HANDLE); +} + +} diff --git a/WebCore/platform/graphics/openvg/TiledImageOpenVG.h b/WebCore/platform/graphics/openvg/TiledImageOpenVG.h new file mode 100644 index 0000000..c8f55d2 --- /dev/null +++ b/WebCore/platform/graphics/openvg/TiledImageOpenVG.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. 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 TiledImageOpenVG_h +#define TiledImageOpenVG_h + +#include "IntRect.h" +#include "IntSize.h" +#include "SharedResourceOpenVG.h" + +#include <openvg.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class FloatRect; + +class TiledImageOpenVG : public SharedResourceOpenVG { +public: + TiledImageOpenVG(const IntSize& size, const IntSize& tileSize); + TiledImageOpenVG(const TiledImageOpenVG&); + ~TiledImageOpenVG(); + + TiledImageOpenVG& operator=(const TiledImageOpenVG&); + + const IntSize& size() const { return m_size; } + const IntSize& maxTileSize() const { return m_maxTileSize; } + + int numTiles() const; + int numColumns() const; + int numRows() const; + + IntRect tilesInRect(const FloatRect&) const; + + void setTile(int xIndex, int yIndex, VGImage); + VGImage tile(int xIndex, int yIndex) const; + IntRect tileRect(int xIndex, int yIndex) const; + +private: + void detachTiles(); + void destroyTiles(); + + IntSize m_size; + IntSize m_maxTileSize; + + int m_numColumns; + + Vector<VGImage> m_tiles; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/openvg/VGUtils.cpp b/WebCore/platform/graphics/openvg/VGUtils.cpp index ce9bcd2..2559aaf 100644 --- a/WebCore/platform/graphics/openvg/VGUtils.cpp +++ b/WebCore/platform/graphics/openvg/VGUtils.cpp @@ -120,4 +120,116 @@ FloatRect::operator VGRect() const return VGRect(*this); } +int VGUtils::bytesForImage(VGImageFormat format, VGint width, VGint height) +{ + return width * height * imageFormatBitsPerPixel(format) / 8; +} + +int VGUtils::bytesForImageScanline(VGImageFormat format, VGint width) +{ + int bits = width * imageFormatBitsPerPixel(format); + if (bits % 8 > 1) // If unaligned, round up to the next byte. + bits += 8 - (bits % 8); + + return bits / 8; +} + +int VGUtils::imageFormatBitsPerPixel(VGImageFormat format) +{ + switch (format) { + case VG_sRGBX_8888: + case VG_sRGBA_8888: + case VG_sRGBA_8888_PRE: + case VG_lRGBX_8888: + case VG_lRGBA_8888: + case VG_lRGBA_8888_PRE: + case VG_sXRGB_8888: + case VG_sARGB_8888: + case VG_sARGB_8888_PRE: + case VG_lXRGB_8888: + case VG_lARGB_8888: + case VG_lARGB_8888_PRE: + case VG_sBGRX_8888: + case VG_sBGRA_8888: + case VG_sBGRA_8888_PRE: + case VG_lBGRX_8888: + case VG_lBGRA_8888: + case VG_lBGRA_8888_PRE: + case VG_sXBGR_8888: + case VG_sABGR_8888: + case VG_sABGR_8888_PRE: + case VG_lXBGR_8888: + case VG_lABGR_8888: + case VG_lABGR_8888_PRE: + return 32; + + case VG_sRGB_565: + case VG_sRGBA_5551: + case VG_sRGBA_4444: + case VG_sARGB_1555: + case VG_sARGB_4444: + case VG_sBGR_565: + case VG_sBGRA_5551: + case VG_sBGRA_4444: + case VG_sABGR_1555: + case VG_sABGR_4444: + return 16; + + case VG_sL_8: + case VG_lL_8: + case VG_A_8: + return 8; + + case VG_A_4: + return 4; + + case VG_BW_1: + case VG_A_1: + return 1; + + default: // Will only happen when OpenVG extends the enum and we don't. + ASSERT(false); + return 0; + } +} + +#ifndef WTF_PLATFORM_BIG_ENDIAN +VGImageFormat VGUtils::endianAwareImageFormat(VGImageFormat bigEndianFormat) +{ + switch (bigEndianFormat) { + case VG_sRGBX_8888: return VG_sXBGR_8888; + case VG_sRGBA_8888: return VG_sABGR_8888; + case VG_sRGBA_8888_PRE: return VG_sABGR_8888_PRE; + case VG_lRGBX_8888: return VG_lXBGR_8888; + case VG_lRGBA_8888: return VG_lABGR_8888; + case VG_lRGBA_8888_PRE: return VG_lABGR_8888_PRE; + case VG_sXRGB_8888: return VG_sBGRX_8888; + case VG_sARGB_8888: return VG_sBGRA_8888; + case VG_sARGB_8888_PRE: return VG_sBGRA_8888_PRE; + case VG_lXRGB_8888: return VG_lBGRX_8888; + case VG_lARGB_8888: return VG_lBGRA_8888; + case VG_lARGB_8888_PRE: return VG_lBGRA_8888_PRE; + case VG_sBGRX_8888: return VG_sXRGB_8888; + case VG_sBGRA_8888: return VG_sARGB_8888; + case VG_sBGRA_8888_PRE: return VG_sARGB_8888_PRE; + case VG_lBGRX_8888: return VG_lXRGB_8888; + case VG_lBGRA_8888: return VG_lARGB_8888; + case VG_lBGRA_8888_PRE: return VG_lARGB_8888_PRE; + case VG_sXBGR_8888: return VG_sRGBX_8888; + case VG_sABGR_8888: return VG_sRGBA_8888; + case VG_sABGR_8888_PRE: return VG_sRGBA_8888_PRE; + case VG_lXBGR_8888: return VG_lRGBX_8888; + case VG_lABGR_8888: return VG_lRGBA_8888; + case VG_lABGR_8888_PRE: return VG_lRGBA_8888_PRE; + default: ASSERT(false); + return (VGImageFormat) 0; + } +} +#else +VGImageFormat VGUtils::endianAwareImageFormat(VGImageFormat bigEndianFormat) +{ + return bigEndianFormat; +} +#endif + } diff --git a/WebCore/platform/graphics/openvg/VGUtils.h b/WebCore/platform/graphics/openvg/VGUtils.h index 3a290cb..06d5fea 100644 --- a/WebCore/platform/graphics/openvg/VGUtils.h +++ b/WebCore/platform/graphics/openvg/VGUtils.h @@ -85,6 +85,31 @@ private: VGfloat m_data[4]; }; +class VGUtils { +public: + static int bytesForImage(VGImageFormat, VGint width, VGint height); + static int bytesForImageScanline(VGImageFormat, VGint width); + static int imageFormatBitsPerPixel(VGImageFormat); + + /** + * Return a flipped VGImageFormat if the platform is little endian + * (e.g. VG_ABGR_8888 for a given VG_RGBA_8888), or return the image format + * as is if the platform is big endian. + * + * OpenVG itself is indifferent to endianness, it will always work on a + * single machine word with the bytes going from left to right as specified + * in the image format, no matter which one of the bytes is most or least + * significant. + * + * However, if you interface with vgImageSubData()/vgGetImageSubData() + * using a byte array then you want to make sure the byte order is + * appropriate for the given platform (otherwise the byte indexes need + * to be swapped depending on endianness). So, use this function when + * interfacing with byte arrays, and don't use it otherwise. + */ + static VGImageFormat endianAwareImageFormat(VGImageFormat bigEndianFormat); +}; + } #endif diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 8dfb967..ad43908 100644 --- a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -28,17 +28,17 @@ #include "NotImplemented.h" #include "QWebPageClient.h" #include "WebGLActiveInfo.h" -#include "WebGLArray.h" +#include "ArrayBufferView.h" #include "WebGLBuffer.h" -#include "WebGLFloatArray.h" +#include "FloatArray.h" #include "WebGLFramebuffer.h" -#include "WebGLIntArray.h" +#include "Int32Array.h" #include "WebGLProgram.h" #include "WebGLRenderbuffer.h" #include "WebGLRenderingContext.h" #include "WebGLShader.h" #include "WebGLTexture.h" -#include "WebGLUnsignedByteArray.h" +#include "Uint8Array.h" #include <QAbstractScrollArea> #include <wtf/UnusedParam.h> #include <wtf/text/CString.h> @@ -671,7 +671,7 @@ void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long m_internal->bufferData(target, size, /* data */ 0, usage); } -void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage) +void GraphicsContext3D::bufferData(unsigned long target, ArrayBufferView* array, unsigned long usage) { if (!array || !array->length()) return; @@ -680,7 +680,7 @@ void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsi m_internal->bufferData(target, array->byteLength(), array->baseAddress(), usage); } -void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array) +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, ArrayBufferView* array) { if (!array || !array->length()) return; diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp index 86c01de..aac1164 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp @@ -364,14 +364,6 @@ void GraphicsLayerQtImpl::updateTransform() return; } - // Simplistic depth test - we stack the item behind its parent if its computed z is lower than the parent's computed z at the item's center point. - if (parent) { - const QPointF centerPointMappedToRoot = rootLayer()->mapFromItem(this, m_size.width() / 2, m_size.height() / 2); - setFlag(ItemStacksBehindParent, - m_transformRelativeToRootLayer.mapPoint(FloatPoint3D(centerPointMappedToRoot.x(), centerPointMappedToRoot.y(), 0)).z() < - parent->m_transformRelativeToRootLayer.mapPoint(FloatPoint3D(centerPointMappedToRoot.x(), centerPointMappedToRoot.y(), 0)).z()); - } - // The item is front-facing or backface-visibility is on. setVisible(true); @@ -629,8 +621,10 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform if (m_maskEffect) m_maskEffect.data()->update(); else if (m_changeMask & DisplayChange) { - // Recache now: all the content is ready and we don't want to wait until the paint event. - recache(m_pendingContent.regionToUpdate); + // Recache now: all the content is ready and we don't want to wait until the paint event. We only need to do this for HTML content, + // there's no point in caching directly composited content like images or solid rectangles. + if (m_pendingContent.contentType == HTMLContentType) + recache(m_pendingContent.regionToUpdate); update(m_pendingContent.regionToUpdate.boundingRect()); m_pendingContent.regionToUpdate = QRegion(); } diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index b1bfbdd..21ba934 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -346,10 +346,19 @@ void Image::drawPattern(GraphicsContext* context, if (resampling == RESAMPLE_AWESOME) { // Do nice resampling. - SkBitmap resampled = skia::ImageOperations::Resize(srcSubset, - skia::ImageOperations::RESIZE_LANCZOS3, - static_cast<int>(destBitmapWidth), - static_cast<int>(destBitmapHeight)); + SkBitmap resampled; + int width = static_cast<int>(destBitmapWidth); + int height = static_cast<int>(destBitmapHeight); + if (!srcRect.fLeft && !srcRect.fTop + && srcRect.fRight == bitmap->width() && srcRect.fBottom == bitmap->height() + && (bitmap->hasResizedBitmap(width, height) + || bitmap->shouldCacheResampling(width, height, width, height))) { + // resizedBitmap() caches resized image. + resampled = bitmap->resizedBitmap(width, height); + } else { + resampled = skia::ImageOperations::Resize(srcSubset, + skia::ImageOperations::RESIZE_LANCZOS3, width, height); + } shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); // Since we just resized the bitmap, we need to undo the scale set in diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp new file mode 100644 index 0000000..87625d3 --- /dev/null +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp @@ -0,0 +1,968 @@ +/* + * 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 "QTMovie.h" +#include "QTMovieTask.h" +#include "QTMovieVisualContext.h" +#include "ScrollView.h" +#include "SoftLinking.h" +#include "StringBuilder.h" +#include "StringHash.h" +#include "TimeRanges.h" +#include "Timer.h" +#include <Wininet.h> +#include <wtf/CurrentTime.h> +#include <wtf/HashSet.h> +#include <wtf/MainThread.h> +#include <wtf/MathExtras.h> +#include <wtf/StdLibExtras.h> + +#if USE(ACCELERATED_COMPOSITING) +#include "GraphicsLayerCACF.h" +#include "WKCACFLayer.h" +#endif + +using namespace std; + +const CFStringRef kMinQuartzCoreVersion = CFSTR("1.0.43.0"); +const CFStringRef kMinCoreVideoVersion = CFSTR("1.0.0.2"); + +namespace WebCore { + +SOFT_LINK_LIBRARY(Wininet) +SOFT_LINK(Wininet, InternetSetCookieExW, DWORD, WINAPI, (LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData, DWORD dwFlags, DWORD_PTR dwReserved), (lpszUrl, lpszCookieName, lpszCookieData, dwFlags, dwReserved)) + +// 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) +// Interface declaration for MediaPlayerPrivateQuickTimeVisualContext's GraphicsLayerClient aggregate +class MediaPlayerPrivateQuickTimeVisualContext::LayerClient : public GraphicsLayerClient { +public: + LayerClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {} + virtual ~LayerClient() { m_parent = 0; } + virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip); + virtual void notifyAnimationStarted(const GraphicsLayer*, double time) { } + virtual void notifySyncRequired(const GraphicsLayer*) { } + virtual bool showDebugBorders() const { return false; } + virtual bool showRepaintCounter() const { return false; } +private: + MediaPlayerPrivateQuickTimeVisualContext* m_parent; +}; +#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)) +#endif + , m_visualContextClient(new MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient(this)) +{ +} + +MediaPlayerPrivateQuickTimeVisualContext::~MediaPlayerPrivateQuickTimeVisualContext() +{ + tearDownVideoRendering(); + cancelCallOnMainThread(&VisualContextClient::retrieveCurrentImageProc, this); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::supportsFullscreen() const +{ + return true; +} + +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_qtVideoLayer ? m_qtVideoLayer->platformLayer() : 0; +} +#endif + +String MediaPlayerPrivateQuickTimeVisualContext::rfc2616DateStringFromTime(CFAbsoluteTime time) +{ + static const char* const dayStrings[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; + static const char* const monthStrings[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + static const CFStringRef dateFormatString = CFSTR("%s, %02d %s %04d %02d:%02d:%02d GMT"); + static CFTimeZoneRef gmtTimeZone; + if (!gmtTimeZone) + gmtTimeZone = CFTimeZoneCopyDefault(); + + CFGregorianDate dateValue = CFAbsoluteTimeGetGregorianDate(time, gmtTimeZone); + if (!CFGregorianDateIsValid(dateValue, kCFGregorianAllUnits)) + return String(); + + time = CFGregorianDateGetAbsoluteTime(dateValue, gmtTimeZone); + SInt32 day = CFAbsoluteTimeGetDayOfWeek(time, 0); + + RetainPtr<CFStringRef> dateCFString(AdoptCF, CFStringCreateWithFormat(0, 0, dateFormatString, dayStrings[day - 1], dateValue.day, + monthStrings[dateValue.month - 1], dateValue.year, dateValue.hour, dateValue.minute, (int)dateValue.second)); + return dateCFString.get(); +} + +static void addCookieParam(StringBuilder& cookieBuilder, const String& name, const String& value) +{ + if (name.isEmpty()) + return; + + // If this isn't the first parameter added, terminate the previous one. + if (cookieBuilder.length()) + cookieBuilder.append("; "); + + // Add parameter name, and value if there is one. + cookieBuilder.append(name); + if (!value.isEmpty()) { + cookieBuilder.append("="); + cookieBuilder.append(value); + } +} + +void MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime(const String& url) +{ + // WebCore loaded the page with the movie URL with CFNetwork but QuickTime will + // use WinINet to download the movie, so we need to copy any cookies needed to + // download the movie into WinInet before asking QuickTime to open it. + Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; + if (!frame || !frame->page() || !frame->page()->cookieEnabled()) + return; + + KURL movieURL = KURL(KURL(), url); + Vector<Cookie> documentCookies; + if (!getRawCookies(frame->document(), movieURL, documentCookies)) + return; + + for (size_t ndx = 0; ndx < documentCookies.size(); ndx++) { + const Cookie& cookie = documentCookies[ndx]; + + if (cookie.name.isEmpty()) + continue; + + // Build up the cookie string with as much information as we can get so WinINet + // knows what to do with it. + StringBuilder cookieBuilder; + addCookieParam(cookieBuilder, cookie.name, cookie.value); + addCookieParam(cookieBuilder, "path", cookie.path); + if (cookie.expires) + addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires)); + if (cookie.httpOnly) + addCookieParam(cookieBuilder, "httpOnly", String()); + cookieBuilder.append(";"); + + String cookieURL; + if (!cookie.domain.isEmpty()) { + StringBuilder urlBuilder; + + urlBuilder.append(movieURL.protocol()); + urlBuilder.append("://"); + if (cookie.domain[0] == '.') + urlBuilder.append(cookie.domain.substring(1)); + else + urlBuilder.append(cookie.domain); + if (cookie.path.length() > 1) + urlBuilder.append(cookie.path); + + cookieURL = urlBuilder.toString(); + } else + cookieURL = movieURL; + + InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0); + } +} + +void MediaPlayerPrivateQuickTimeVisualContext::load(const String& url) +{ + if (!QTMovie::initializeQuickTime()) { + // FIXME: is this the right error to return? + m_networkState = MediaPlayer::DecodeError; + m_player->networkStateChanged(); + return; + } + + // Initialize the task timer. + MediaPlayerPrivateTaskTimer::initialize(); + + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::HaveNothing) { + m_readyState = MediaPlayer::HaveNothing; + m_player->readyStateChanged(); + } + cancelSeek(); + + setUpCookiesForQuickTime(url); + + m_movie = adoptRef(new QTMovie(m_movieClient.get())); + m_movie->load(url.characters(), url.length(), m_player->preservesPitch()); + m_movie->setVolume(m_player->volume()); + + CFDictionaryRef options = QTMovieVisualContext::getCGImageOptions(); + m_visualContext = adoptRef(new QTMovieVisualContext(m_visualContextClient.get(), options)); +} + +void MediaPlayerPrivateQuickTimeVisualContext::play() +{ + if (!m_movie) + return; + m_startedPlaying = true; + + m_movie->play(); + m_visualContextTimer.startRepeating(1.0 / 30); +} + +void MediaPlayerPrivateQuickTimeVisualContext::pause() +{ + if (!m_movie) + return; + m_startedPlaying = false; + + m_movie->pause(); + m_visualContextTimer.stop(); +} + +float MediaPlayerPrivateQuickTimeVisualContext::duration() const +{ + if (!m_movie) + return 0; + return m_movie->duration(); +} + +float MediaPlayerPrivateQuickTimeVisualContext::currentTime() const +{ + if (!m_movie) + return 0; + return m_movie->currentTime(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::seek(float time) +{ + cancelSeek(); + + if (!m_movie) + return; + + if (time > duration()) + time = duration(); + + m_seekTo = time; + if (maxTimeLoaded() >= m_seekTo) + doSeek(); + else + m_seekTimer.start(0, 0.5f); +} + +void MediaPlayerPrivateQuickTimeVisualContext::doSeek() +{ + float oldRate = m_movie->rate(); + if (oldRate) + m_movie->setRate(0); + m_movie->setCurrentTime(m_seekTo); + float timeAfterSeek = currentTime(); + // restore playback only if not at end, othewise QTMovie will loop + if (oldRate && timeAfterSeek < duration()) + m_movie->setRate(oldRate); + cancelSeek(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::cancelSeek() +{ + m_seekTo = -1; + m_seekTimer.stop(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::seekTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*) +{ + if (!m_movie || !seeking() || currentTime() == m_seekTo) { + cancelSeek(); + updateStates(); + m_player->timeChanged(); + return; + } + + if (maxTimeLoaded() >= m_seekTo) + doSeek(); + else { + MediaPlayer::NetworkState state = networkState(); + if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) { + cancelSeek(); + updateStates(); + m_player->timeChanged(); + } + } +} + +bool MediaPlayerPrivateQuickTimeVisualContext::paused() const +{ + if (!m_movie) + return true; + return (!m_movie->rate()); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::seeking() const +{ + if (!m_movie) + return false; + return m_seekTo >= 0; +} + +IntSize MediaPlayerPrivateQuickTimeVisualContext::naturalSize() const +{ + if (!m_movie) + return IntSize(); + int width; + int height; + m_movie->getNaturalSize(width, height); + return IntSize(width, height); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::hasVideo() const +{ + if (!m_movie) + return false; + return m_movie->hasVideo(); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::hasAudio() const +{ + if (!m_movie) + return false; + return m_movie->hasAudio(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::setVolume(float volume) +{ + if (!m_movie) + return; + m_movie->setVolume(volume); +} + +void MediaPlayerPrivateQuickTimeVisualContext::setRate(float rate) +{ + if (!m_movie) + return; + + // Do not call setRate(...) unless we have started playing; otherwise + // QuickTime's VisualContext can get wedged waiting for a rate change + // call which will never come. + if (m_startedPlaying) + m_movie->setRate(rate); +} + +void MediaPlayerPrivateQuickTimeVisualContext::setPreservesPitch(bool preservesPitch) +{ + if (!m_movie) + return; + m_movie->setPreservesPitch(preservesPitch); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::hasClosedCaptions() const +{ + if (!m_movie) + return false; + return m_movie->hasClosedCaptions(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::setClosedCaptionsVisible(bool visible) +{ + if (!m_movie) + return; + m_movie->setClosedCaptionsVisible(visible); +} + +PassRefPtr<TimeRanges> MediaPlayerPrivateQuickTimeVisualContext::buffered() const +{ + RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + float loaded = maxTimeLoaded(); + // rtsp streams are not buffered + if (!m_isStreaming && loaded > 0) + timeRanges->add(0, loaded); + return timeRanges.release(); +} + +float MediaPlayerPrivateQuickTimeVisualContext::maxTimeSeekable() const +{ + // infinite duration means live stream + return !isfinite(duration()) ? 0 : maxTimeLoaded(); +} + +float MediaPlayerPrivateQuickTimeVisualContext::maxTimeLoaded() const +{ + if (!m_movie) + return 0; + return m_movie->maxTimeLoaded(); +} + +unsigned MediaPlayerPrivateQuickTimeVisualContext::bytesLoaded() const +{ + if (!m_movie) + return 0; + float dur = duration(); + float maxTime = maxTimeLoaded(); + if (!dur) + return 0; + return totalBytes() * maxTime / dur; +} + +unsigned MediaPlayerPrivateQuickTimeVisualContext::totalBytes() const +{ + if (!m_movie) + return 0; + return m_movie->dataSize(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::cancelLoad() +{ + if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) + return; + + tearDownVideoRendering(); + + // Cancel the load by destroying the movie. + m_movie.clear(); + + updateStates(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::updateStates() +{ + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + + long loadState = m_movie ? m_movie->loadState() : QTMovieLoadStateError; + + if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) { + m_movie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount); + if (m_player->inMediaDocument()) { + if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) { + // This is a type of media that we do not handle directly with a <video> + // element, eg. QuickTime VR, a movie with a sprite track, etc. Tell the + // MediaPlayerClient that we won't support it. + sawUnsupportedTracks(); + return; + } + } else if (!m_enabledTrackCount) + loadState = QTMovieLoadStateError; + } + + // "Loaded" is reserved for fully buffered movies, never the case when streaming + if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) { + m_networkState = MediaPlayer::Loaded; + m_readyState = MediaPlayer::HaveEnoughData; + } else if (loadState >= QTMovieLoadStatePlaythroughOK) { + m_readyState = MediaPlayer::HaveEnoughData; + } else if (loadState >= QTMovieLoadStatePlayable) { + // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967> + m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData; + } else if (loadState >= QTMovieLoadStateLoaded) { + m_readyState = MediaPlayer::HaveMetadata; + } else if (loadState > QTMovieLoadStateError) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveNothing; + } else { + if (m_player->inMediaDocument()) { + // Something went wrong in the loading of media within a standalone file. + // This can occur with chained ref movies that eventually resolve to a + // file we don't support. + sawUnsupportedTracks(); + return; + } + + float loaded = maxTimeLoaded(); + if (!loaded) + m_readyState = MediaPlayer::HaveNothing; + + if (!m_enabledTrackCount) + m_networkState = MediaPlayer::FormatError; + else { + // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692> + if (loaded > 0) + m_networkState = MediaPlayer::DecodeError; + else + m_readyState = MediaPlayer::HaveNothing; + } + } + + if (isReadyForRendering() && !hasSetUpVideoRendering()) + setUpVideoRendering(); + + if (seeking()) + m_readyState = MediaPlayer::HaveNothing; + + if (m_networkState != oldNetworkState) + m_player->networkStateChanged(); + if (m_readyState != oldReadyState) + m_player->readyStateChanged(); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::isReadyForRendering() const +{ + return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::sawUnsupportedTracks() +{ + m_movie->setDisabled(true); + m_hasUnsupportedTracks = true; + m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player); +} + +void MediaPlayerPrivateQuickTimeVisualContext::didEnd() +{ + if (m_hasUnsupportedTracks) + return; + + m_startedPlaying = false; + + updateStates(); + m_player->timeChanged(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::setSize(const IntSize& size) +{ + if (m_hasUnsupportedTracks || !m_movie || m_size == size) + return; + m_size = size; +} + +void MediaPlayerPrivateQuickTimeVisualContext::setVisible(bool visible) +{ + if (m_hasUnsupportedTracks || !m_movie || m_visible == visible) + return; + + m_visible = visible; + if (m_visible) { + if (isReadyForRendering()) + setUpVideoRendering(); + } else + tearDownVideoRendering(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::paint(GraphicsContext* p, const IntRect& r) +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_qtVideoLayer) + return; +#endif + + paintCompleted(*p, r); +} + +void MediaPlayerPrivateQuickTimeVisualContext::paintCompleted(GraphicsContext& context, const IntRect& rect) +{ + m_newFrameAvailable = false; +} + +void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::retrieveCurrentImageProc(void* refcon) +{ + static_cast<MediaPlayerPrivateQuickTimeVisualContext*>(refcon)->retrieveCurrentImage(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::imageAvailableForTime(const QTCVTimeStamp* timeStamp) +{ + // This call may come in on another thread, so marshall to the main thread first: + callOnMainThread(&retrieveCurrentImageProc, m_parent); + + // callOnMainThread must be paired with cancelCallOnMainThread in the destructor, + // in case this object is deleted before the main thread request is handled. +} + +void MediaPlayerPrivateQuickTimeVisualContext::visualContextTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*) +{ + retrieveCurrentImage(); +} + +static CFDictionaryRef QTCFDictionaryCreateWithDataCallback(CFAllocatorRef allocator, const UInt8* bytes, CFIndex length) +{ + CFDataRef data = CFDataCreateWithBytesNoCopy(allocator, bytes, length, 0); + if (!data) + return 0; + + return reinterpret_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(allocator, data, kCFPropertyListImmutable, 0)); +} + +static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer) +{ +#if USE(ACCELERATED_COMPOSITING) + CGDataProviderRef provider = 0; + CGColorSpaceRef colorSpace = 0; + CGImageRef image = 0; + + size_t bitsPerComponent = 0; + size_t bitsPerPixel = 0; + CGImageAlphaInfo alphaInfo = kCGImageAlphaNone; + + if (buffer.pixelFormatIs32BGRA()) { + bitsPerComponent = 8; + bitsPerPixel = 32; + alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little); + } else if (buffer.pixelFormatIs32ARGB()) { + bitsPerComponent = 8; + bitsPerPixel = 32; + alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big); + } else { + // All other pixel formats are currently unsupported: + ASSERT_NOT_REACHED(); + } + + CGDataProviderDirectAccessCallbacks callbacks = { + &QTPixelBuffer::dataProviderGetBytePointerCallback, + &QTPixelBuffer::dataProviderReleaseBytePointerCallback, + &QTPixelBuffer::dataProviderGetBytesAtPositionCallback, + &QTPixelBuffer::dataProviderReleaseInfoCallback, + }; + + // Colorspace should be device, so that Quartz does not have to do an extra render. + colorSpace = CGColorSpaceCreateDeviceRGB(); + require(colorSpace, Bail); + + provider = CGDataProviderCreateDirectAccess(buffer.pixelBufferRef(), buffer.dataSize(), &callbacks); + require(provider, Bail); + + // CGDataProvider does not retain the buffer, but it will release it later, so do an extra retain here: + QTPixelBuffer::retainCallback(buffer.pixelBufferRef()); + + image = CGImageCreate(buffer.width(), buffer.height(), bitsPerComponent, bitsPerPixel, buffer.bytesPerRow(), colorSpace, alphaInfo, provider, 0, false, kCGRenderingIntentDefault); + +Bail: + // Once the image is created we can release our reference to the provider and the colorspace, they are retained by the image + if (provider) + CGDataProviderRelease(provider); + if (colorSpace) + CGColorSpaceRelease(colorSpace); + + return image; +#else + return 0; +#endif +} + + +void MediaPlayerPrivateQuickTimeVisualContext::retrieveCurrentImage() +{ + if (!m_visualContext) + return; + +#if USE(ACCELERATED_COMPOSITING) + if (!m_qtVideoLayer) + return; + + QTPixelBuffer buffer = m_visualContext->imageForTime(0); + if (!buffer.pixelBufferRef()) + return; + + WKCACFLayer* layer = static_cast<WKCACFLayer*>(m_qtVideoLayer->platformLayer()); + + if (!buffer.lockBaseAddress()) { +#ifndef NDEBUG + // Debug QuickTime links against a non-Debug version of CoreFoundation, so the CFDictionary attached to the CVPixelBuffer cannot be directly passed on into the CAImageQueue without being converted to a non-Debug CFDictionary: + CFDictionaryRef attachments = QTCFDictionaryCreateCopyWithDataCallback(kCFAllocatorDefault, buffer.attachments(), &QTCFDictionaryCreateWithDataCallback); +#else + // However, this is unnecssesary in the non-Debug case: + CFDictionaryRef attachments = static_cast<CFDictionaryRef>(CFRetain(buffer.attachments())); +#endif + + CFTimeInterval imageTime = QTMovieVisualContext::currentHostTime(); + + CGImageRef image = CreateCGImageFromPixelBuffer(buffer); + layer->setContents(image); + CGImageRelease(image); + + if (attachments) + CFRelease(attachments); + + buffer.unlockBaseAddress(); + layer->rootLayer()->setNeedsRender(); + } + m_visualContext->task(); +#endif +} + +static HashSet<String> mimeTypeCache() +{ + DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ()); + static bool typeListInitialized = false; + + if (!typeListInitialized) { + unsigned count = QTMovie::countSupportedTypes(); + for (unsigned n = 0; n < count; n++) { + const UChar* character; + unsigned len; + QTMovie::getSupportedType(n, character, len); + if (len) + typeCache.add(String(character, len)); + } + + typeListInitialized = true; + } + + return typeCache; +} + +void MediaPlayerPrivateQuickTimeVisualContext::getSupportedTypes(HashSet<String>& types) +{ + types = mimeTypeCache(); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::isAvailable() +{ + return QTMovie::initializeQuickTime(); +} + +MediaPlayer::SupportsType MediaPlayerPrivateQuickTimeVisualContext::supportsType(const String& type, const String& codecs) +{ + // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an + // extended MIME type + return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported; +} + +void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieEnded(QTMovie* movie) +{ + if (m_parent->m_hasUnsupportedTracks) + return; + + m_parent->m_visualContextTimer.stop(); + + ASSERT(m_parent->m_movie.get() == movie); + m_parent->didEnd(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieLoadStateChanged(QTMovie* movie) +{ + if (m_parent->m_hasUnsupportedTracks) + return; + + ASSERT(m_parent->m_movie.get() == movie); + m_parent->updateStates(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieTimeChanged(QTMovie* movie) +{ + if (m_parent->m_hasUnsupportedTracks) + return; + + ASSERT(m_parent->m_movie.get() == movie); + m_parent->updateStates(); + m_parent->m_player->timeChanged(); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::hasSingleSecurityOrigin() const +{ + // We tell quicktime to disallow resources that come from different origins + // so we all media is single origin. + return true; +} + +MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::currentRenderingMode() const +{ + if (!m_movie) + return MediaRenderingNone; + +#if USE(ACCELERATED_COMPOSITING) + if (m_qtVideoLayer) + return MediaRenderingMovieLayer; +#endif + + return MediaRenderingSoftwareRenderer; +} + +MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::preferredRenderingMode() const +{ + if (!m_player->frameView() || !m_movie) + return MediaRenderingNone; + +#if USE(ACCELERATED_COMPOSITING) + if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player)) + return MediaRenderingMovieLayer; +#endif + + return MediaRenderingSoftwareRenderer; +} + +void MediaPlayerPrivateQuickTimeVisualContext::setUpVideoRendering() +{ + MediaRenderingMode currentMode = currentRenderingMode(); + MediaRenderingMode preferredMode = preferredRenderingMode(); + +#if !USE(ACCELERATED_COMPOSITING) + ASSERT(preferredMode != MediaRenderingMovieLayer); +#endif + + if (currentMode == preferredMode && currentMode != MediaRenderingNone) + return; + + if (currentMode != MediaRenderingNone) + tearDownVideoRendering(); + + if (preferredMode == MediaRenderingMovieLayer) + createLayerForMovie(); + +#if USE(ACCELERATED_COMPOSITING) + if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer) + m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player); +#endif + + m_visualContext->setMovie(m_movie.get()); +} + +void MediaPlayerPrivateQuickTimeVisualContext::tearDownVideoRendering() +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_qtVideoLayer) + destroyLayerForMovie(); +#endif + + m_visualContext->setMovie(0); +} + +bool MediaPlayerPrivateQuickTimeVisualContext::hasSetUpVideoRendering() const +{ +#if USE(ACCELERATED_COMPOSITING) + return m_qtVideoLayer || currentRenderingMode() != MediaRenderingMovieLayer; +#else + return true; +#endif +} + +void MediaPlayerPrivateQuickTimeVisualContext::createLayerForMovie() +{ +#if USE(ACCELERATED_COMPOSITING) + ASSERT(supportsAcceleratedRendering()); + + if (!m_movie || m_qtVideoLayer) + return; + + // Create a GraphicsLayer that won't be inserted directly into the render tree, but will used + // as a wrapper for a WKCACFLayer which gets inserted as the content layer of the video + // renderer's GraphicsLayer. + m_qtVideoLayer.set(new GraphicsLayerCACF(m_layerClient.get())); + if (!m_qtVideoLayer) + return; + + // Mark the layer as drawing itself, anchored in the top left, and bottom-up. + m_qtVideoLayer->setDrawsContent(true); + m_qtVideoLayer->setAnchorPoint(FloatPoint3D()); + m_qtVideoLayer->setContentsOrientation(GraphicsLayer::CompositingCoordinatesBottomUp); +#ifndef NDEBUG + m_qtVideoLayer->setName("Video layer"); +#endif + // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration(). +#endif +} + +void MediaPlayerPrivateQuickTimeVisualContext::destroyLayerForMovie() +{ +#if USE(ACCELERATED_COMPOSITING) + if (!m_qtVideoLayer) + return; + m_qtVideoLayer = 0; +#endif +} + +#if USE(ACCELERATED_COMPOSITING) +void MediaPlayerPrivateQuickTimeVisualContext::LayerClient::paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) +{ +} + +bool MediaPlayerPrivateQuickTimeVisualContext::supportsAcceleratedRendering() const +{ + return isReadyForRendering(); +} + +void MediaPlayerPrivateQuickTimeVisualContext::acceleratedRenderingStateChanged() +{ + // Set up or change the rendering path if necessary. + setUpVideoRendering(); +} + +#endif + + +} + +#endif diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h new file mode 100644 index 0000000..12166a3 --- /dev/null +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaPlayerPrivateQuickTimeVisualContext_h +#define MediaPlayerPrivateQuickTimeVisualContext_h + +#if ENABLE(VIDEO) + +#include "GraphicsLayer.h" +#include "MediaPlayerPrivate.h" +#include "Timer.h" +#include <wtf/OwnPtr.h> +#include <wtf/RetainPtr.h> + +#ifndef DRAW_FRAME_RATE +#define DRAW_FRAME_RATE 0 +#endif + +typedef struct CGImage *CGImageRef; +class QTMovie; +class QTMovieVisualContext; +class WKCAImageQueue; + +namespace WebCore { + +class GraphicsContext; +class IntSize; +class IntRect; +class String; + +class MediaPlayerPrivateQuickTimeVisualContext : public MediaPlayerPrivateInterface { +public: + static void registerMediaEngine(MediaEngineRegistrar); + + ~MediaPlayerPrivateQuickTimeVisualContext(); + +private: + MediaPlayerPrivateQuickTimeVisualContext(MediaPlayer*); + + virtual bool supportsFullscreen() const; + virtual PlatformMedia platformMedia() const; +#if USE(ACCELERATED_COMPOSITING) + PlatformLayer* platformLayer() const; +#endif + IntSize naturalSize() const; + bool hasVideo() const; + bool hasAudio() const; + + void load(const String& url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float time); + + void setRate(float); + void setVolume(float); + void setPreservesPitch(bool); + + MediaPlayer::NetworkState networkState() const { return m_networkState; } + MediaPlayer::ReadyState readyState() const { return m_readyState; } + + PassRefPtr<TimeRanges> buffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setSize(const IntSize&); + + void loadStateChanged(); + void didEnd(); + + void paint(GraphicsContext*, const IntRect&); + void paintCompleted(GraphicsContext&, const IntRect&); + + bool hasSingleSecurityOrigin() const; + + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); + + void updateStates(); + void doSeek(); + void cancelSeek(); + void seekTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*); + float maxTimeLoaded() const; + void sawUnsupportedTracks(); + + // engine support + static MediaPlayerPrivateInterface* create(MediaPlayer*); + static void getSupportedTypes(HashSet<String>& types); + static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); + static bool isAvailable(); + +#if USE(ACCELERATED_COMPOSITING) + virtual bool supportsAcceleratedRendering() const; + virtual void acceleratedRenderingStateChanged(); +#endif + + enum MediaRenderingMode { MediaRenderingNone, MediaRenderingSoftwareRenderer, MediaRenderingMovieLayer }; + MediaRenderingMode currentRenderingMode() const; + MediaRenderingMode preferredRenderingMode() const; + bool isReadyForRendering() const; + + void setUpVideoRendering(); + void tearDownVideoRendering(); + bool hasSetUpVideoRendering() const; + + void createLayerForMovie(); + void destroyLayerForMovie(); + + void setUpCookiesForQuickTime(const String& url); + String rfc2616DateStringFromTime(CFAbsoluteTime); + + void visualContextTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*); + void retrieveCurrentImage(); + + class MovieClient; + friend class MovieClient; + OwnPtr<MovieClient> m_movieClient; + +#if USE(ACCELERATED_COMPOSITING) + class LayerClient; + friend class LayerClient; + OwnPtr<LayerClient> m_layerClient; +#endif + + class VisualContextClient; + friend class VisualContextClient; + OwnPtr<VisualContextClient> m_visualContextClient; + + MediaPlayer* m_player; + RefPtr<QTMovie> m_movie; +#if USE(ACCELERATED_COMPOSITING) + OwnPtr<GraphicsLayer> m_qtVideoLayer; +#endif + RefPtr<QTMovieVisualContext> m_visualContext; + float m_seekTo; + Timer<MediaPlayerPrivateQuickTimeVisualContext> m_seekTimer; + Timer<MediaPlayerPrivateQuickTimeVisualContext> m_visualContextTimer; + IntSize m_size; + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + unsigned m_enabledTrackCount; + unsigned m_totalTrackCount; + bool m_hasUnsupportedTracks; + bool m_startedPlaying; + bool m_isStreaming; + bool m_visible; + bool m_newFrameAvailable; +#if DRAW_FRAME_RATE + double m_frameCountWhilePlaying; + double m_timeStartedPlaying; + double m_timeStoppedPlaying; +#endif +}; + +} + +#endif +#endif diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index c848eb3..69aaeaf 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -34,7 +34,8 @@ #include "FrameView.h" #include "GraphicsContext.h" #include "KURL.h" -#include "QTMovieWin.h" +#include "MediaPlayerPrivateTaskTimer.h" +#include "QTMovieTask.h" #include "ScrollView.h" #include "SoftLinking.h" #include "StringBuilder.h" @@ -53,10 +54,8 @@ #endif #if DRAW_FRAME_RATE -#include "Font.h" -#include "FrameView.h" -#include "Frame.h" #include "Document.h" +#include "Font.h" #include "RenderObject.h" #include "RenderStyle.h" #include "Windows.h" @@ -104,6 +103,7 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) MediaPlayerPrivate::~MediaPlayerPrivate() { tearDownVideoRendering(); + m_qtGWorld->setMovie(0); } bool MediaPlayerPrivate::supportsFullscreen() const @@ -114,7 +114,8 @@ bool MediaPlayerPrivate::supportsFullscreen() const PlatformMedia MediaPlayerPrivate::platformMedia() const { PlatformMedia p; - p.qtMovie = reinterpret_cast<QTMovie*>(m_qtMovie.get()); + p.type = PlatformMedia::QTMovieGWorldType; + p.media.qtMovieGWorld = m_qtGWorld.get(); return p; } @@ -125,50 +126,6 @@ PlatformLayer* MediaPlayerPrivate::platformLayer() const } #endif -class TaskTimer : TimerBase { -public: - static void initialize(); - -private: - static void setTaskTimerDelay(double); - static void stopTaskTimer(); - - void fired(); - - static TaskTimer* s_timer; -}; - -TaskTimer* TaskTimer::s_timer = 0; - -void TaskTimer::initialize() -{ - if (s_timer) - return; - - s_timer = new TaskTimer; - - QTMovieWin::setTaskTimerFuncs(setTaskTimerDelay, stopTaskTimer); -} - -void TaskTimer::setTaskTimerDelay(double delayInSeconds) -{ - ASSERT(s_timer); - - s_timer->startOneShot(delayInSeconds); -} - -void TaskTimer::stopTaskTimer() -{ - ASSERT(s_timer); - - s_timer->stop(); -} - -void TaskTimer::fired() -{ - QTMovieWin::taskTimerFired(); -} - String MediaPlayerPrivate::rfc2616DateStringFromTime(CFAbsoluteTime time) { static const char* const dayStrings[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; @@ -262,7 +219,7 @@ void MediaPlayerPrivate::setUpCookiesForQuickTime(const String& url) void MediaPlayerPrivate::load(const String& url) { - if (!QTMovieWin::initializeQuickTime()) { + if (!QTMovie::initializeQuickTime()) { // FIXME: is this the right error to return? m_networkState = MediaPlayer::DecodeError; m_player->networkStateChanged(); @@ -270,7 +227,7 @@ void MediaPlayerPrivate::load(const String& url) } // Initialize the task timer. - TaskTimer::initialize(); + MediaPlayerPrivateTaskTimer::initialize(); if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; @@ -284,10 +241,13 @@ void MediaPlayerPrivate::load(const String& url) setUpCookiesForQuickTime(url); - m_qtMovie.set(new QTMovieWin(this)); + m_qtMovie = adoptRef(new QTMovie(this)); m_qtMovie->load(url.characters(), url.length(), m_player->preservesPitch()); m_qtMovie->setVolume(m_player->volume()); - m_qtMovie->setVisible(m_player->visible()); + + m_qtGWorld = adoptRef(new QTMovieGWorld(this)); + m_qtGWorld->setMovie(m_qtMovie.get()); + m_qtGWorld->setVisible(m_player->visible()); } void MediaPlayerPrivate::play() @@ -388,7 +348,7 @@ bool MediaPlayerPrivate::paused() const { if (!m_qtMovie) return true; - return m_qtMovie->rate() == 0.0f; + return (!m_qtMovie->rate()); } bool MediaPlayerPrivate::seeking() const @@ -612,7 +572,7 @@ void MediaPlayerPrivate::setSize(const IntSize& size) if (m_hasUnsupportedTracks || !m_qtMovie || m_size == size) return; m_size = size; - m_qtMovie->setSize(size.width(), size.height()); + m_qtGWorld->setSize(size.width(), size.height()); } void MediaPlayerPrivate::setVisible(bool visible) @@ -620,7 +580,7 @@ void MediaPlayerPrivate::setVisible(bool visible) if (m_hasUnsupportedTracks || !m_qtMovie || m_visible == visible) return; - m_qtMovie->setVisible(visible); + m_qtGWorld->setVisible(visible); m_visible = visible; if (m_visible) { if (isReadyForRendering()) @@ -643,7 +603,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) HDC hdc = p->getWindowsContext(r); if (!hdc) { // The graphics context doesn't have an associated HDC so create a temporary - // bitmap where QTMovieWin can draw the frame and we can copy it. + // bitmap where QTMovieGWorld can draw the frame and we can copy it. usingTempBitmap = true; bitmap.set(p->createWindowsBitmap(r.size())); hdc = bitmap->hdc(); @@ -659,7 +619,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) SetWorldTransform(hdc, &xform); } - m_qtMovie->paint(hdc, r.x(), r.y()); + m_qtGWorld->paint(hdc, r.x(), r.y()); if (usingTempBitmap) p->drawWindowsBitmap(bitmap.get(), r.topLeft()); else @@ -719,11 +679,11 @@ static HashSet<String> mimeTypeCache() static bool typeListInitialized = false; if (!typeListInitialized) { - unsigned count = QTMovieWin::countSupportedTypes(); + unsigned count = QTMovie::countSupportedTypes(); for (unsigned n = 0; n < count; n++) { const UChar* character; unsigned len; - QTMovieWin::getSupportedType(n, character, len); + QTMovie::getSupportedType(n, character, len); if (len) typeCache.add(String(character, len)); } @@ -741,7 +701,7 @@ void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) bool MediaPlayerPrivate::isAvailable() { - return QTMovieWin::initializeQuickTime(); + return QTMovie::initializeQuickTime(); } MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) @@ -751,7 +711,7 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, c return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported; } -void MediaPlayerPrivate::movieEnded(QTMovieWin* movie) +void MediaPlayerPrivate::movieEnded(QTMovie* movie) { if (m_hasUnsupportedTracks) return; @@ -760,7 +720,7 @@ void MediaPlayerPrivate::movieEnded(QTMovieWin* movie) didEnd(); } -void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie) +void MediaPlayerPrivate::movieLoadStateChanged(QTMovie* movie) { if (m_hasUnsupportedTracks) return; @@ -769,7 +729,7 @@ void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie) updateStates(); } -void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie) +void MediaPlayerPrivate::movieTimeChanged(QTMovie* movie) { if (m_hasUnsupportedTracks) return; @@ -779,12 +739,12 @@ void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie) m_player->timeChanged(); } -void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie) +void MediaPlayerPrivate::movieNewImageAvailable(QTMovieGWorld* movie) { if (m_hasUnsupportedTracks) return; - ASSERT(m_qtMovie.get() == movie); + ASSERT(m_qtGWorld.get() == movie); #if DRAW_FRAME_RATE if (m_startedPlaying) { m_frameCountWhilePlaying++; @@ -900,9 +860,9 @@ void MediaPlayerPrivate::paintContents(const GraphicsLayer*, GraphicsContext& co unsigned width; unsigned height; - m_qtMovie->getCurrentFrameInfo(buffer, bitsPerPixel, rowBytes, width, height); + m_qtGWorld->getCurrentFrameInfo(buffer, bitsPerPixel, rowBytes, width, height); if (!buffer) - return ; + return; RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, static_cast<UInt8*>(buffer), rowBytes * height, kCFAllocatorNull)); RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index 9de5894..ecdb9da 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -23,14 +23,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MediaPlayerPrivateQTKit_h -#define MediaPlayerPrivateQTKit_h +#ifndef MediaPlayerPrivateQuickTimeWin_h +#define MediaPlayerPrivateQuickTimeWin_h #if ENABLE(VIDEO) #include "MediaPlayerPrivate.h" #include "Timer.h" -#include <QTMovieWin.h> +#include <QTMovie.h> +#include <QTMovieGWorld.h> #include <wtf/OwnPtr.h> #include <wtf/RetainPtr.h> @@ -51,7 +52,7 @@ class IntSize; class IntRect; class String; -class MediaPlayerPrivate : public MediaPlayerPrivateInterface, public QTMovieWinClient +class MediaPlayerPrivate : public MediaPlayerPrivateInterface, public QTMovieClient, public QTMovieGWorldClient #if USE(ACCELERATED_COMPOSITING) , public GraphicsLayerClient #endif @@ -130,10 +131,10 @@ private: float maxTimeLoaded() const; void sawUnsupportedTracks(); - virtual void movieEnded(QTMovieWin*); - virtual void movieLoadStateChanged(QTMovieWin*); - virtual void movieTimeChanged(QTMovieWin*); - virtual void movieNewImageAvailable(QTMovieWin*); + virtual void movieEnded(QTMovie*); + virtual void movieLoadStateChanged(QTMovie*); + virtual void movieTimeChanged(QTMovie*); + virtual void movieNewImageAvailable(QTMovieGWorld*); // engine support static MediaPlayerPrivateInterface* create(MediaPlayer*); @@ -162,7 +163,8 @@ private: String rfc2616DateStringFromTime(CFAbsoluteTime); MediaPlayer* m_player; - OwnPtr<QTMovieWin> m_qtMovie; + RefPtr<QTMovie> m_qtMovie; + RefPtr<QTMovieGWorld> m_qtGWorld; #if USE(ACCELERATED_COMPOSITING) OwnPtr<GraphicsLayer> m_qtVideoLayer; #endif diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp new file mode 100644 index 0000000..770e73e --- /dev/null +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "MediaPlayerPrivateTaskTimer.h" + +#include "QTMovieTask.h" + +namespace WebCore { + +MediaPlayerPrivateTaskTimer* MediaPlayerPrivateTaskTimer::s_timer = 0; + +void MediaPlayerPrivateTaskTimer::initialize() +{ + if (s_timer) + return; + + s_timer = new MediaPlayerPrivateTaskTimer; + + QTMovieTask::sharedTask()->setTaskTimerFuncs(setDelay, stopTaskTimer); +} + +void MediaPlayerPrivateTaskTimer::setDelay(double delayInSeconds) +{ + ASSERT(s_timer); + + s_timer->startOneShot(delayInSeconds); +} + +void MediaPlayerPrivateTaskTimer::stopTaskTimer() +{ + ASSERT(s_timer); + + s_timer->stop(); +} + +void MediaPlayerPrivateTaskTimer::fired() +{ + QTMovieTask::sharedTask()->fireTaskClients(); +} + +} diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h b/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h new file mode 100644 index 0000000..10f861e --- /dev/null +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateTaskTimer.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaPlayerPrivateTaskTimer_h +#define MediaPlayerPrivateTaskTimer_h + +#include "Timer.h" + +namespace WebCore { + +class MediaPlayerPrivateTaskTimer : TimerBase { +public: + static void initialize(); + +private: + static void setDelay(double); + static void stopTaskTimer(); + + void fired(); + + static MediaPlayerPrivateTaskTimer* s_timer; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/win/QTCFDictionary.cpp b/WebCore/platform/graphics/win/QTCFDictionary.cpp new file mode 100644 index 0000000..ada1500 --- /dev/null +++ b/WebCore/platform/graphics/win/QTCFDictionary.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "QTCFDictionary.h" + +#include <CFData.h> +#include <windows.h> + +CFDataRef QTCFPropertyListCreateXMLData(CFAllocatorRef allocator, CFPropertyListRef propertyList) +{ + + typedef CFDataRef (* pfnCFPropertyListCreateXMLData)(CFAllocatorRef allocator, CFPropertyListRef propertyList); + static pfnCFPropertyListCreateXMLData pCFPropertyListCreateXMLData = 0; + if (!pCFPropertyListCreateXMLData) { + HMODULE qtcfDLL = LoadLibraryW(L"QTCF.dll"); + if (qtcfDLL) + pCFPropertyListCreateXMLData = reinterpret_cast<pfnCFPropertyListCreateXMLData>(GetProcAddress(qtcfDLL, "QTCF_CFPropertyListCreateXMLData")); + } + + if (pCFPropertyListCreateXMLData) + return pCFPropertyListCreateXMLData(allocator, propertyList); + return 0; +} + +CFDictionaryRef QTCFDictionaryCreateCopyWithDataCallback(CFAllocatorRef allocator, CFDictionaryRef dictionary, QTCFDictonaryCreateFromDataCallback callback) +{ + ASSERT(dictionary); + ASSERT(callback); + + CFDataRef data = QTCFPropertyListCreateXMLData(kCFAllocatorDefault, dictionary); + CFDictionaryRef outputDictionary = callback(allocator, CFDataGetBytePtr(data), CFDataGetLength(data)); + if (data) + CFRelease(data); + + return outputDictionary; +} diff --git a/WebCore/platform/graphics/win/QTCFDictionary.h b/WebCore/platform/graphics/win/QTCFDictionary.h new file mode 100644 index 0000000..ff34328 --- /dev/null +++ b/WebCore/platform/graphics/win/QTCFDictionary.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QTCFDictionary_h +#define QTCFDictionary_h + +#ifdef QTMOVIEWIN_EXPORTS +#define QTMOVIEWIN_API __declspec(dllexport) +#else +#define QTMOVIEWIN_API __declspec(dllimport) +#endif + +#include <CoreFoundation/CFBase.h> + +typedef const struct __CFDictionary * CFDictionaryRef; +typedef const struct __CFAllocator * CFAllocatorRef; + +typedef CFDictionaryRef (* QTCFDictonaryCreateFromDataCallback)(CFAllocatorRef, const UInt8*, CFIndex); + +QTMOVIEWIN_API CFDictionaryRef QTCFDictionaryCreateCopyWithDataCallback(CFAllocatorRef, CFDictionaryRef, QTCFDictonaryCreateFromDataCallback); + +#endif diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovie.cpp index 4831062..032b446 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovie.cpp @@ -24,17 +24,15 @@ */ #include "config.h" -#include "QTMovieWin.h" - -// Put Movies.h first so build failures here point clearly to QuickTime -#include <Movies.h> +#include "QTMovie.h" +#include "QTMovieTask.h" #include "QTMovieWinTimer.h" #include <GXMath.h> +#include <Movies.h> #include <QTML.h> #include <QuickTimeComponents.h> #include <wtf/Assertions.h> -#include <wtf/HashSet.h> #include <wtf/Noncopyable.h> #include <wtf/Vector.h> @@ -47,7 +45,7 @@ static const long subTitleTrackType = 'sbtl'; static const long mpeg4ObjectDescriptionTrackType = 'odsm'; static const long mpeg4SceneDescriptionTrackType = 'sdsm'; static const long closedCaptionDisplayPropertyID = 'disp'; -static LPCTSTR fullscreenQTMovieWinPointerProp = TEXT("fullscreenQTMovieWinPointer"); +static LPCTSTR fullscreenQTMoviePointerProp = TEXT("fullscreenQTMoviePointer"); // Resizing GWorlds is slow, give them a minimum size so size of small // videos can be animated smoothly @@ -61,53 +59,26 @@ union UppParam { void* ptr; }; -static MovieDrawingCompleteUPP gMovieDrawingCompleteUPP = 0; -static HashSet<QTMovieWinPrivate*>* gTaskList; static Vector<CFStringRef>* gSupportedTypes = 0; static SInt32 quickTimeVersion = 0; -static QTMovieWin::SetTaskTimerDelayFunc gSetTaskTimerDelay = 0; -static QTMovieWin::StopTaskTimerFunc gStopTaskTimer = 0; - -static void updateTaskTimer(int maxInterval = 1000) -{ - if (!gTaskList->size()) { - gStopTaskTimer(); - return; - } - - long intervalInMS; - QTGetTimeUntilNextTask(&intervalInMS, 1000); - if (intervalInMS > maxInterval) - intervalInMS = maxInterval; - gSetTaskTimerDelay(static_cast<float>(intervalInMS) / 1000); -} - -class QTMovieWinPrivate : public Noncopyable { +class QTMoviePrivate : public Noncopyable, public QTMovieTaskClient { public: - QTMovieWinPrivate(); - ~QTMovieWinPrivate(); + QTMoviePrivate(); + ~QTMoviePrivate(); void task(); void startTask(); void endTask(); void createMovieController(); - void registerDrawingCallback(); - void drawingComplete(); - void updateGWorld(); - void createGWorld(); - void deleteGWorld(); - void clearGWorld(); void cacheMovieScale(); - void updateMovieSize(); - - void setSize(int, int); - QTMovieWin* m_movieWin; + QTMovie* m_movieWin; Movie m_movie; MovieController m_movieController; bool m_tasking; - QTMovieWinClient* m_client; + bool m_disabled; + Vector<QTMovieClient*> m_clients; long m_loadState; bool m_ended; bool m_seeking; @@ -116,10 +87,6 @@ public: int m_width; int m_height; bool m_visible; - GWorldPtr m_gWorld; - int m_gWorldWidth; - int m_gWorldHeight; - GWorldPtr m_savedGWorld; long m_loadError; float m_widthScaleFactor; float m_heightScaleFactor; @@ -129,19 +96,13 @@ public: #if !ASSERT_DISABLED bool m_scaleCached; #endif - WindowPtr m_fullscreenWindow; - GWorldPtr m_fullscreenOrigGWorld; - Rect m_fullscreenRect; - QTMovieWinFullscreenClient* m_fullscreenClient; - char* m_fullscreenRestoreState; }; -QTMovieWinPrivate::QTMovieWinPrivate() +QTMoviePrivate::QTMoviePrivate() : m_movieWin(0) , m_movie(0) , m_movieController(0) , m_tasking(false) - , m_client(0) , m_loadState(0) , m_ended(false) , m_seeking(false) @@ -150,35 +111,22 @@ QTMovieWinPrivate::QTMovieWinPrivate() , m_width(0) , m_height(0) , m_visible(false) - , m_gWorld(0) - , m_gWorldWidth(0) - , m_gWorldHeight(0) - , m_savedGWorld(0) , m_loadError(0) , m_widthScaleFactor(1) , m_heightScaleFactor(1) , m_currentURL(0) , m_timeToRestore(-1.0f) , m_rateToRestore(-1.0f) + , m_disabled(false) #if !ASSERT_DISABLED , m_scaleCached(false) #endif - , m_fullscreenWindow(0) - , m_fullscreenOrigGWorld(0) - , m_fullscreenClient(0) - , m_fullscreenRestoreState(0) { - Rect rect = { 0, 0, 0, 0 }; - m_fullscreenRect = rect; } -QTMovieWinPrivate::~QTMovieWinPrivate() +QTMoviePrivate::~QTMoviePrivate() { - ASSERT(!m_fullscreenWindow); - endTask(); - if (m_gWorld) - deleteGWorld(); if (m_movieController) DisposeMovieController(m_movieController); if (m_movie) @@ -187,59 +135,25 @@ QTMovieWinPrivate::~QTMovieWinPrivate() CFRelease(m_currentURL); } -void QTMovieWin::taskTimerFired() -{ - // The hash content might change during task() - Vector<QTMovieWinPrivate*> tasks; - copyToVector(*gTaskList, tasks); - size_t count = tasks.size(); - for (unsigned n = 0; n < count; ++n) - tasks[n]->task(); - - updateTaskTimer(); -} - -void QTMovieWinPrivate::startTask() -{ - if (m_tasking) - return; - if (!gTaskList) - gTaskList = new HashSet<QTMovieWinPrivate*>; - gTaskList->add(this); - m_tasking = true; - updateTaskTimer(); -} - -void QTMovieWinPrivate::endTask() +void QTMoviePrivate::startTask() { - if (!m_tasking) - return; - gTaskList->remove(this); - m_tasking = false; - updateTaskTimer(); + if (!m_tasking) { + QTMovieTask::sharedTask()->addTaskClient(this); + m_tasking = true; + } + QTMovieTask::sharedTask()->updateTaskTimer(); } -void QTMovieWinPrivate::cacheMovieScale() +void QTMoviePrivate::endTask() { - Rect naturalRect; - Rect initialRect; - - GetMovieNaturalBoundsRect(m_movie, &naturalRect); - GetMovieBox(m_movie, &initialRect); - - float naturalWidth = naturalRect.right - naturalRect.left; - float naturalHeight = naturalRect.bottom - naturalRect.top; - - if (naturalWidth) - m_widthScaleFactor = (initialRect.right - initialRect.left) / naturalWidth; - if (naturalHeight) - m_heightScaleFactor = (initialRect.bottom - initialRect.top) / naturalHeight; -#if !ASSERT_DISABLED - m_scaleCached = true;; -#endif + if (m_tasking) { + QTMovieTask::sharedTask()->removeTaskClient(this); + m_tasking = false; + } + QTMovieTask::sharedTask()->updateTaskTimer(); } -void QTMovieWinPrivate::task() +void QTMoviePrivate::task() { ASSERT(m_tasking); @@ -256,7 +170,6 @@ void QTMovieWinPrivate::task() // This is different from QTKit API and seems strange. long loadState = m_loadError ? QTMovieLoadStateError : GetMovieLoadState(m_movie); if (loadState != m_loadState) { - // we only need to erase the movie gworld when the load state changes to loaded while it // is visible as the gworld is destroyed/created when visibility changes bool shouldRestorePlaybackState = false; @@ -264,15 +177,14 @@ void QTMovieWinPrivate::task() m_loadState = loadState; if (movieNewlyPlayable) { cacheMovieScale(); - updateMovieSize(); - if (m_visible) - clearGWorld(); shouldRestorePlaybackState = true; } if (!m_movieController && m_loadState >= QTMovieLoadStateLoaded) createMovieController(); - m_client->movieLoadStateChanged(m_movieWin); + + for (size_t i = 0; i < m_clients.size(); ++i) + m_clients[i]->movieLoadStateChanged(m_movieWin); if (shouldRestorePlaybackState && m_timeToRestore != -1.0f) { m_movieWin->setCurrentTime(m_timeToRestore); @@ -281,7 +193,7 @@ void QTMovieWinPrivate::task() m_rateToRestore = -1.0f; } - if (m_movieWin->m_disabled) { + if (m_disabled) { endTask(); return; } @@ -292,23 +204,27 @@ void QTMovieWinPrivate::task() bool ended = !!IsMovieDone(m_movie); if (ended != m_ended) { m_ended = ended; - if (m_client && ended) - m_client->movieEnded(m_movieWin); + if (ended) { + for (size_t i = 0; i < m_clients.size(); ++i) + m_clients[i]->movieEnded(m_movieWin); + } } float time = m_movieWin->currentTime(); if (time < m_lastMediaTime || time >= m_lastMediaTime + cNonContinuousTimeChange || m_seeking) { m_seeking = false; - if (m_client) - m_client->movieTimeChanged(m_movieWin); + for (size_t i = 0; i < m_clients.size(); ++i) + m_clients[i]->movieTimeChanged(m_movieWin); } m_lastMediaTime = time; if (m_loadError) endTask(); + else + QTMovieTask::sharedTask()->updateTaskTimer(); } -void QTMovieWinPrivate::createMovieController() +void QTMoviePrivate::createMovieController() { Rect bounds; long flags; @@ -324,155 +240,56 @@ void QTMovieWinPrivate::createMovieController() m_movieController = NewMovieController(m_movie, &bounds, flags); if (!m_movieController) return; - - MCSetControllerPort(m_movieController, m_gWorld); - MCSetControllerAttached(m_movieController, false); } -void QTMovieWinPrivate::registerDrawingCallback() +void QTMoviePrivate::cacheMovieScale() { - UppParam param; - param.ptr = this; - SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, gMovieDrawingCompleteUPP, param.longValue); -} - -void QTMovieWinPrivate::drawingComplete() -{ - if (!m_gWorld || m_movieWin->m_disabled || m_loadState < QTMovieLoadStateLoaded) - return; - m_client->movieNewImageAvailable(m_movieWin); -} - -void QTMovieWinPrivate::updateGWorld() -{ - bool shouldBeVisible = m_visible; - if (!m_height || !m_width) - shouldBeVisible = false; - - if (shouldBeVisible && !m_gWorld) - createGWorld(); - else if (!shouldBeVisible && m_gWorld) - deleteGWorld(); - else if (m_gWorld && (m_width > m_gWorldWidth || m_height > m_gWorldHeight)) { - // need a bigger, better gWorld - deleteGWorld(); - createGWorld(); - } -} - -void QTMovieWinPrivate::createGWorld() -{ - ASSERT(!m_gWorld); - if (!m_movie || m_loadState < QTMovieLoadStateLoaded) - return; - - m_gWorldWidth = max(cGWorldMinWidth, m_width); - m_gWorldHeight = max(cGWorldMinHeight, m_height); - Rect bounds; - bounds.top = 0; - bounds.left = 0; - bounds.right = m_gWorldWidth; - bounds.bottom = m_gWorldHeight; - OSErr err = QTNewGWorld(&m_gWorld, k32BGRAPixelFormat, &bounds, 0, 0, 0); - if (err) - return; - GetMovieGWorld(m_movie, &m_savedGWorld, 0); - if (m_movieController) - MCSetControllerPort(m_movieController, m_gWorld); - SetMovieGWorld(m_movie, m_gWorld, 0); - bounds.right = m_width; - bounds.bottom = m_height; - if (m_movieController) - MCSetControllerBoundsRect(m_movieController, &bounds); - SetMovieBox(m_movie, &bounds); -} - -void QTMovieWinPrivate::clearGWorld() -{ - if (!m_movie||!m_gWorld) - return; - - GrafPtr savePort; - GetPort(&savePort); - MacSetPort((GrafPtr)m_gWorld); - - Rect bounds; - bounds.top = 0; - bounds.left = 0; - bounds.right = m_gWorldWidth; - bounds.bottom = m_gWorldHeight; - EraseRect(&bounds); - - MacSetPort(savePort); -} + Rect naturalRect; + Rect initialRect; -void QTMovieWinPrivate::setSize(int width, int height) -{ - if (m_width == width && m_height == height) - return; - m_width = width; - m_height = height; + GetMovieNaturalBoundsRect(m_movie, &naturalRect); + GetMovieBox(m_movie, &initialRect); - // Do not change movie box before reaching load state loaded as we grab - // the initial size when task() sees that state for the first time, and - // we need the initial size to be able to scale movie properly. - if (!m_movie || m_loadState < QTMovieLoadStateLoaded) - return; + float naturalWidth = naturalRect.right - naturalRect.left; + float naturalHeight = naturalRect.bottom - naturalRect.top; + if (naturalWidth) + m_widthScaleFactor = (initialRect.right - initialRect.left) / naturalWidth; + if (naturalHeight) + m_heightScaleFactor = (initialRect.bottom - initialRect.top) / naturalHeight; #if !ASSERT_DISABLED - ASSERT(m_scaleCached); + m_scaleCached = true; #endif - - updateMovieSize(); } -void QTMovieWinPrivate::updateMovieSize() +QTMovie::QTMovie(QTMovieClient* client) + : m_private(new QTMoviePrivate()) { - if (!m_movie || m_loadState < QTMovieLoadStateLoaded) - return; - - Rect bounds; - bounds.top = 0; - bounds.left = 0; - bounds.right = m_width; - bounds.bottom = m_height; - if (m_movieController) - MCSetControllerBoundsRect(m_movieController, &bounds); - SetMovieBox(m_movie, &bounds); - updateGWorld(); + m_private->m_movieWin = this; + if (client) + m_private->m_clients.append(client); + initializeQuickTime(); } - -void QTMovieWinPrivate::deleteGWorld() +QTMovie::~QTMovie() { - ASSERT(m_gWorld); - if (m_movieController) - MCSetControllerPort(m_movieController, m_savedGWorld); - if (m_movie) - SetMovieGWorld(m_movie, m_savedGWorld, 0); - m_savedGWorld = 0; - DisposeGWorld(m_gWorld); - m_gWorld = 0; - m_gWorldWidth = 0; - m_gWorldHeight = 0; + delete m_private; } - -QTMovieWin::QTMovieWin(QTMovieWinClient* client) - : m_private(new QTMovieWinPrivate()) - , m_disabled(false) +void QTMovie::addClient(QTMovieClient* client) { - m_private->m_movieWin = this; - m_private->m_client = client; - initializeQuickTime(); + if (client) + m_private->m_clients.append(client); } -QTMovieWin::~QTMovieWin() +void QTMovie::removeClient(QTMovieClient* client) { - delete m_private; + size_t indexOfClient = m_private->m_clients.find(client); + if (indexOfClient != notFound) + m_private->m_clients.remove(indexOfClient); } -void QTMovieWin::play() +void QTMovie::play() { m_private->m_timeToRestore = -1.0f; @@ -483,7 +300,7 @@ void QTMovieWin::play() m_private->startTask(); } -void QTMovieWin::pause() +void QTMovie::pause() { m_private->m_timeToRestore = -1.0f; @@ -491,17 +308,17 @@ void QTMovieWin::pause() MCDoAction(m_private->m_movieController, mcActionPlay, 0); else StopMovie(m_private->m_movie); - updateTaskTimer(); + QTMovieTask::sharedTask()->updateTaskTimer(); } -float QTMovieWin::rate() const +float QTMovie::rate() const { if (!m_private->m_movie) return 0; return FixedToFloat(GetMovieRate(m_private->m_movie)); } -void QTMovieWin::setRate(float rate) +void QTMovie::setRate(float rate) { if (!m_private->m_movie) return; @@ -511,10 +328,10 @@ void QTMovieWin::setRate(float rate) MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)FloatToFixed(rate)); else SetMovieRate(m_private->m_movie, FloatToFixed(rate)); - updateTaskTimer(); + QTMovieTask::sharedTask()->updateTaskTimer(); } -float QTMovieWin::duration() const +float QTMovie::duration() const { if (!m_private->m_movie) return 0; @@ -523,7 +340,7 @@ float QTMovieWin::duration() const return static_cast<float>(val) / scale; } -float QTMovieWin::currentTime() const +float QTMovie::currentTime() const { if (!m_private->m_movie) return 0; @@ -532,7 +349,7 @@ float QTMovieWin::currentTime() const return static_cast<float>(val) / scale; } -void QTMovieWin::setCurrentTime(float time) const +void QTMovie::setCurrentTime(float time) const { if (!m_private->m_movie) return; @@ -541,22 +358,22 @@ void QTMovieWin::setCurrentTime(float time) const m_private->m_seeking = true; TimeScale scale = GetMovieTimeScale(m_private->m_movie); - if (m_private->m_movieController){ + if (m_private->m_movieController) { QTRestartAtTimeRecord restart = { time * scale , 0 }; MCDoAction(m_private->m_movieController, mcActionRestartAtTime, (void *)&restart); } else SetMovieTimeValue(m_private->m_movie, TimeValue(time * scale)); - updateTaskTimer(); + QTMovieTask::sharedTask()->updateTaskTimer(); } -void QTMovieWin::setVolume(float volume) +void QTMovie::setVolume(float volume) { if (!m_private->m_movie) return; SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256)); } -void QTMovieWin::setPreservesPitch(bool preservesPitch) +void QTMovie::setPreservesPitch(bool preservesPitch) { if (!m_private->m_movie || !m_private->m_currentURL) return; @@ -575,14 +392,14 @@ void QTMovieWin::setPreservesPitch(bool preservesPitch) load(m_private->m_currentURL, preservesPitch); } -unsigned QTMovieWin::dataSize() const +unsigned QTMovie::dataSize() const { if (!m_private->m_movie) return 0; return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie)); } -float QTMovieWin::maxTimeLoaded() const +float QTMovie::maxTimeLoaded() const { if (!m_private->m_movie) return 0; @@ -592,12 +409,12 @@ float QTMovieWin::maxTimeLoaded() const return static_cast<float>(val) / scale; } -long QTMovieWin::loadState() const +long QTMovie::loadState() const { return m_private->m_loadState; } -void QTMovieWin::getNaturalSize(int& width, int& height) +void QTMovie::getNaturalSize(int& width, int& height) { Rect rect = { 0, }; @@ -607,56 +424,7 @@ void QTMovieWin::getNaturalSize(int& width, int& height) height = (rect.bottom - rect.top) * m_private->m_heightScaleFactor; } -void QTMovieWin::setSize(int width, int height) -{ - m_private->setSize(width, height); - updateTaskTimer(0); -} - -void QTMovieWin::setVisible(bool b) -{ - m_private->m_visible = b; - m_private->updateGWorld(); -} - -void QTMovieWin::getCurrentFrameInfo(void*& buffer, unsigned& bitsPerPixel, unsigned& rowBytes, unsigned& width, unsigned& height) -{ - if (!m_private->m_gWorld) { - buffer = 0; - bitsPerPixel = 0; - rowBytes = 0; - width = 0; - height = 0; - return; - } - PixMapHandle offscreenPixMap = GetGWorldPixMap(m_private->m_gWorld); - buffer = (*offscreenPixMap)->baseAddr; - bitsPerPixel = (*offscreenPixMap)->pixelSize; - rowBytes = (*offscreenPixMap)->rowBytes & 0x3FFF; - width = m_private->m_width; - height = m_private->m_height; -} - -void QTMovieWin::paint(HDC hdc, int x, int y) -{ - if (!m_private->m_gWorld) - return; - - HDC hdcSrc = static_cast<HDC>(GetPortHDC(reinterpret_cast<GrafPtr>(m_private->m_gWorld))); - if (!hdcSrc) - return; - - // FIXME: If we could determine the movie has no alpha, we could use BitBlt for those cases, which might be faster. - BLENDFUNCTION blendFunction; - blendFunction.BlendOp = AC_SRC_OVER; - blendFunction.BlendFlags = 0; - blendFunction.SourceConstantAlpha = 255; - blendFunction.AlphaFormat = AC_SRC_ALPHA; - AlphaBlend(hdc, x, y, m_private->m_width, m_private->m_height, hdcSrc, - 0, 0, m_private->m_width, m_private->m_height, blendFunction); -} - -void QTMovieWin::load(const UChar* url, int len, bool preservesPitch) +void QTMovie::load(const UChar* url, int len, bool preservesPitch) { CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len); CFURLRef cfURL = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0); @@ -667,15 +435,13 @@ void QTMovieWin::load(const UChar* url, int len, bool preservesPitch) CFRelease(urlStringRef); } -void QTMovieWin::load(CFURLRef url, bool preservesPitch) +void QTMovie::load(CFURLRef url, bool preservesPitch) { if (!url) return; if (m_private->m_movie) { m_private->endTask(); - if (m_private->m_gWorld) - m_private->deleteGWorld(); if (m_private->m_movieController) DisposeMovieController(m_private->m_movieController); m_private->m_movieController = 0; @@ -768,14 +534,14 @@ void QTMovieWin::load(CFURLRef url, bool preservesPitch) movieProps[moviePropCount].propStatus = 0; moviePropCount++; - ASSERT(moviePropCount <= sizeof(movieProps)/sizeof(movieProps[0])); + ASSERT(moviePropCount <= sizeof(movieProps) / sizeof(movieProps[0])); m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, 0, &m_private->m_movie); end: m_private->startTask(); // get the load fail callback quickly if (m_private->m_loadError) - updateTaskTimer(0); + QTMovieTask::sharedTask()->updateTaskTimer(0); else { OSType mode = kQTApertureMode_CleanAperture; @@ -784,11 +550,10 @@ end: // the installed version of QT doesn't support it and it isn't serious enough to // warrant failing. QTSetMovieProperty(m_private->m_movie, kQTPropertyClass_Visual, kQTVisualPropertyID_ApertureMode, sizeof(mode), &mode); - m_private->registerDrawingCallback(); } } -void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount) +void QTMovie::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount) { if (!m_private->m_movie) { totalTrackCount = 0; @@ -903,20 +668,25 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& } } -void QTMovieWin::setDisabled(bool b) +bool QTMovie::isDisabled() const +{ + return m_private->m_disabled; +} + +void QTMovie::setDisabled(bool b) { - m_disabled = b; + m_private->m_disabled = b; } -bool QTMovieWin::hasVideo() const +bool QTMovie::hasVideo() const { if (!m_private->m_movie) return false; return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)); } -bool QTMovieWin::hasAudio() const +bool QTMovie::hasAudio() const { if (!m_private->m_movie) return false; @@ -924,14 +694,14 @@ bool QTMovieWin::hasAudio() const } -bool QTMovieWin::hasClosedCaptions() const +bool QTMovie::hasClosedCaptions() const { if (!m_private->m_movie) return false; return GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType); } -void QTMovieWin::setClosedCaptionsVisible(bool visible) +void QTMovie::setClosedCaptionsVisible(bool visible) { if (!m_private->m_movie) return; @@ -944,16 +714,6 @@ void QTMovieWin::setClosedCaptionsVisible(bool visible) QTSetTrackProperty(ccTrack, closedCaptionTrackType, closedCaptionDisplayPropertyID, sizeof(doDisplay), &doDisplay); } -pascal OSErr movieDrawingCompleteProc(Movie movie, long data) -{ - UppParam param; - param.longValue = data; - QTMovieWinPrivate* mp = static_cast<QTMovieWinPrivate*>(param.ptr); - if (mp) - mp->drawingComplete(); - return 0; -} - static void initializeSupportedTypes() { if (gSupportedTypes) @@ -1043,13 +803,13 @@ static void initializeSupportedTypes() } } -unsigned QTMovieWin::countSupportedTypes() +unsigned QTMovie::countSupportedTypes() { initializeSupportedTypes(); return static_cast<unsigned>(gSupportedTypes->size()); } -void QTMovieWin::getSupportedType(unsigned index, const UChar*& str, unsigned& len) +void QTMovie::getSupportedType(unsigned index, const UChar*& str, unsigned& len) { initializeSupportedTypes(); ASSERT(index < gSupportedTypes->size()); @@ -1067,13 +827,7 @@ void QTMovieWin::getSupportedType(unsigned index, const UChar*& str, unsigned& l } -void QTMovieWin::setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer) -{ - gSetTaskTimerDelay = setTaskTimerDelay; - gStopTaskTimer = stopTaskTimer; -} - -bool QTMovieWin::initializeQuickTime() +bool QTMovie::initializeQuickTime() { static bool initialized = false; static bool initializationSucceeded = false; @@ -1092,75 +846,14 @@ bool QTMovieWin::initializeQuickTime() return false; } EnterMovies(); - gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc); initializationSucceeded = true; } return initializationSucceeded; } -LRESULT QTMovieWin::fullscreenWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - QTMovieWin* movie = static_cast<QTMovieWin*>(GetProp(wnd, fullscreenQTMovieWinPointerProp)); - - if (message == WM_DESTROY) - RemoveProp(wnd, fullscreenQTMovieWinPointerProp); - - if (!movie) - return DefWindowProc(wnd, message, wParam, lParam); - - return movie->m_private->m_fullscreenClient->fullscreenClientWndProc(wnd, message, wParam, lParam); -} - -HWND QTMovieWin::enterFullscreen(QTMovieWinFullscreenClient* client) -{ - m_private->m_fullscreenClient = client; - - BeginFullScreen(&m_private->m_fullscreenRestoreState, 0, 0, 0, &m_private->m_fullscreenWindow, 0, fullScreenAllowEvents); - QTMLSetWindowWndProc(m_private->m_fullscreenWindow, fullscreenWndProc); - CreatePortAssociation(GetPortNativeWindow(m_private->m_fullscreenWindow), 0, 0); - - GetMovieBox(m_private->m_movie, &m_private->m_fullscreenRect); - GetMovieGWorld(m_private->m_movie, &m_private->m_fullscreenOrigGWorld, 0); - SetMovieGWorld(m_private->m_movie, reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow), GetGWorldDevice(reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow))); - - // Set the size of the box to preserve aspect ratio - Rect rect = m_private->m_fullscreenWindow->portRect; - - float movieRatio = static_cast<float>(m_private->m_width) / m_private->m_height; - int windowWidth = rect.right - rect.left; - int windowHeight = rect.bottom - rect.top; - float windowRatio = static_cast<float>(windowWidth) / windowHeight; - int actualWidth = (windowRatio > movieRatio) ? (windowHeight * movieRatio) : windowWidth; - int actualHeight = (windowRatio < movieRatio) ? (windowWidth / movieRatio) : windowHeight; - int offsetX = (windowWidth - actualWidth) / 2; - int offsetY = (windowHeight - actualHeight) / 2; - - rect.left = offsetX; - rect.right = offsetX + actualWidth; - rect.top = offsetY; - rect.bottom = offsetY + actualHeight; - - SetMovieBox(m_private->m_movie, &rect); - ShowHideTaskBar(true); - - // Set the 'this' pointer on the HWND - HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow)); - SetProp(wnd, fullscreenQTMovieWinPointerProp, static_cast<HANDLE>(this)); - - return wnd; -} - -void QTMovieWin::exitFullscreen() +Movie QTMovie::getMovieHandle() const { - if (!m_private->m_fullscreenWindow) - return; - - HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow)); - DestroyPortAssociation(reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow)); - SetMovieGWorld(m_private->m_movie, m_private->m_fullscreenOrigGWorld, 0); - EndFullScreen(m_private->m_fullscreenRestoreState, 0L); - SetMovieBox(m_private->m_movie, &m_private->m_fullscreenRect); - m_private->m_fullscreenWindow = 0; + return m_private->m_movie; } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovie.h index d2a7ed0..8fa4b6e 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.h +++ b/WebCore/platform/graphics/win/QTMovie.h @@ -23,11 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef QTMovieWin_h -#define QTMovieWin_h +#ifndef QTMovie_h +#define QTMovie_h #include <Unicode.h> #include <windows.h> +#include <wtf/RefCounted.h> #ifdef QTMOVIEWIN_EXPORTS #define QTMOVIEWIN_API __declspec(dllexport) @@ -35,20 +36,15 @@ #define QTMOVIEWIN_API __declspec(dllimport) #endif -class QTMovieWin; -class QTMovieWinPrivate; +class QTMovie; +class QTMoviePrivate; +typedef struct MovieType** Movie; -class QTMovieWinClient { +class QTMovieClient { public: - virtual void movieEnded(QTMovieWin*) = 0; - virtual void movieLoadStateChanged(QTMovieWin*) = 0; - virtual void movieTimeChanged(QTMovieWin*) = 0; - virtual void movieNewImageAvailable(QTMovieWin*) = 0; -}; - -class QTMovieWinFullscreenClient { -public: - virtual LRESULT fullscreenClientWndProc(HWND, UINT message, WPARAM, LPARAM) = 0; + virtual void movieEnded(QTMovie*) = 0; + virtual void movieLoadStateChanged(QTMovie*) = 0; + virtual void movieTimeChanged(QTMovie*) = 0; }; enum { @@ -61,19 +57,20 @@ enum { typedef const struct __CFURL * CFURLRef; -class QTMOVIEWIN_API QTMovieWin { +class QTMOVIEWIN_API QTMovie : public RefCounted<QTMovie> { public: static bool initializeQuickTime(); - - typedef void (*SetTaskTimerDelayFunc)(double); - typedef void (*StopTaskTimerFunc)(); - static void setTaskTimerFuncs(SetTaskTimerDelayFunc, StopTaskTimerFunc); static void taskTimerFired(); - QTMovieWin(QTMovieWinClient*); - ~QTMovieWin(); + QTMovie(QTMovieClient*); + ~QTMovie(); + + void addClient(QTMovieClient*); + void removeClient(QTMovieClient*); void load(const UChar* url, int len, bool preservesPitch); + void load(CFURLRef, bool preservesPitch); + long loadState() const; float maxTimeLoaded() const; @@ -93,13 +90,10 @@ public: unsigned dataSize() const; void getNaturalSize(int& width, int& height); - void setSize(int width, int height); - - void setVisible(bool); - void paint(HDC, int x, int y); - void getCurrentFrameInfo(void*& buffer, unsigned& bitsPerPixel, unsigned& rowBytes, unsigned& width, unsigned& height); void disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount); + + bool isDisabled() const; void setDisabled(bool); bool hasVideo() const; @@ -111,17 +105,11 @@ public: static unsigned countSupportedTypes(); static void getSupportedType(unsigned index, const UChar*& str, unsigned& len); - // Returns the full-screen window created - HWND enterFullscreen(QTMovieWinFullscreenClient*); - void exitFullscreen(); + Movie getMovieHandle() const; private: - void load(CFURLRef, bool preservesPitch); - static LRESULT fullscreenWndProc(HWND, UINT message, WPARAM, LPARAM); - - QTMovieWinPrivate* m_private; - bool m_disabled; - friend class QTMovieWinPrivate; + QTMoviePrivate* m_private; + friend class QTMoviePrivate; }; #endif diff --git a/WebCore/platform/graphics/win/QTMovieGWorld.cpp b/WebCore/platform/graphics/win/QTMovieGWorld.cpp new file mode 100644 index 0000000..e13f732 --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieGWorld.cpp @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include "QTMovieGWorld.h" + +#include "QTMovieTask.h" +#include <GXMath.h> +#include <Movies.h> +#include <QTML.h> +#include <QuickTimeComponents.h> +#include <wtf/Assertions.h> +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +using namespace std; + +static const long minimumQuickTimeVersion = 0x07300000; // 7.3 + +static LPCTSTR fullscreenQTMovieGWorldPointerProp = TEXT("fullscreenQTMovieGWorldPointer"); + +// Resizing GWorlds is slow, give them a minimum size so size of small +// videos can be animated smoothly +static const int cGWorldMinWidth = 640; +static const int cGWorldMinHeight = 360; + +static const float cNonContinuousTimeChange = 0.2f; + +union UppParam { + long longValue; + void* ptr; +}; + +static MovieDrawingCompleteUPP gMovieDrawingCompleteUPP = 0; +static HashSet<QTMovieGWorldPrivate*>* gTaskList; +static Vector<CFStringRef>* gSupportedTypes = 0; +static SInt32 quickTimeVersion = 0; + +class QTMovieGWorldPrivate : public QTMovieClient { +public: + QTMovieGWorldPrivate(QTMovieGWorld* movieWin); + virtual ~QTMovieGWorldPrivate(); + + void registerDrawingCallback(); + void unregisterDrawingCallback(); + void drawingComplete(); + void updateGWorld(); + void createGWorld(); + void deleteGWorld(); + void clearGWorld(); + void updateMovieSize(); + + void setSize(int, int); + + virtual void movieEnded(QTMovie*); + virtual void movieLoadStateChanged(QTMovie*); + virtual void movieTimeChanged(QTMovie*); + + QTMovieGWorld* m_movieWin; + RefPtr<QTMovie> m_qtMovie; + Movie m_movie; + QTMovieGWorldClient* m_client; + long m_loadState; + int m_width; + int m_height; + bool m_visible; + GWorldPtr m_gWorld; + int m_gWorldWidth; + int m_gWorldHeight; + GWorldPtr m_savedGWorld; + float m_widthScaleFactor; + float m_heightScaleFactor; +#if !ASSERT_DISABLED + bool m_scaleCached; +#endif + WindowPtr m_fullscreenWindow; + GWorldPtr m_fullscreenOrigGWorld; + Rect m_fullscreenRect; + QTMovieGWorldFullscreenClient* m_fullscreenClient; + char* m_fullscreenRestoreState; + bool m_disabled; +}; + +QTMovieGWorldPrivate::QTMovieGWorldPrivate(QTMovieGWorld* movieWin) + : m_movieWin(movieWin) + , m_movie(0) + , m_client(0) + , m_loadState(0) + , m_width(0) + , m_height(0) + , m_visible(false) + , m_gWorld(0) + , m_gWorldWidth(0) + , m_gWorldHeight(0) + , m_savedGWorld(0) + , m_widthScaleFactor(1) + , m_heightScaleFactor(1) +#if !ASSERT_DISABLED + , m_scaleCached(false) +#endif + , m_fullscreenWindow(0) + , m_fullscreenOrigGWorld(0) + , m_fullscreenClient(0) + , m_fullscreenRestoreState(0) + , m_disabled(false) + , m_qtMovie(0) +{ + Rect rect = { 0, 0, 0, 0 }; + m_fullscreenRect = rect; +} + +QTMovieGWorldPrivate::~QTMovieGWorldPrivate() +{ + ASSERT(!m_fullscreenWindow); + + if (m_gWorld) + deleteGWorld(); +} + +pascal OSErr movieDrawingCompleteProc(Movie movie, long data) +{ + UppParam param; + param.longValue = data; + QTMovieGWorldPrivate* mp = static_cast<QTMovieGWorldPrivate*>(param.ptr); + if (mp) + mp->drawingComplete(); + return 0; +} + +void QTMovieGWorldPrivate::registerDrawingCallback() +{ + if (!gMovieDrawingCompleteUPP) + gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc); + + UppParam param; + param.ptr = this; + SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, gMovieDrawingCompleteUPP, param.longValue); +} + +void QTMovieGWorldPrivate::unregisterDrawingCallback() +{ + SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, 0, 0); +} + +void QTMovieGWorldPrivate::drawingComplete() +{ + if (!m_gWorld || m_movieWin->m_private->m_disabled || m_loadState < QTMovieLoadStateLoaded) + return; + m_client->movieNewImageAvailable(m_movieWin); +} + +void QTMovieGWorldPrivate::updateGWorld() +{ + bool shouldBeVisible = m_visible; + if (!m_height || !m_width) + shouldBeVisible = false; + + if (shouldBeVisible && !m_gWorld) + createGWorld(); + else if (!shouldBeVisible && m_gWorld) + deleteGWorld(); + else if (m_gWorld && (m_width > m_gWorldWidth || m_height > m_gWorldHeight)) { + // need a bigger, better gWorld + deleteGWorld(); + createGWorld(); + } +} + +void QTMovieGWorldPrivate::createGWorld() +{ + ASSERT(!m_gWorld); + if (!m_movie || m_loadState < QTMovieLoadStateLoaded) + return; + + m_gWorldWidth = max(cGWorldMinWidth, m_width); + m_gWorldHeight = max(cGWorldMinHeight, m_height); + Rect bounds; + bounds.top = 0; + bounds.left = 0; + bounds.right = m_gWorldWidth; + bounds.bottom = m_gWorldHeight; + OSErr err = QTNewGWorld(&m_gWorld, k32BGRAPixelFormat, &bounds, 0, 0, 0); + if (err) + return; + GetMovieGWorld(m_movie, &m_savedGWorld, 0); + SetMovieGWorld(m_movie, m_gWorld, 0); + bounds.right = m_width; + bounds.bottom = m_height; + SetMovieBox(m_movie, &bounds); +} + +void QTMovieGWorldPrivate::clearGWorld() +{ + if (!m_movie || !m_gWorld) + return; + + GrafPtr savePort; + GetPort(&savePort); + MacSetPort((GrafPtr)m_gWorld); + + Rect bounds; + bounds.top = 0; + bounds.left = 0; + bounds.right = m_gWorldWidth; + bounds.bottom = m_gWorldHeight; + EraseRect(&bounds); + + MacSetPort(savePort); +} + +void QTMovieGWorldPrivate::setSize(int width, int height) +{ + if (m_width == width && m_height == height) + return; + m_width = width; + m_height = height; + + // Do not change movie box before reaching load state loaded as we grab + // the initial size when task() sees that state for the first time, and + // we need the initial size to be able to scale movie properly. + if (!m_movie || m_loadState < QTMovieLoadStateLoaded) + return; + +#if !ASSERT_DISABLED + ASSERT(m_scaleCached); +#endif + + updateMovieSize(); +} + +void QTMovieGWorldPrivate::updateMovieSize() +{ + if (!m_movie || m_loadState < QTMovieLoadStateLoaded) + return; + + Rect bounds; + bounds.top = 0; + bounds.left = 0; + bounds.right = m_width; + bounds.bottom = m_height; + SetMovieBox(m_movie, &bounds); + updateGWorld(); +} + + +void QTMovieGWorldPrivate::deleteGWorld() +{ + ASSERT(m_gWorld); + if (m_movie) + SetMovieGWorld(m_movie, m_savedGWorld, 0); + m_savedGWorld = 0; + DisposeGWorld(m_gWorld); + m_gWorld = 0; + m_gWorldWidth = 0; + m_gWorldHeight = 0; +} + +void QTMovieGWorldPrivate::movieEnded(QTMovie*) +{ + // Do nothing +} + +void QTMovieGWorldPrivate::movieLoadStateChanged(QTMovie* movie) +{ + long loadState = GetMovieLoadState(movie->getMovieHandle()); + if (loadState != m_loadState) { + + // we only need to erase the movie gworld when the load state changes to loaded while it + // is visible as the gworld is destroyed/created when visibility changes + bool movieNewlyPlayable = loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded; + m_loadState = loadState; + + if (movieNewlyPlayable) { + updateMovieSize(); + if (m_visible) + clearGWorld(); + } + } +} + +void QTMovieGWorldPrivate::movieTimeChanged(QTMovie*) +{ + // Do nothing +} + +QTMovieGWorld::QTMovieGWorld(QTMovieGWorldClient* client) + : m_private(new QTMovieGWorldPrivate(this)) +{ + m_private->m_client = client; +} + +QTMovieGWorld::~QTMovieGWorld() +{ + delete m_private; +} + +void QTMovieGWorld::setSize(int width, int height) +{ + m_private->setSize(width, height); + QTMovieTask::sharedTask()->updateTaskTimer(); +} + +void QTMovieGWorld::setVisible(bool b) +{ + m_private->m_visible = b; + m_private->updateGWorld(); +} + +void QTMovieGWorld::getCurrentFrameInfo(void*& buffer, unsigned& bitsPerPixel, unsigned& rowBytes, unsigned& width, unsigned& height) +{ + if (!m_private->m_gWorld) { + buffer = 0; + bitsPerPixel = 0; + rowBytes = 0; + width = 0; + height = 0; + return; + } + PixMapHandle offscreenPixMap = GetGWorldPixMap(m_private->m_gWorld); + buffer = (*offscreenPixMap)->baseAddr; + bitsPerPixel = (*offscreenPixMap)->pixelSize; + rowBytes = (*offscreenPixMap)->rowBytes & 0x3FFF; + width = m_private->m_width; + height = m_private->m_height; +} + +void QTMovieGWorld::paint(HDC hdc, int x, int y) +{ + if (!m_private->m_gWorld) + return; + + HDC hdcSrc = static_cast<HDC>(GetPortHDC(reinterpret_cast<GrafPtr>(m_private->m_gWorld))); + if (!hdcSrc) + return; + + // FIXME: If we could determine the movie has no alpha, we could use BitBlt for those cases, which might be faster. + BLENDFUNCTION blendFunction; + blendFunction.BlendOp = AC_SRC_OVER; + blendFunction.BlendFlags = 0; + blendFunction.SourceConstantAlpha = 255; + blendFunction.AlphaFormat = AC_SRC_ALPHA; + AlphaBlend(hdc, x, y, m_private->m_width, m_private->m_height, hdcSrc, + 0, 0, m_private->m_width, m_private->m_height, blendFunction); +} + +void QTMovieGWorld::setDisabled(bool b) +{ + m_private->m_disabled = b; +} + +bool QTMovieGWorld::isDisabled() const +{ + return m_private->m_disabled; +} + +LRESULT QTMovieGWorld::fullscreenWndProc(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + QTMovieGWorld* movie = static_cast<QTMovieGWorld*>(GetProp(wnd, fullscreenQTMovieGWorldPointerProp)); + + if (message == WM_DESTROY) + RemoveProp(wnd, fullscreenQTMovieGWorldPointerProp); + + if (!movie) + return DefWindowProc(wnd, message, wParam, lParam); + + return movie->m_private->m_fullscreenClient->fullscreenClientWndProc(wnd, message, wParam, lParam); +} + +HWND QTMovieGWorld::enterFullscreen(QTMovieGWorldFullscreenClient* client) +{ + m_private->m_fullscreenClient = client; + + BeginFullScreen(&m_private->m_fullscreenRestoreState, 0, 0, 0, &m_private->m_fullscreenWindow, 0, fullScreenAllowEvents); + QTMLSetWindowWndProc(m_private->m_fullscreenWindow, fullscreenWndProc); + CreatePortAssociation(GetPortNativeWindow(m_private->m_fullscreenWindow), 0, 0); + + GetMovieBox(m_private->m_movie, &m_private->m_fullscreenRect); + GetMovieGWorld(m_private->m_movie, &m_private->m_fullscreenOrigGWorld, 0); + SetMovieGWorld(m_private->m_movie, reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow), GetGWorldDevice(reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow))); + + // Set the size of the box to preserve aspect ratio + Rect rect = m_private->m_fullscreenWindow->portRect; + + float movieRatio = static_cast<float>(m_private->m_width) / m_private->m_height; + int windowWidth = rect.right - rect.left; + int windowHeight = rect.bottom - rect.top; + float windowRatio = static_cast<float>(windowWidth) / windowHeight; + int actualWidth = (windowRatio > movieRatio) ? (windowHeight * movieRatio) : windowWidth; + int actualHeight = (windowRatio < movieRatio) ? (windowWidth / movieRatio) : windowHeight; + int offsetX = (windowWidth - actualWidth) / 2; + int offsetY = (windowHeight - actualHeight) / 2; + + rect.left = offsetX; + rect.right = offsetX + actualWidth; + rect.top = offsetY; + rect.bottom = offsetY + actualHeight; + + SetMovieBox(m_private->m_movie, &rect); + ShowHideTaskBar(true); + + // Set the 'this' pointer on the HWND + HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow)); + SetProp(wnd, fullscreenQTMovieGWorldPointerProp, static_cast<HANDLE>(this)); + + return wnd; +} + +void QTMovieGWorld::exitFullscreen() +{ + if (!m_private->m_fullscreenWindow) + return; + + HWND wnd = static_cast<HWND>(GetPortNativeWindow(m_private->m_fullscreenWindow)); + DestroyPortAssociation(reinterpret_cast<CGrafPtr>(m_private->m_fullscreenWindow)); + SetMovieGWorld(m_private->m_movie, m_private->m_fullscreenOrigGWorld, 0); + EndFullScreen(m_private->m_fullscreenRestoreState, 0L); + SetMovieBox(m_private->m_movie, &m_private->m_fullscreenRect); + m_private->m_fullscreenWindow = 0; +} + +void QTMovieGWorld::setMovie(PassRefPtr<QTMovie> movie) +{ + if (m_private->m_qtMovie) { + m_private->unregisterDrawingCallback(); + m_private->m_qtMovie->removeClient(m_private); + m_private->m_qtMovie = 0; + m_private->m_movie = 0; + } + + m_private->m_qtMovie = movie; + + if (m_private->m_qtMovie) { + m_private->m_qtMovie->addClient(m_private); + m_private->m_movie = m_private->m_qtMovie->getMovieHandle(); + m_private->registerDrawingCallback(); + } +} + +QTMovie* QTMovieGWorld::movie() const +{ + return m_private->m_qtMovie.get(); +} diff --git a/WebCore/platform/graphics/win/QTMovieGWorld.h b/WebCore/platform/graphics/win/QTMovieGWorld.h new file mode 100644 index 0000000..495fe25 --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieGWorld.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QTMovieGWorld_h +#define QTMovieGWorld_h + + +#include "QTMovie.h" +#include <Unicode.h> +#include <WTF/RefCounted.h> +#include <WTF/RefPtr.h> +#include <windows.h> + +#ifdef QTMOVIEWIN_EXPORTS +#define QTMOVIEWIN_API __declspec(dllexport) +#else +#define QTMOVIEWIN_API __declspec(dllimport) +#endif + +class QTMovieGWorld; +class QTMovieGWorldPrivate; + +class QTMovieGWorldClient { +public: + virtual void movieNewImageAvailable(QTMovieGWorld*) = 0; +}; + +class QTMovieGWorldFullscreenClient { +public: + virtual LRESULT fullscreenClientWndProc(HWND, UINT message, WPARAM, LPARAM) = 0; +}; + +class QTMOVIEWIN_API QTMovieGWorld : public RefCounted<QTMovieGWorld> { +public: + QTMovieGWorld(QTMovieGWorldClient*); + ~QTMovieGWorld(); + + void getNaturalSize(int& width, int& height); + void setSize(int width, int height); + + void setVisible(bool); + void paint(HDC, int x, int y); + void getCurrentFrameInfo(void*& buffer, unsigned& bitsPerPixel, unsigned& rowBytes, unsigned& width, unsigned& height); + + void setDisabled(bool); + bool isDisabled() const; + + // Returns the full-screen window created + HWND enterFullscreen(QTMovieGWorldFullscreenClient*); + void exitFullscreen(); + + void setMovie(PassRefPtr<QTMovie>); + QTMovie* movie() const; + +private: + static LRESULT fullscreenWndProc(HWND, UINT message, WPARAM, LPARAM); + + QTMovieGWorldPrivate* m_private; + friend class QTMovieGWorldPrivate; +}; + +#endif diff --git a/WebCore/platform/graphics/win/QTMovieTask.cpp b/WebCore/platform/graphics/win/QTMovieTask.cpp new file mode 100644 index 0000000..8713588 --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieTask.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include "QTMovieTask.h" + +// Put Movies.h first so build failures here point clearly to QuickTime +#include <Movies.h> + +#include <wtf/HashSet.h> +#include <wtf/StdLibExtras.h> +#include <wtf/Vector.h> + +QTMovieTask::QTMovieTask() + : m_setTaskTimerDelay(0) + , m_stopTaskTimer(0) +{ +} + +QTMovieTask::~QTMovieTask() +{ +} + +QTMovieTask* QTMovieTask::sharedTask() +{ + static QTMovieTask* s_sharedTask = new QTMovieTask; + return s_sharedTask; +} + +void QTMovieTask::updateTaskTimer(double maxInterval, double minInterval) +{ + ASSERT(m_setTaskTimerDelay); + if (!m_setTaskTimerDelay) + return; + + ASSERT(m_stopTaskTimer); + if (!m_taskList.size() && m_stopTaskTimer) { + m_stopTaskTimer(); + return; + } + + long intervalInMS; + OSStatus status = QTGetTimeUntilNextTask(&intervalInMS, 1000); + double interval = intervalInMS / 1000.0; + if (interval < minInterval) + interval = minInterval; + if (interval > maxInterval) + interval = maxInterval; + m_setTaskTimerDelay(interval); +} + +void QTMovieTask::fireTaskClients() +{ + Vector<QTMovieTaskClient*> clients; + copyToVector(m_taskList, clients); + for (Vector<QTMovieTaskClient*>::iterator i = clients.begin(); i != clients.end(); ++i) + (*i)->task(); +} + +void QTMovieTask::addTaskClient(QTMovieTaskClient* client) +{ + ASSERT(client); + if (!client) + return; + + m_taskList.add(client); +} + +void QTMovieTask::removeTaskClient(QTMovieTaskClient* client) +{ + ASSERT(client); + if (!client) + return; + + m_taskList.remove(client); +} + +void QTMovieTask::setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer) +{ + m_setTaskTimerDelay = setTaskTimerDelay; + m_stopTaskTimer = stopTaskTimer; +} + diff --git a/WebCore/platform/graphics/win/QTMovieTask.h b/WebCore/platform/graphics/win/QTMovieTask.h new file mode 100644 index 0000000..e394d6e --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieTask.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QTMovieTask_h +#define QTMovieTask_h + +#include <WTF/HashSet.h> + +#ifdef QTMOVIEWIN_EXPORTS +#define QTMOVIEWIN_API __declspec(dllexport) +#else +#define QTMOVIEWIN_API __declspec(dllimport) +#endif + +class QTMovieTaskClient { +public: + virtual void task() = 0; +}; + +typedef void (*SetTaskTimerDelayFunc)(double); +typedef void (*StopTaskTimerFunc)(); + +class QTMOVIEWIN_API QTMovieTask { +public: + static QTMovieTask* sharedTask(); + + void addTaskClient(QTMovieTaskClient* client); + void removeTaskClient(QTMovieTaskClient*); + void fireTaskClients(); + + void updateTaskTimer(double maxInterval = 1.0, double minInterval = 1.0 / 30); + void setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer); + +protected: + QTMovieTask(); + ~QTMovieTask(); + + SetTaskTimerDelayFunc m_setTaskTimerDelay; + StopTaskTimerFunc m_stopTaskTimer; + HashSet<QTMovieTaskClient*> m_taskList; + +private: + QTMovieTask(const QTMovieTask&); + QTMovieTask& operator=(const QTMovieTask&); +}; + +#endif diff --git a/WebCore/platform/graphics/win/QTMovieVisualContext.cpp b/WebCore/platform/graphics/win/QTMovieVisualContext.cpp new file mode 100644 index 0000000..9c08cd9 --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieVisualContext.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include "QTMovieVisualContext.h" + +#include "QTMovieTask.h" +#include <CVBase.h> +#include <CVHostTime.h> +#include <ImageCompression.h> +#include <Movies.h> +#include <windows.h> + +struct QTCVTimeStamp { + CVTimeStamp t; +}; + +class QTMovieVisualContextPriv { +public: + QTMovieVisualContextPriv(QTMovieVisualContext* parent, QTMovieVisualContextClient* client, CFDictionaryRef options); + ~QTMovieVisualContextPriv(); + + bool isImageAvailableForTime(const QTCVTimeStamp*) const; + QTPixelBuffer imageForTime(const QTCVTimeStamp*); + void task(); + + QTVisualContextRef visualContextRef(); + + void setMovie(PassRefPtr<QTMovie>); + QTMovie* movie() const; + + static void imageAvailableCallback(QTVisualContextRef visualContext, const CVTimeStamp *timeStamp, void *refCon); + +private: + QTMovieVisualContext* m_parent; + QTMovieVisualContextClient* m_client; + QTVisualContextRef m_visualContext; + RefPtr<QTMovie> m_movie; + +}; + +QTMovieVisualContextPriv::QTMovieVisualContextPriv(QTMovieVisualContext* parent, QTMovieVisualContextClient* client, CFDictionaryRef options) + : m_parent(parent) + , m_client(client) + , m_visualContext(0) +{ + typedef OSStatus ( __cdecl *pfnQTPixelBufferContextCreate)(CFAllocatorRef, CFDictionaryRef, QTVisualContextRef*); + static pfnQTPixelBufferContextCreate pPixelBufferContextCreate = 0; + if (!pPixelBufferContextCreate) { + HMODULE qtmlDLL = ::LoadLibraryW(L"QTMLClient.dll"); + if (!qtmlDLL) + return; + pPixelBufferContextCreate = reinterpret_cast<pfnQTPixelBufferContextCreate>(GetProcAddress(qtmlDLL, "QTPixelBufferContextCreate")); + if (!pPixelBufferContextCreate) + return; + } + + OSStatus status = pPixelBufferContextCreate(kCFAllocatorDefault, options, &m_visualContext); + if (status == noErr && m_visualContext) + QTVisualContextSetImageAvailableCallback(m_visualContext, &QTMovieVisualContextPriv::imageAvailableCallback, static_cast<void*>(this)); +} + +QTMovieVisualContextPriv::~QTMovieVisualContextPriv() +{ +} + +bool QTMovieVisualContextPriv::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const +{ + if (!m_visualContext) + return false; + + return QTVisualContextIsNewImageAvailable(m_visualContext, reinterpret_cast<const CVTimeStamp*>(timeStamp)); +} + +QTPixelBuffer QTMovieVisualContextPriv::imageForTime(const QTCVTimeStamp* timeStamp) +{ + QTPixelBuffer pixelBuffer; + if (m_visualContext) { + CVImageBufferRef newImage = 0; + OSStatus status = QTVisualContextCopyImageForTime(m_visualContext, kCFAllocatorDefault, reinterpret_cast<const CVTimeStamp*>(timeStamp), &newImage); + if (status == noErr) + pixelBuffer.adopt(newImage); + } + return pixelBuffer; +} + +void QTMovieVisualContextPriv::task() +{ + if (m_visualContext) + QTVisualContextTask(m_visualContext); +} + +QTVisualContextRef QTMovieVisualContextPriv::visualContextRef() +{ + return m_visualContext; +} + +void QTMovieVisualContextPriv::setMovie(PassRefPtr<QTMovie> movie) +{ + if (movie == m_movie) + return; + + if (m_movie) { + SetMovieVisualContext(m_movie->getMovieHandle(), 0); + m_movie = 0; + } + + if (movie) + OSStatus status = SetMovieVisualContext(movie->getMovieHandle(), m_visualContext); + + m_movie = movie; +} + +QTMovie* QTMovieVisualContextPriv::movie() const +{ + return m_movie.get(); +} + +void QTMovieVisualContextPriv::imageAvailableCallback(QTVisualContextRef visualContext, const CVTimeStamp *timeStamp, void *refCon) +{ + if (!refCon) + return; + + QTMovieVisualContextPriv* vc = static_cast<QTMovieVisualContextPriv*>(refCon); + if (!vc->m_client) + return; + + vc->m_client->imageAvailableForTime(reinterpret_cast<const QTCVTimeStamp*>(timeStamp)); +} + +static OSStatus SetNumberValue(CFMutableDictionaryRef inDict, CFStringRef inKey, SInt32 inValue) +{ + CFNumberRef number; + + number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue); + if (!number) + return coreFoundationUnknownErr; + + CFDictionarySetValue(inDict, inKey, number); + + CFRelease(number); + + return noErr; +} + +CFDictionaryRef QTMovieVisualContext::getCGImageOptions() +{ + static CFDictionaryRef options = 0; + + if (!options) { + CFMutableDictionaryRef pixelBufferOptions = 0; + CFMutableDictionaryRef visualContextOptions = 0; + OSStatus status = noErr; + + // Pixel Buffer attributes + pixelBufferOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + // Use the k32BGRAPixelFormat, as QuartzCore will be able to use the pixels directly, + // without needing an aditional copy or rendering pass:s + SetNumberValue(pixelBufferOptions, kCVPixelBufferPixelFormatTypeKey, k32BGRAPixelFormat); + + // alignment + SetNumberValue(pixelBufferOptions, kCVPixelBufferBytesPerRowAlignmentKey, 16); + + // compatability + SetNumberValue(pixelBufferOptions, kCVPixelBufferCGImageCompatibilityKey, 1); + + // QT Visual Context attributes + visualContextOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + // set the pixel buffer attributes for the visual context + CFDictionarySetValue(visualContextOptions, + kQTVisualContextPixelBufferAttributesKey, + pixelBufferOptions); + + if (pixelBufferOptions) + CFRelease(pixelBufferOptions); + + options = visualContextOptions; + } + + return options; +} + +QTMovieVisualContext::QTMovieVisualContext(QTMovieVisualContextClient* client, CFDictionaryRef options) + : m_private(new QTMovieVisualContextPriv(this, client, options)) +{ +} + +QTMovieVisualContext::~QTMovieVisualContext() +{ +} + +bool QTMovieVisualContext::isImageAvailableForTime(const QTCVTimeStamp* timeStamp) const +{ + return m_private->isImageAvailableForTime(timeStamp); +} + +QTPixelBuffer QTMovieVisualContext::imageForTime(const QTCVTimeStamp* timeStamp) +{ + return m_private->imageForTime(timeStamp); +} + +void QTMovieVisualContext::task() +{ + m_private->task(); +} + +QTVisualContextRef QTMovieVisualContext::visualContextRef() +{ + return m_private->visualContextRef(); +} + +void QTMovieVisualContext::setMovie(PassRefPtr<QTMovie> movie) +{ + m_private->setMovie(movie); +} + +QTMovie* QTMovieVisualContext::movie() const +{ + return m_private->movie(); +} + +double QTMovieVisualContext::currentHostTime() +{ + return CVGetCurrentHostTime() / CVGetHostClockFrequency(); +} diff --git a/WebCore/platform/graphics/win/QTMovieVisualContext.h b/WebCore/platform/graphics/win/QTMovieVisualContext.h new file mode 100644 index 0000000..7afe589 --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieVisualContext.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QTMovieVisualContext_h +#define QTMovieVisualContext_h + +#ifdef QTMOVIEWIN_EXPORTS +#define QTMOVIEWIN_API __declspec(dllexport) +#else +#define QTMOVIEWIN_API __declspec(dllimport) +#endif + +#include "QTMovie.h" +#include "QTMovieTask.h" +#include "QTPixelBuffer.h" +#include <WTF/OwnPtr.h> +#include <WTF/RefCounted.h> + +typedef struct OpaqueQTVisualContext* QTVisualContextRef; + +// QTCVTimeStamp is a struct containing only a CVTimeStamp. This is to +// work around the inability of CVTimeStamp to be forward declared, in +// addition to it being declared in different header files when building +// the QTMovieWin and WebCore projects. +struct QTCVTimeStamp; + +class QTMovieVisualContextClient { +public: + virtual void imageAvailableForTime(const QTCVTimeStamp*) = 0; +}; + +class QTMOVIEWIN_API QTMovieVisualContext : public RefCounted<QTMovieVisualContext> { +public: + QTMovieVisualContext(QTMovieVisualContextClient*, CFDictionaryRef options = 0); + ~QTMovieVisualContext(); + + bool isImageAvailableForTime(const QTCVTimeStamp*) const; + QTPixelBuffer imageForTime(const QTCVTimeStamp*); + void task(); + + QTVisualContextRef visualContextRef(); + + void setMovie(PassRefPtr<QTMovie>); + QTMovie* movie() const; + + static CFDictionaryRef getCGImageOptions(); + static double currentHostTime(); + +protected: + void setupVisualContext(); + + friend class QTMovieVisualContextPriv; + OwnPtr<QTMovieVisualContextPriv> m_private; +}; + +#endif diff --git a/WebCore/platform/graphics/win/QTPixelBuffer.cpp b/WebCore/platform/graphics/win/QTPixelBuffer.cpp new file mode 100644 index 0000000..657b68e --- /dev/null +++ b/WebCore/platform/graphics/win/QTPixelBuffer.cpp @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include "QTPixelBuffer.h" + +#include <CFString.h> +#include <CGColorSpace.h> +#include <CGImage.h> +#include <CVPixelBuffer.h> +#include <QuickDraw.h> +#include <memory.h> + +QTPixelBuffer::QTPixelBuffer() + : m_pixelBuffer(0) +{ +} + +QTPixelBuffer::QTPixelBuffer(const QTPixelBuffer& p) + : m_pixelBuffer(p.m_pixelBuffer) +{ + CVPixelBufferRetain(m_pixelBuffer); +} + +QTPixelBuffer::QTPixelBuffer(CVPixelBufferRef ref) + : m_pixelBuffer(ref) +{ + CVPixelBufferRetain(m_pixelBuffer); +} + +QTPixelBuffer::~QTPixelBuffer() +{ + clear(); +} + +QTPixelBuffer& QTPixelBuffer::operator=(const QTPixelBuffer& p) +{ + set(p.m_pixelBuffer); + return *this; +} + +void QTPixelBuffer::set(CVPixelBufferRef ref) +{ + CVPixelBufferRetain(ref); + CVPixelBufferRelease(m_pixelBuffer); + m_pixelBuffer = ref; +} + +CVPixelBufferRef QTPixelBuffer::pixelBufferRef() +{ + return m_pixelBuffer; +} + +void QTPixelBuffer::adopt(CVPixelBufferRef ref) +{ + if (ref == m_pixelBuffer) + return; + CVPixelBufferRelease(m_pixelBuffer); + m_pixelBuffer = ref; +} + +void QTPixelBuffer::clear() +{ + CVPixelBufferRelease(m_pixelBuffer); + m_pixelBuffer = 0; +} + +CVReturn QTPixelBuffer::lockBaseAddress() +{ + return CVPixelBufferLockBaseAddress(m_pixelBuffer, 0); +} + +CVReturn QTPixelBuffer::unlockBaseAddress() +{ + return CVPixelBufferUnlockBaseAddress(m_pixelBuffer, 0); +} + +void* QTPixelBuffer::baseAddress() +{ + return CVPixelBufferGetBaseAddress(m_pixelBuffer); +} + +size_t QTPixelBuffer::width() const +{ + return CVPixelBufferGetWidth(m_pixelBuffer); +} + +size_t QTPixelBuffer::height() const +{ + return CVPixelBufferGetHeight(m_pixelBuffer); +} + +unsigned long QTPixelBuffer::pixelFormatType() const +{ + return CVPixelBufferGetPixelFormatType(m_pixelBuffer); +} + +bool QTPixelBuffer::pixelFormatIs32ARGB() const +{ + return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32ARGBPixelFormat; +} + +bool QTPixelBuffer::pixelFormatIs32BGRA() const +{ + return CVPixelBufferGetPixelFormatType(m_pixelBuffer) == k32BGRAPixelFormat; +} + +size_t QTPixelBuffer::bytesPerRow() const +{ + return CVPixelBufferGetBytesPerRow(m_pixelBuffer); +} + +size_t QTPixelBuffer::dataSize() const +{ + return CVPixelBufferGetDataSize(m_pixelBuffer); +} + +bool QTPixelBuffer::isPlanar() const +{ + return CVPixelBufferIsPlanar(m_pixelBuffer); +} + +size_t QTPixelBuffer::planeCount() const +{ + return CVPixelBufferGetPlaneCount(m_pixelBuffer); +} + +size_t QTPixelBuffer::widthOfPlane(size_t plane) const +{ + return CVPixelBufferGetWidthOfPlane(m_pixelBuffer, plane); +} + +size_t QTPixelBuffer::heightOfPlane(size_t plane) const +{ + return CVPixelBufferGetHeightOfPlane(m_pixelBuffer, plane); +} + +void* QTPixelBuffer::baseAddressOfPlane(size_t plane) const +{ + return CVPixelBufferGetBaseAddressOfPlane(m_pixelBuffer, plane); +} + +size_t QTPixelBuffer::bytesPerRowOfPlane(size_t plane) const +{ + return CVPixelBufferGetBytesPerRowOfPlane(m_pixelBuffer, plane); +} + +void QTPixelBuffer::getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const +{ + return CVPixelBufferGetExtendedPixels(m_pixelBuffer, left, right, top, bottom); +} + +CFDictionaryRef QTPixelBuffer::attachments() const +{ + return CVBufferGetAttachments(m_pixelBuffer, kCVAttachmentMode_ShouldPropagate); +} + +void QTPixelBuffer::retainCallback(void* refcon) +{ + CVPixelBufferRetain(static_cast<CVPixelBufferRef>(refcon)); +} + +void QTPixelBuffer::releaseCallback(void* refcon) +{ + CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon)); +} + +void QTPixelBuffer::imageQueueReleaseCallback(unsigned int type, uint64_t id, void* refcon) +{ + CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon)); +} + +void QTPixelBuffer::dataProviderReleaseBytePointerCallback(void* refcon, const void* pointer) +{ + CVPixelBufferUnlockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0); +} + +const void* QTPixelBuffer::dataProviderGetBytePointerCallback(void* refcon) +{ + CVPixelBufferLockBaseAddress(static_cast<CVPixelBufferRef>(refcon), 0); + return CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon)); +} + +size_t QTPixelBuffer::dataProviderGetBytesAtPositionCallback(void* refcon, void* buffer, size_t position, size_t count) +{ + char* data = (char*)CVPixelBufferGetBaseAddress(static_cast<CVPixelBufferRef>(refcon)); + size_t size = CVPixelBufferGetDataSize(static_cast<CVPixelBufferRef>(refcon)); + if (size - position < count) + count = size - position; + + memcpy(buffer, data+position, count); + return count; +} + +void QTPixelBuffer::dataProviderReleaseInfoCallback(void* refcon) +{ + CVPixelBufferRelease(static_cast<CVPixelBufferRef>(refcon)); +} diff --git a/WebCore/platform/graphics/win/QTPixelBuffer.h b/WebCore/platform/graphics/win/QTPixelBuffer.h new file mode 100644 index 0000000..22f8ba4 --- /dev/null +++ b/WebCore/platform/graphics/win/QTPixelBuffer.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007, 2008, 2009, 2010 Apple, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QTPixelBuffer_h +#define QTPixelBuffer_h + +#ifdef QTMOVIEWIN_EXPORTS +#define QTMOVIEWIN_API __declspec(dllexport) +#else +#define QTMOVIEWIN_API __declspec(dllimport) +#endif + +#include <stdint.h> + +typedef struct __CVBuffer *CVBufferRef; +typedef CVBufferRef CVPixelBufferRef; +typedef struct CGImage* CGImageRef; +typedef int32_t CVReturn; +typedef const struct __CFDictionary * CFDictionaryRef; + +// QTPixelBuffer wraps QuickTime's implementation of CVPixelBuffer, so its functions are +// safe to call within WebKit. +class QTMOVIEWIN_API QTPixelBuffer { +public: + QTPixelBuffer(); + QTPixelBuffer(const QTPixelBuffer&); + QTPixelBuffer(CVPixelBufferRef); + QTPixelBuffer& operator=(const QTPixelBuffer&); + ~QTPixelBuffer(); + + void set(CVPixelBufferRef); + CVPixelBufferRef pixelBufferRef(); + void adopt(CVPixelBufferRef); + void clear(); + + CVReturn lockBaseAddress(); + CVReturn unlockBaseAddress(); + void* baseAddress(); + + size_t width() const; + size_t height() const; + unsigned long pixelFormatType() const; + bool pixelFormatIs32ARGB() const; + bool pixelFormatIs32BGRA() const; + size_t bytesPerRow() const; + size_t dataSize() const; + + bool isPlanar() const; + size_t planeCount() const; + size_t widthOfPlane(size_t) const; + size_t heightOfPlane(size_t) const; + void* baseAddressOfPlane(size_t) const; + size_t bytesPerRowOfPlane(size_t) const; + + void getExtendedPixels(size_t* left, size_t* right, size_t* top, size_t* bottom) const; + CFDictionaryRef attachments() const; + + // Generic CFRetain/CFRelease callbacks + static void releaseCallback(void* refcon); + static void retainCallback(void* refcon); + + // CAImageQueue callbacks + static void imageQueueReleaseCallback(unsigned int type, uint64_t id, void* refcon); + + // CGDataProvider callbacks + static void dataProviderReleaseBytePointerCallback(void* refcon, const void* pointer); + static const void* dataProviderGetBytePointerCallback(void* refcon); + static size_t dataProviderGetBytesAtPositionCallback(void* refcon, void* buffer, size_t position, size_t count); + static void dataProviderReleaseInfoCallback(void* refcon); + +private: + CVPixelBufferRef m_pixelBuffer; +}; + +#endif diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp index 714a4ac..994d079 100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp @@ -231,6 +231,7 @@ WKCACFLayerRenderer::WKCACFLayerRenderer() , m_scrollPosition(0, 0) , m_scrollSize(1, 1) , m_backingStoreDirty(false) + , m_mustResetLostDeviceBeforeRendering(false) { #ifndef NDEBUG char* printTreeFlag = getenv("CA_PRINT_TREE"); @@ -422,7 +423,9 @@ void WKCACFLayerRenderer::resize() if (!m_d3dDevice) return; - resetDevice(); + // Resetting the device might fail here. But that's OK, because if it does it we will attempt to + // reset the device the next time we try to render. + resetDevice(ChangedWindowSize); if (m_rootLayer) { m_rootLayer->setFrame(bounds()); @@ -491,6 +494,12 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) { ASSERT(m_d3dDevice); + if (m_mustResetLostDeviceBeforeRendering && !resetDevice(LostDevice)) { + // We can't reset the device right now. Try again soon. + renderSoon(); + return; + } + // Flush the root layer to the render tree. WKCACFContextFlusher::shared().flushAllContexts(); @@ -547,10 +556,12 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) err = m_d3dDevice->Present(0, 0, 0, 0); if (err == D3DERR_DEVICELOST) { - // Lost device situation. - CARenderOGLPurge(m_renderer); - resetDevice(); CARenderUpdateAddRect(u, &bounds); + if (!resetDevice(LostDevice)) { + // We can't reset the device right now. Try again soon. + renderSoon(); + return; + } } } while (err == D3DERR_DEVICELOST); @@ -593,13 +604,43 @@ void WKCACFLayerRenderer::initD3DGeometry() m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); } -void WKCACFLayerRenderer::resetDevice() +bool WKCACFLayerRenderer::resetDevice(ResetReason reason) { ASSERT(m_d3dDevice); + ASSERT(m_renderContext); + + HRESULT hr = m_d3dDevice->TestCooperativeLevel(); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_DRIVERINTERNALERROR) { + // The device cannot be reset at this time. Try again soon. + m_mustResetLostDeviceBeforeRendering = true; + return false; + } + + m_mustResetLostDeviceBeforeRendering = false; + + if (reason == LostDevice && hr == D3D_OK) { + // The device wasn't lost after all. + return true; + } + + // We can reset the device. + + // We have to purge the CARenderOGLContext whenever we reset the IDirect3DDevice9 in order to + // destroy any D3DPOOL_DEFAULT resources that Core Animation has allocated (e.g., textures used + // for mask layers). See <http://msdn.microsoft.com/en-us/library/bb174425(v=VS.85).aspx>. + CARenderOGLPurge(m_renderer); D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); - m_d3dDevice->Reset(¶meters); + hr = m_d3dDevice->Reset(¶meters); + + // TestCooperativeLevel told us the device may be reset now, so we should + // not be told here that the device is lost. + ASSERT(hr != D3DERR_DEVICELOST); + initD3DGeometry(); + + return true; } } diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h index b708464..259c52f 100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h @@ -84,7 +84,12 @@ private: CGRect bounds() const; void initD3DGeometry(); - void resetDevice(); + + // Call this when the device window has changed size or when IDirect3DDevice9::Present returns + // D3DERR_DEVICELOST. Returns true if the device was recovered, false if rendering must be + // aborted and reattempted soon. + enum ResetReason { ChangedWindowSize, LostDevice }; + bool resetDevice(ResetReason); void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); void paint(); @@ -104,6 +109,7 @@ private: IntPoint m_scrollPosition; IntSize m_scrollSize; bool m_backingStoreDirty; + bool m_mustResetLostDeviceBeforeRendering; #ifndef NDEBUG bool m_printTree; #endif diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h index 94585e6..9d506d6 100644 --- a/WebCore/platform/graphics/wx/FontPlatformData.h +++ b/WebCore/platform/graphics/wx/FontPlatformData.h @@ -156,9 +156,8 @@ public: #if OS(DARWIN) ATSUFontID m_atsuFontID; CGFontRef cgFont() const; - NSFont* nsFont() const; + NSFont* nsFont() const { return m_nsFont; } void cacheNSFont(); - #endif float m_size; diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index 601d6b4..6c5b300 100644 --- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -99,8 +99,12 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri ) ); #endif -#if OS(DARWIN) +#if OS(DARWIN) && !defined(wxOSX_USE_CORE_TEXT) +#if wxCHECK_VERSION(2,9,0) + m_atsuFontID = m_font->font()->OSXGetATSUFontID(); +#else m_atsuFontID = m_font->font()->MacGetATSUFontID(); +#endif cacheNSFont(); #endif m_size = desc.computedPixelSize(); diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWxMac.mm b/WebCore/platform/graphics/wx/FontPlatformDataWxMac.mm index b719656..4290f04 100644 --- a/WebCore/platform/graphics/wx/FontPlatformDataWxMac.mm +++ b/WebCore/platform/graphics/wx/FontPlatformDataWxMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Kevin Ollivier All rights reserved. + * Copyright (C) 2010 Kevin Ollivier, Stefan Csomor All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,20 +31,117 @@ #include <wx/defs.h> #include <wx/font.h> +#include <wx/fontutil.h> -namespace WebCore { +#if !wxCHECK_VERSION(2,9,0) +#include <wx/mac/private.h> +#else +#include <wx/osx/private.h> +#endif + +#if !wxCHECK_VERSION(2,9,0) || !wxOSX_USE_COCOA -NSFont* FontPlatformData::nsFont() const +static inline double DegToRad(double deg) { -#if wxCHECK_VERSION(2,9,1) && wxOSX_USE_COCOA - if (m_font && m_font->font()) - return (NSFont*)m_font->font()->OSXGetNSFont(); -#endif + return (deg * M_PI) / 180.0; } -void FontPlatformData::cacheNSFont() +static const NSAffineTransformStruct kSlantNSTransformStruct = { 1, 0, tan(DegToRad(11)), 1, 0, 0 }; + +NSFont* OSXCreateNSFont(const wxNativeFontInfo* info) { + NSFont* nsFont; + int weight = 5; + NSFontTraitMask traits = 0; + if (info->GetWeight() == wxFONTWEIGHT_BOLD) + { + traits |= NSBoldFontMask; + weight = 9; + } + else if (info->GetWeight() == wxFONTWEIGHT_LIGHT) + weight = 3; + + if (info->GetStyle() == wxFONTSTYLE_ITALIC || info->GetStyle() == wxFONTSTYLE_SLANT) + traits |= NSItalicFontMask; + + nsFont = [[NSFontManager sharedFontManager] fontWithFamily:(NSString*)(CFStringRef)wxMacCFStringHolder(info->GetFaceName()) + traits:traits weight:weight size:info->GetPointSize()]; + + if ( nsFont == nil ) + { + NSFontTraitMask remainingTraits = traits; + nsFont = [[NSFontManager sharedFontManager] fontWithFamily:(NSString*)(CFStringRef)wxMacCFStringHolder(info->GetFaceName()) + traits:0 weight:5 size:info->GetPointSize()]; + if ( nsFont == nil ) + { + if ( info->GetWeight() == wxFONTWEIGHT_BOLD ) + { + nsFont = [NSFont boldSystemFontOfSize:info->GetPointSize()]; + remainingTraits &= ~NSBoldFontMask; + } + else + nsFont = [NSFont systemFontOfSize:info->GetPointSize()]; + } + + // fallback - if in doubt, let go of the bold attribute + if ( nsFont && (remainingTraits & NSItalicFontMask) ) + { + NSFont* nsFontWithTraits = nil; + if ( remainingTraits & NSBoldFontMask) + { + nsFontWithTraits = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSBoldFontMask]; + if ( nsFontWithTraits == nil ) + { + nsFontWithTraits = [[NSFontManager sharedFontManager] convertFont:nsFont toHaveTrait:NSItalicFontMask]; + if ( nsFontWithTraits != nil ) + remainingTraits &= ~NSItalicFontMask; + } + else + { + remainingTraits &= ~NSBoldFontMask; + } + } + if ( remainingTraits & NSItalicFontMask) + { + if ( nsFontWithTraits == nil ) + nsFontWithTraits = nsFont; + + NSAffineTransform* transform = [NSAffineTransform transform]; + [transform setTransformStruct:kSlantNSTransformStruct]; + [transform scaleBy:info->GetPointSize()]; + NSFontDescriptor* italicDesc = [[nsFontWithTraits fontDescriptor] fontDescriptorWithMatrix:transform]; + if ( italicDesc != nil ) + { + NSFont* f = [NSFont fontWithDescriptor:italicDesc size:(CGFloat)(info->GetPointSize())]; + if ( f != nil ) + nsFontWithTraits = f; + } + } + if ( nsFontWithTraits != nil ) + nsFont = nsFontWithTraits; + } + } + + wxASSERT_MSG(nsFont != nil,wxT("Couldn't create nsFont")) ; + wxMacCocoaRetain(nsFont); + return nsFont; +} +#endif + +namespace WebCore { + +void FontPlatformData::cacheNSFont() +{ + if (m_nsFont) + return; + +#if wxCHECK_VERSION(2,9,1) && wxOSX_USE_COCOA + if (m_font && m_font->font()) + m_nsFont = (NSFont*)m_font->font()->OSXGetNSFont(); +#else + m_nsFont = OSXCreateNSFont(m_font->font()->GetNativeFontInfo()); +#endif } } |