summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-02-02 14:57:50 +0000
committerSteve Block <steveblock@google.com>2010-02-04 15:06:55 +0000
commitd0825bca7fe65beaee391d30da42e937db621564 (patch)
tree7461c49eb5844ffd1f35d1ba2c8b7584c1620823 /WebCore/platform/graphics
parent3db770bd97c5a59b6c7574ca80a39e5a51c1defd (diff)
downloadexternal_webkit-d0825bca7fe65beaee391d30da42e937db621564.zip
external_webkit-d0825bca7fe65beaee391d30da42e937db621564.tar.gz
external_webkit-d0825bca7fe65beaee391d30da42e937db621564.tar.bz2
Merge webkit.org at r54127 : Initial merge by git
Change-Id: Ib661abb595522f50ea406f72d3a0ce17f7193c82
Diffstat (limited to 'WebCore/platform/graphics')
-rw-r--r--WebCore/platform/graphics/BitmapImage.h6
-rw-r--r--WebCore/platform/graphics/FloatPoint.h4
-rw-r--r--WebCore/platform/graphics/FloatQuad.cpp6
-rw-r--r--WebCore/platform/graphics/FloatQuad.h6
-rw-r--r--WebCore/platform/graphics/FloatRect.h12
-rw-r--r--WebCore/platform/graphics/FloatSize.h4
-rw-r--r--WebCore/platform/graphics/Font.cpp17
-rw-r--r--WebCore/platform/graphics/Font.h22
-rw-r--r--WebCore/platform/graphics/FontCache.cpp6
-rw-r--r--WebCore/platform/graphics/FontCache.h2
-rw-r--r--WebCore/platform/graphics/FontFastPath.cpp15
-rw-r--r--WebCore/platform/graphics/GeneratedImage.cpp41
-rw-r--r--WebCore/platform/graphics/Generator.h1
-rw-r--r--WebCore/platform/graphics/GlyphBuffer.h10
-rw-r--r--WebCore/platform/graphics/Gradient.cpp36
-rw-r--r--WebCore/platform/graphics/Gradient.h17
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp102
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h31
-rw-r--r--WebCore/platform/graphics/GraphicsContext3D.h56
-rw-r--r--WebCore/platform/graphics/GraphicsContextPrivate.h9
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.cpp37
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.h31
-rw-r--r--WebCore/platform/graphics/Image.h1
-rw-r--r--WebCore/platform/graphics/ImageSource.cpp9
-rw-r--r--WebCore/platform/graphics/ImageSource.h4
-rw-r--r--WebCore/platform/graphics/IntRect.cpp35
-rw-r--r--WebCore/platform/graphics/IntRect.h33
-rw-r--r--WebCore/platform/graphics/IntSize.h3
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp37
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h10
-rw-r--r--WebCore/platform/graphics/MediaPlayerPrivate.h10
-rw-r--r--WebCore/platform/graphics/Path.h18
-rw-r--r--WebCore/platform/graphics/Pattern.h2
-rw-r--r--WebCore/platform/graphics/SimpleFontData.h19
-rw-r--r--WebCore/platform/graphics/TypesettingFeatures.h38
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp12
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h2
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp2
-rw-r--r--WebCore/platform/graphics/cg/ColorCG.cpp4
-rw-r--r--WebCore/platform/graphics/cg/GradientCG.cpp49
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp61
-rw-r--r--WebCore/platform/graphics/cg/PatternCG.cpp2
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp28
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.h12
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp36
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformData.h4
-rw-r--r--WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp34
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.cpp5
-rw-r--r--WebCore/platform/graphics/filters/FEColorMatrix.cpp1
-rw-r--r--WebCore/platform/graphics/filters/FEComponentTransfer.cpp4
-rw-r--r--WebCore/platform/graphics/filters/FEComponentTransfer.h1
-rw-r--r--WebCore/platform/graphics/filters/FEComposite.cpp4
-rw-r--r--WebCore/platform/graphics/gtk/ImageGtk.cpp57
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp385
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h37
-rw-r--r--WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp8
-rw-r--r--WebCore/platform/graphics/mac/Canvas3DLayer.mm10
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextController.cpp65
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextController.h31
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp67
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp59
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp181
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContextMac.mm52
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.h161
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm956
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h18
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm74
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm29
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.mm7
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.mm7
-rw-r--r--WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp2
-rw-r--r--WebCore/platform/graphics/opentype/OpenTypeUtilities.h2
-rw-r--r--WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp431
-rw-r--r--WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h89
-rw-r--r--WebCore/platform/graphics/openvg/EGLUtils.h71
-rw-r--r--WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp566
-rw-r--r--WebCore/platform/graphics/openvg/PainterOpenVG.cpp957
-rw-r--r--WebCore/platform/graphics/openvg/PainterOpenVG.h121
-rw-r--r--WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp243
-rw-r--r--WebCore/platform/graphics/openvg/SurfaceOpenVG.h137
-rw-r--r--WebCore/platform/graphics/openvg/VGUtils.cpp100
-rw-r--r--WebCore/platform/graphics/openvg/VGUtils.h87
-rw-r--r--WebCore/platform/graphics/qt/FontCacheQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformData.h2
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformDataQt.cpp11
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp37
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp30
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.cpp1118
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.h85
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp29
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.h5
-rw-r--r--WebCore/platform/graphics/qt/ImageQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp32
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h4
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp81
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextSkia.cpp15
-rw-r--r--WebCore/platform/graphics/skia/ImageBufferSkia.cpp2
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp19
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.h8
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.h36
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp3
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp13
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.cpp33
-rw-r--r--WebCore/platform/graphics/win/FontDatabase.cpp3
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp7
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp12
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp17
-rw-r--r--WebCore/platform/graphics/win/GraphicsLayerCACF.cpp11
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp6
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp325
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h65
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.cpp132
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.h14
-rw-r--r--WebCore/platform/graphics/win/TransformationMatrixWin.cpp2
-rw-r--r--WebCore/platform/graphics/win/WKCACFLayer.cpp170
-rw-r--r--WebCore/platform/graphics/win/WKCACFLayer.h23
-rw-r--r--WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp98
-rw-r--r--WebCore/platform/graphics/win/WKCACFLayerRenderer.h4
-rw-r--r--WebCore/platform/graphics/wince/GraphicsContextWince.cpp12
-rw-r--r--WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h4
-rw-r--r--WebCore/platform/graphics/wx/GraphicsContextWx.cpp9
122 files changed, 7161 insertions, 1283 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h
index 0031df6..485bb02 100644
--- a/WebCore/platform/graphics/BitmapImage.h
+++ b/WebCore/platform/graphics/BitmapImage.h
@@ -140,7 +140,7 @@ public:
virtual CGImageRef getCGImageRef();
#endif
-#if PLATFORM(WIN) || (PLATFORM(QT) && PLATFORM(WIN_OS))
+#if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS))
static PassRefPtr<BitmapImage> create(HBITMAP);
#endif
#if PLATFORM(WIN)
@@ -173,7 +173,7 @@ protected:
#endif
virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
-#if PLATFORM(WX) || (PLATFORM(WINCE) && !PLATFORM(QT))
+#if PLATFORM(WX) || (OS(WINCE) && !PLATFORM(QT))
virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect);
#endif
@@ -240,7 +240,7 @@ protected:
checkForSolidColor();
// WINCE PORT: checkForSolidColor() doesn't set m_checkedForSolidColor until
// it gets enough information to make final decision.
-#if !PLATFORM(WINCE)
+#if !OS(WINCE)
ASSERT(m_checkedForSolidColor);
#endif
}
diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h
index 45a1e83..6b037ff 100644
--- a/WebCore/platform/graphics/FloatPoint.h
+++ b/WebCore/platform/graphics/FloatPoint.h
@@ -36,7 +36,7 @@
typedef struct CGPoint CGPoint;
#endif
-#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
typedef struct CGPoint NSPoint;
#else
@@ -85,7 +85,7 @@ public:
#endif
#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
- || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
FloatPoint(const NSPoint&);
operator NSPoint() const;
#endif
diff --git a/WebCore/platform/graphics/FloatQuad.cpp b/WebCore/platform/graphics/FloatQuad.cpp
index 427230d..d1069fb 100644
--- a/WebCore/platform/graphics/FloatQuad.cpp
+++ b/WebCore/platform/graphics/FloatQuad.cpp
@@ -85,6 +85,12 @@ FloatRect FloatQuad::boundingBox() const
return FloatRect(left, top, right - left, bottom - top);
}
+bool FloatQuad::isRectilinear() const
+{
+ return (m_p1.x() == m_p2.x() && m_p2.y() == m_p3.y() && m_p3.x() == m_p4.x() && m_p4.y() == m_p1.y())
+ || (m_p1.y() == m_p2.y() && m_p2.x() == m_p3.x() && m_p3.y() == m_p4.y() && m_p4.x() == m_p1.x());
+}
+
bool FloatQuad::containsPoint(const FloatPoint& p) const
{
return isPointInTriangle(p, m_p1, m_p2, m_p3) || isPointInTriangle(p, m_p1, m_p3, m_p4);
diff --git a/WebCore/platform/graphics/FloatQuad.h b/WebCore/platform/graphics/FloatQuad.h
index 5982967..6cd86f6 100644
--- a/WebCore/platform/graphics/FloatQuad.h
+++ b/WebCore/platform/graphics/FloatQuad.h
@@ -74,6 +74,12 @@ public:
// "slanted" empty quads.
bool isEmpty() const { return boundingBox().isEmpty(); }
+ // Tests whether this quad can be losslessly represented by a FloatRect,
+ // that is, if two edges are parallel to the x-axis and the other two
+ // are parallel to the y-axis. If this method returns true, the
+ // corresponding FloatRect can be retrieved with boundingBox().
+ bool isRectilinear() const;
+
// Tests whether the given point is inside, or on an edge or corner of this quad.
bool containsPoint(const FloatPoint&) const;
diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h
index 2dc854d..74a6293 100644
--- a/WebCore/platform/graphics/FloatRect.h
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -33,7 +33,7 @@
typedef struct CGRect CGRect;
#endif
-#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
typedef struct CGRect NSRect;
#else
@@ -61,6 +61,10 @@ struct SkRect;
namespace WebCore {
+#if PLATFORM(OPENVG)
+class VGRect;
+#endif
+
class IntRect;
class FloatRect {
@@ -129,7 +133,7 @@ public:
#endif
#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
- || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
FloatRect(const NSRect&);
operator NSRect() const;
#endif
@@ -154,6 +158,10 @@ public:
operator SkRect() const;
#endif
+#if PLATFORM(OPENVG)
+ operator VGRect() const;
+#endif
+
private:
FloatPoint m_location;
FloatSize m_size;
diff --git a/WebCore/platform/graphics/FloatSize.h b/WebCore/platform/graphics/FloatSize.h
index 5a84fd1..1bc3423 100644
--- a/WebCore/platform/graphics/FloatSize.h
+++ b/WebCore/platform/graphics/FloatSize.h
@@ -34,7 +34,7 @@
typedef struct CGSize CGSize;
#endif
-#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
typedef struct CGSize NSSize;
#else
@@ -80,7 +80,7 @@ public:
#endif
#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
- || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
explicit FloatSize(const NSSize &); // don't do this implicitly since it's lossy
operator NSSize() const;
#endif
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp
index 88774cb..7d0e5a9 100644
--- a/WebCore/platform/graphics/Font.cpp
+++ b/WebCore/platform/graphics/Font.cpp
@@ -24,7 +24,6 @@
#include "config.h"
#include "Font.h"
-#include "CharacterNames.h"
#include "FloatRect.h"
#include "FontCache.h"
#include "FontFallbackList.h"
@@ -266,6 +265,22 @@ FontSelector* Font::fontSelector() const
return m_fontList ? m_fontList->fontSelector() : 0;
}
+String Font::normalizeSpaces(const String& string)
+{
+ unsigned length = string.length();
+ Vector<UChar, 256> buffer(length);
+ bool didReplacement = false;
+
+ for (unsigned i = 0; i < length; ++i) {
+ UChar originalCharacter = string[i];
+ buffer[i] = normalizeSpaces(originalCharacter);
+ if (buffer[i] != originalCharacter)
+ didReplacement = true;
+ }
+
+ return didReplacement ? String(buffer.data(), length) : string;
+}
+
static bool shouldUseFontSmoothing = true;
void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h
index c067071..3c07be7 100644
--- a/WebCore/platform/graphics/Font.h
+++ b/WebCore/platform/graphics/Font.h
@@ -25,10 +25,13 @@
#ifndef Font_h
#define Font_h
+#include "CharacterNames.h"
#include "TextRun.h"
#include "FontDescription.h"
#include "SimpleFontData.h"
+#include "TypesettingFeatures.h"
#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
#include <wtf/MathExtras.h>
#if PLATFORM(QT)
@@ -96,6 +99,12 @@ public:
FontRenderingMode renderingMode() const { return m_fontDescription.renderingMode(); }
+ TypesettingFeatures typesettingFeatures() const
+ {
+ TextRenderingMode textRenderingMode = m_fontDescription.textRenderingMode();
+ return textRenderingMode == OptimizeLegibility || textRenderingMode == GeometricPrecision ? Kerning | Ligatures : 0;
+ }
+
FontFamily& firstFamily() { return m_fontDescription.firstFamily(); }
const FontFamily& family() const { return m_fontDescription.family(); }
@@ -175,6 +184,19 @@ public:
static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; }
static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == 0x200e || c == 0x200f || (c >= 0x202a && c <= 0x202e) || c == 0xFFFC; }
+ static inline UChar normalizeSpaces(UChar character)
+ {
+ if (treatAsSpace(character))
+ return space;
+
+ if (treatAsZeroWidthSpace(character))
+ return zeroWidthSpace;
+
+ return character;
+ }
+
+ static String normalizeSpaces(const String&);
+
#if ENABLE(SVG_FONTS)
bool isSVGFont() const;
SVGFontElement* svgFont() const;
diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp
index 06ea56b..2aa68f1 100644
--- a/WebCore/platform/graphics/FontCache.cpp
+++ b/WebCore/platform/graphics/FontCache.cpp
@@ -53,7 +53,7 @@ FontCache::FontCache()
{
}
-struct FontPlatformDataCacheKey {
+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)
@@ -139,7 +139,7 @@ static const AtomicString& alternateFamilyName(const AtomicString& familyName)
DEFINE_STATIC_LOCAL(AtomicString, courierNew, ("Courier New"));
if (equalIgnoringCase(familyName, courier))
return courierNew;
-#if !PLATFORM(WIN_OS)
+#if !OS(WINDOWS)
// On Windows, Courier New (truetype font) is always present and
// Courier is a bitmap font. So, we don't want to map Courier New to
// Courier.
@@ -163,7 +163,7 @@ static const AtomicString& alternateFamilyName(const AtomicString& familyName)
if (equalIgnoringCase(familyName, helvetica))
return arial;
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
// On Windows, bitmap fonts are blocked altogether so that we have to
// alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font)
DEFINE_STATIC_LOCAL(AtomicString, msSans, ("MS Sans Serif"));
diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h
index 4a6222b..9b41e38 100644
--- a/WebCore/platform/graphics/FontCache.h
+++ b/WebCore/platform/graphics/FontCache.h
@@ -64,7 +64,7 @@ public:
// Also implemented by the platform.
void platformInit();
-#if PLATFORM(WINCE) && !PLATFORM(QT)
+#if OS(WINCE) && !PLATFORM(QT)
#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
IMLangFontLink2* getFontLinkInterface();
#else
diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp
index 5246593..428e85e 100644
--- a/WebCore/platform/graphics/FontFastPath.cpp
+++ b/WebCore/platform/graphics/FontFastPath.cpp
@@ -135,13 +135,7 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap
UChar codeUnits[2];
int codeUnitsLength;
if (c <= 0xFFFF) {
- UChar c16 = c;
- if (Font::treatAsSpace(c16))
- codeUnits[0] = ' ';
- else if (Font::treatAsZeroWidthSpace(c16))
- codeUnits[0] = zeroWidthSpace;
- else
- codeUnits[0] = c16;
+ codeUnits[0] = Font::normalizeSpaces(c);
codeUnitsLength = 1;
} else {
codeUnits[0] = U16_LEAD(c);
@@ -157,7 +151,7 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap
GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
// Cache it so we don't have to do system fallback again next time.
if (!useSmallCapsFont) {
-#if PLATFORM(WINCE)
+#if OS(WINCE)
// missingGlyphData returns a null character, which is not suitable for GDI to display.
// Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
// display the character, probably because the font package is not installed correctly.
@@ -175,7 +169,7 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap
// FIXME: It would be nicer to use the missing glyph from the last resort font instead.
GlyphData data = primaryFont()->missingGlyphData();
if (!useSmallCapsFont) {
-#if PLATFORM(WINCE)
+#if OS(WINCE)
// See comment about WINCE GDI handling near setGlyphDataForCharacter above.
page->setGlyphDataForCharacter(c, c, data.fontData);
return page->glyphDataForCharacter(c);
@@ -251,8 +245,7 @@ bool Font::canUseGlyphCache(const TextRun& run) const
return false;
}
- TextRenderingMode textMode = m_fontDescription.textRenderingMode();
- if (textMode == OptimizeLegibility || textMode == GeometricPrecision)
+ if (typesettingFeatures())
return false;
return true;
diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp
index eec7ffb..8395aff 100644
--- a/WebCore/platform/graphics/GeneratedImage.cpp
+++ b/WebCore/platform/graphics/GeneratedImage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 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
@@ -10,17 +10,17 @@
* 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.
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -50,19 +50,24 @@ void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, co
void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect)
{
+ // Allow the generator to provide visually-equivalent tiling parameters for better performance.
+ IntSize adjustedSize = m_size;
+ FloatRect adjustedSrcRect = srcRect;
+ m_generator->adjustParametersForTiledDrawing(adjustedSize, adjustedSrcRect);
+
// Create a BitmapImage and call drawPattern on it.
- OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size);
+ OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(adjustedSize);
ASSERT(imageBuffer.get());
-
+
// Fill with the gradient.
GraphicsContext* graphicsContext = imageBuffer->context();
- graphicsContext->fillRect(FloatRect(FloatPoint(), m_size), *m_generator.get());
-
+ graphicsContext->fillRect(FloatRect(FloatPoint(), adjustedSize), *m_generator.get());
+
// Grab the final image from the image buffer.
Image* bitmap = imageBuffer->image();
-
+
// Now just call drawTiled on that image.
- bitmap->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, compositeOp, destRect);
+ bitmap->drawPattern(context, adjustedSrcRect, patternTransform, phase, styleColorSpace, compositeOp, destRect);
}
}
diff --git a/WebCore/platform/graphics/Generator.h b/WebCore/platform/graphics/Generator.h
index a0af689..b64d051 100644
--- a/WebCore/platform/graphics/Generator.h
+++ b/WebCore/platform/graphics/Generator.h
@@ -38,6 +38,7 @@ public:
virtual ~Generator() {};
virtual void fill(GraphicsContext*, const FloatRect&) = 0;
+ virtual void adjustParametersForTiledDrawing(IntSize& /* size */, FloatRect& /* srcRect */) { }
};
} //namespace
diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h
index 04491a7..edb804c 100644
--- a/WebCore/platform/graphics/GlyphBuffer.h
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -50,7 +50,7 @@ class SimpleFontData;
#if PLATFORM(CAIRO)
// FIXME: Why does Cairo use such a huge struct instead of just an offset into an array?
typedef cairo_glyph_t GlyphBufferGlyph;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
typedef wchar_t GlyphBufferGlyph;
#else
typedef Glyph GlyphBufferGlyph;
@@ -60,7 +60,7 @@ typedef Glyph GlyphBufferGlyph;
// can be passed directly to CGContextShowGlyphsWithAdvances in FontMac.mm
#if PLATFORM(CG)
typedef CGSize GlyphBufferAdvance;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
// There is no cross-platform code that uses the height of GlyphBufferAdvance,
// so we can save memory space on embedded devices by storing only the width
typedef float GlyphBufferAdvance;
@@ -124,7 +124,7 @@ public:
{
#if PLATFORM(CG)
return m_advances[index].width;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
return m_advances[index];
#else
return m_advances[index].width();
@@ -156,7 +156,7 @@ public:
#if PLATFORM(CG)
CGSize advance = { width, 0 };
m_advances.append(advance);
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
m_advances.append(width);
#else
m_advances.append(FloatSize(width, 0));
@@ -172,7 +172,7 @@ public:
#endif
}
-#if !PLATFORM(WINCE)
+#if !OS(WINCE)
void add(Glyph glyph, const SimpleFontData* font, GlyphBufferAdvance advance)
{
m_fontData.append(font);
diff --git a/WebCore/platform/graphics/Gradient.cpp b/WebCore/platform/graphics/Gradient.cpp
index 204a2b6..17d461f 100644
--- a/WebCore/platform/graphics/Gradient.cpp
+++ b/WebCore/platform/graphics/Gradient.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -28,6 +28,8 @@
#include "Gradient.h"
#include "Color.h"
+#include "FloatRect.h"
+#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -62,6 +64,28 @@ Gradient::~Gradient()
platformDestroy();
}
+void Gradient::adjustParametersForTiledDrawing(IntSize& size, FloatRect& srcRect)
+{
+ if (m_radial)
+ return;
+
+ if (srcRect.isEmpty())
+ return;
+
+ if (m_p0.x() == m_p1.x()) {
+ size.setWidth(1);
+ srcRect.setWidth(1);
+ srcRect.setX(0);
+ return;
+ }
+ if (m_p0.y() != m_p1.y())
+ return;
+
+ size.setHeight(1);
+ srcRect.setHeight(1);
+ srcRect.setY(0);
+}
+
void Gradient::addColorStop(float value, const Color& color)
{
float r;
@@ -81,6 +105,16 @@ static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::Co
return a.stop < b.stop;
}
+void Gradient::sortStopsIfNecessary()
+{
+ if (m_stopsSorted)
+ return;
+
+ if (m_stops.size())
+ std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
+ m_stopsSorted = true;
+}
+
void Gradient::getColor(float value, float* r, float* g, float* b, float* a) const
{
ASSERT(value >= 0);
diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h
index 011a2cd..b65550d 100644
--- a/WebCore/platform/graphics/Gradient.h
+++ b/WebCore/platform/graphics/Gradient.h
@@ -36,8 +36,15 @@
#include <wtf/Vector.h>
#if PLATFORM(CG)
+
+#ifdef BUILDING_ON_TIGER
typedef struct CGShading* CGShadingRef;
typedef CGShadingRef PlatformGradient;
+#else
+typedef struct CGGradient* CGGradientRef;
+typedef CGGradientRef PlatformGradient;
+#endif
+
#elif PLATFORM(QT)
QT_BEGIN_NAMESPACE
class QGradient;
@@ -79,7 +86,7 @@ namespace WebCore {
void getColor(float value, float* r, float* g, float* b, float* a) const;
-#if PLATFORM(WINCE) && !PLATFORM(QT)
+#if OS(WINCE) && !PLATFORM(QT)
const FloatPoint& p0() const { return m_p0; }
const FloatPoint& p1() const { return m_p1; }
float r0() const { return m_r0; }
@@ -105,7 +112,7 @@ namespace WebCore {
};
void setStopsSorted(bool s) { m_stopsSorted = s; }
-
+
void setSpreadMethod(GradientSpreadMethod);
GradientSpreadMethod spreadMethod() { return m_spreadMethod; }
void setGradientSpaceTransform(const TransformationMatrix& gradientSpaceTransformation);
@@ -113,8 +120,13 @@ namespace WebCore {
TransformationMatrix gradientSpaceTransform() { return m_gradientSpaceTransformation; }
virtual void fill(GraphicsContext*, const FloatRect&);
+ virtual void adjustParametersForTiledDrawing(IntSize& size, FloatRect& srcRect);
+
void setPlatformGradientSpaceTransform(const TransformationMatrix& gradientSpaceTransformation);
+#if PLATFORM(CG)
+ void paint(GraphicsContext*);
+#endif
private:
Gradient(const FloatPoint& p0, const FloatPoint& p1);
Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1);
@@ -123,6 +135,7 @@ namespace WebCore {
void platformDestroy();
int findStop(float value) const;
+ void sortStopsIfNecessary();
bool m_radial;
FloatPoint m_p0;
diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp
index e80004f..eac8bcd 100644
--- a/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 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
@@ -10,17 +10,17 @@
* 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.
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -328,7 +328,7 @@ void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const
drawImage(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale);
}
-#if !PLATFORM(WINCE) || PLATFORM(QT)
+#if !OS(WINCE) || PLATFORM(QT)
void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to)
{
if (paintingDisabled())
@@ -382,55 +382,6 @@ void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run,
fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace);
}
-void GraphicsContext::initFocusRing(int width, int offset)
-{
- if (paintingDisabled())
- return;
- clearFocusRing();
-
- m_common->m_focusRingWidth = width;
- m_common->m_focusRingOffset = offset;
-}
-
-void GraphicsContext::clearFocusRing()
-{
- m_common->m_focusRingRects.clear();
-}
-
-IntRect GraphicsContext::focusRingBoundingRect()
-{
- IntRect result = IntRect(0, 0, 0, 0);
-
- const Vector<IntRect>& rects = focusRingRects();
- unsigned rectCount = rects.size();
- for (unsigned i = 0; i < rectCount; i++)
- result.unite(rects[i]);
-
- return result;
-}
-
-void GraphicsContext::addFocusRingRect(const IntRect& rect)
-{
- if (paintingDisabled() || rect.isEmpty())
- return;
- m_common->m_focusRingRects.append(rect);
-}
-
-int GraphicsContext::focusRingWidth() const
-{
- return m_common->m_focusRingWidth;
-}
-
-int GraphicsContext::focusRingOffset() const
-{
- return m_common->m_focusRingOffset;
-}
-
-const Vector<IntRect>& GraphicsContext::focusRingRects() const
-{
- return m_common->m_focusRingRects;
-}
-
void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
{
if (paintingDisabled() || !image)
@@ -460,24 +411,35 @@ void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const
restore();
}
-void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op)
+void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale)
{
if (paintingDisabled() || !image)
return;
-
+ if (useLowQualityScale) {
+ save();
+ setImageInterpolationQuality(InterpolationLow);
+ }
image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
+ if (useLowQualityScale)
+ restore();
}
-void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op)
+void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
{
if (paintingDisabled() || !image)
return;
+ if (useLowQualityScale) {
+ save();
+ setImageInterpolationQuality(InterpolationLow);
+ }
if (hRule == Image::StretchTile && vRule == Image::StretchTile)
// Just do a scale.
- return drawImage(image, styleColorSpace, dest, srcRect, op);
-
- image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
+ drawImage(image, styleColorSpace, dest, srcRect, op);
+ else
+ image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
+ if (useLowQualityScale)
+ restore();
}
void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
@@ -544,7 +506,11 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode)
}
#endif
+<<<<<<< HEAD
#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(HAIKU)
+=======
+#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG)
+>>>>>>> webkit.org at r54127
void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&)
{
}
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index ecf2101..063c490 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -41,6 +41,11 @@
typedef struct CGContext PlatformGraphicsContext;
#elif PLATFORM(CAIRO)
typedef struct _cairo PlatformGraphicsContext;
+#elif PLATFORM(OPENVG)
+namespace WebCore {
+class SurfaceOpenVG;
+}
+typedef class WebCore::SurfaceOpenVG PlatformGraphicsContext;
#elif PLATFORM(QT)
QT_BEGIN_NAMESPACE
class QPainter;
@@ -79,7 +84,7 @@ typedef class PlatformContextSkia PlatformGraphicsContext;
class BView;
typedef BView PlatformGraphicsContext;
struct pattern;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
typedef struct HDC__ PlatformGraphicsContext;
#else
typedef void PlatformGraphicsContext;
@@ -104,7 +109,7 @@ typedef unsigned char UInt8;
namespace WebCore {
-#if PLATFORM(WINCE) && !PLATFORM(QT)
+#if OS(WINCE) && !PLATFORM(QT)
class SharedBitmap;
class SimpleFontData;
class GlyphBuffer;
@@ -152,7 +157,7 @@ namespace WebCore {
GraphicsContext(PlatformGraphicsContext*);
~GraphicsContext();
-#if !PLATFORM(WINCE) || PLATFORM(QT)
+#if !OS(WINCE) || PLATFORM(QT)
PlatformGraphicsContext* platformContext() const;
#endif
@@ -255,10 +260,10 @@ namespace WebCore {
void drawImage(Image*, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1),
CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize,
- CompositeOperator = CompositeSourceOver);
+ CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect,
Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile,
- CompositeOperator = CompositeSourceOver);
+ CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
void setImageInterpolationQuality(InterpolationQuality);
InterpolationQuality imageInterpolationQuality() const;
@@ -297,11 +302,8 @@ namespace WebCore {
bool getShadow(IntSize&, int&, Color&) const;
void clearShadow();
- void initFocusRing(int width, int offset);
- void addFocusRingRect(const IntRect&);
- void drawFocusRing(const Color&);
- void clearFocusRing();
- IntRect focusRingBoundingRect();
+ void drawFocusRing(const Vector<IntRect>&, int width, int offset, const Color&);
+ void drawFocusRing(const Vector<Path>&, int width, int offset, const Color&);
void setLineCap(LineCap);
void setLineDash(const DashArray&, float dashOffset);
@@ -330,6 +332,7 @@ namespace WebCore {
void scale(const FloatSize&);
void rotate(float angleInRadians);
+ void translate(const FloatSize& size) { translate(size.width(), size.height()); }
void translate(float x, float y);
IntPoint origin();
@@ -338,7 +341,7 @@ namespace WebCore {
void concatCTM(const TransformationMatrix&);
TransformationMatrix getCTM() const;
-#if PLATFORM(WINCE) && !PLATFORM(QT)
+#if OS(WINCE) && !PLATFORM(QT)
void setBitmap(PassRefPtr<SharedBitmap>);
const TransformationMatrix& affineTransform() const;
TransformationMatrix& affineTransform();
@@ -396,7 +399,7 @@ namespace WebCore {
void drawWindowsBitmap(WindowsBitmap*, const IntPoint&);
#endif
-#if (PLATFORM(QT) && defined(Q_WS_WIN)) || (PLATFORM(WX) && PLATFORM(WIN_OS))
+#if (PLATFORM(QT) && defined(Q_WS_WIN)) || (PLATFORM(WX) && OS(WINDOWS))
HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true);
void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true);
bool shouldIncludeChildWindows() const { return false; }
@@ -446,10 +449,6 @@ namespace WebCore {
static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle&);
- int focusRingWidth() const;
- int focusRingOffset() const;
- const Vector<IntRect>& focusRingRects() const;
-
static GraphicsContextPrivate* createGraphicsContextPrivate();
static void destroyGraphicsContextPrivate(GraphicsContextPrivate*);
diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h
index aad8dd4..d7406c9 100644
--- a/WebCore/platform/graphics/GraphicsContext3D.h
+++ b/WebCore/platform/graphics/GraphicsContext3D.h
@@ -33,7 +33,7 @@
#include <wtf/PassOwnPtr.h>
// FIXME: Find a better way to avoid the name confliction for NO_ERROR.
-#if PLATFORM(CHROMIUM) && PLATFORM(WIN_OS)
+#if PLATFORM(CHROMIUM) && OS(WINDOWS)
#undef NO_ERROR
#endif
@@ -65,9 +65,6 @@ namespace WebCore {
class WebGLShader;
class WebGLTexture;
class Image;
- class HTMLVideoElement;
- class ImageData;
- class WebKitCSSMatrix;
struct ActiveInfo {
String name;
@@ -385,7 +382,25 @@ namespace WebCore {
INVALID_FRAMEBUFFER_OPERATION = 0x0506
};
- static PassOwnPtr<GraphicsContext3D> create();
+ // Context creation attributes.
+ struct Attributes {
+ Attributes()
+ : alpha(true)
+ , depth(true)
+ , stencil(true)
+ , antialias(true)
+ , premultipliedAlpha(true)
+ {
+ }
+
+ bool alpha;
+ bool depth;
+ bool stencil;
+ bool antialias;
+ bool premultipliedAlpha;
+ };
+
+ static PassOwnPtr<GraphicsContext3D> create(Attributes attrs);
virtual ~GraphicsContext3D();
#if PLATFORM(MAC)
@@ -462,6 +477,8 @@ namespace WebCore {
void getBufferParameteriv(unsigned long target, unsigned long pname, int* value);
+ Attributes getContextAttributes();
+
unsigned long getError();
void getFloatv(unsigned long pname, float* value);
@@ -528,32 +545,14 @@ namespace WebCore {
// These next several functions return an error code (0 if no errors) rather than using an ExceptionCode.
// Currently they return -1 on any error.
- int texImage2D(unsigned target, unsigned level, unsigned internalformat,
- unsigned width, unsigned height, unsigned border,
- unsigned format, unsigned type, WebGLArray* pixels);
- int texImage2D(unsigned target, unsigned level, unsigned internalformat,
- unsigned width, unsigned height, unsigned border,
- unsigned format, unsigned type, ImageData* pixels);
- int texImage2D(unsigned target, unsigned level, Image* image,
- bool flipY, bool premultiplyAlpha);
- int texImage2D(unsigned target, unsigned level, HTMLVideoElement* video,
- bool flipY, bool premultiplyAlpha);
+ int texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels);
+ int texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha);
void texParameterf(unsigned target, unsigned pname, float param);
void texParameteri(unsigned target, unsigned pname, int param);
- int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- unsigned width, unsigned height,
- unsigned format, unsigned type, WebGLArray* pixels);
- int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- unsigned width, unsigned height,
- unsigned format, unsigned type, ImageData* pixels);
- int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- unsigned width, unsigned height, Image* image,
- bool flipY, bool premultiplyAlpha);
- int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- unsigned width, unsigned height, HTMLVideoElement* video,
- bool flipY, bool premultiplyAlpha);
+ int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, unsigned format, unsigned type, void* pixels);
+ int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, Image* image, bool flipY, bool premultiplyAlpha);
void uniform1f(long location, float x);
void uniform1fv(long location, float* v, int size);
@@ -623,11 +622,12 @@ namespace WebCore {
void synthesizeGLError(unsigned long error);
private:
- GraphicsContext3D();
+ GraphicsContext3D(Attributes attrs);
int m_currentWidth, m_currentHeight;
#if PLATFORM(MAC)
+ Attributes m_attrs;
Vector<Vector<float> > m_vertexArray;
CGLContextObj m_contextObj;
diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h
index c532162..1980337 100644
--- a/WebCore/platform/graphics/GraphicsContextPrivate.h
+++ b/WebCore/platform/graphics/GraphicsContextPrivate.h
@@ -48,7 +48,7 @@ namespace WebCore {
, shadowBlur(0)
, shadowsIgnoreTransforms(false)
#if PLATFORM(CAIRO)
- , globalAlpha(1.0f)
+ , globalAlpha(1)
#endif
{
}
@@ -87,17 +87,12 @@ namespace WebCore {
class GraphicsContextPrivate : public Noncopyable {
public:
GraphicsContextPrivate()
- : m_focusRingWidth(0)
- , m_focusRingOffset(0)
- , m_updatingControlTints(false)
+ : m_updatingControlTints(false)
{
}
GraphicsContextState state;
Vector<GraphicsContextState> stack;
- Vector<IntRect> m_focusRingRects;
- int m_focusRingWidth;
- int m_focusRingOffset;
bool m_updatingControlTints;
};
diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp
index e215097..2336d0b 100644
--- a/WebCore/platform/graphics/GraphicsLayer.cpp
+++ b/WebCore/platform/graphics/GraphicsLayer.cpp
@@ -72,6 +72,8 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
, m_contentsOrientation(CompositingCoordinatesTopDown)
, m_parent(0)
, m_maskLayer(0)
+ , m_replicaLayer(0)
+ , m_replicatedLayer(0)
, m_repaintCount(0)
{
}
@@ -214,6 +216,14 @@ void GraphicsLayer::removeFromParent()
}
}
+void GraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
+{
+ if (layer)
+ layer->setReplicatedLayer(this);
+
+ m_replicaLayer = layer;
+}
+
void GraphicsLayer::setBackgroundColor(const Color& color)
{
m_backgroundColor = color;
@@ -454,14 +464,27 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent) const
}
ts << ")\n";
- writeIndent(ts, indent + 1);
- ts << "(children " << m_children.size() << "\n";
+ if (m_replicaLayer) {
+ writeIndent(ts, indent + 1);
+ ts << "(replica layer " << m_replicaLayer << ")\n";
+ m_replicaLayer->dumpLayer(ts, indent+2);
+ }
+
+ if (m_replicatedLayer) {
+ writeIndent(ts, indent + 1);
+ ts << "(replicated layer " << m_replicatedLayer << ")\n";
+ }
- unsigned i;
- for (i = 0; i < m_children.size(); i++)
- m_children[i]->dumpLayer(ts, indent+2);
- writeIndent(ts, indent + 1);
- ts << ")\n";
+ if (m_children.size()) {
+ writeIndent(ts, indent + 1);
+ ts << "(children " << m_children.size() << "\n";
+
+ unsigned i;
+ for (i = 0; i < m_children.size(); i++)
+ m_children[i]->dumpLayer(ts, indent+2);
+ writeIndent(ts, indent + 1);
+ ts << ")\n";
+ }
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h
index 0456bad..844301e 100644
--- a/WebCore/platform/graphics/GraphicsLayer.h
+++ b/WebCore/platform/graphics/GraphicsLayer.h
@@ -59,6 +59,10 @@ class WKCACFLayer;
typedef WKCACFLayer PlatformLayer;
typedef void* NativeLayer;
}
+#elif PLATFORM(QT)
+class QGraphicsItem;
+typedef QGraphicsItem PlatformLayer;
+typedef QGraphicsItem* NativeLayer;
#else
typedef void* PlatformLayer;
typedef void* NativeLayer;
@@ -198,6 +202,16 @@ public:
GraphicsLayer* maskLayer() const { return m_maskLayer; }
virtual void setMaskLayer(GraphicsLayer* layer) { m_maskLayer = layer; }
+ // The given layer will replicate this layer and its children; the replica renders behind this layer.
+ virtual void setReplicatedByLayer(GraphicsLayer*);
+ // Whether this layer is being replicated by another layer.
+ bool isReplicated() const { return m_replicaLayer; }
+ // The layer that replicates this layer (if any).
+ GraphicsLayer* replicaLayer() const { return m_replicaLayer; }
+
+ const FloatPoint& replicatedLayerPosition() const { return m_replicatedLayerPosition; }
+ void setReplicatedLayerPosition(const FloatPoint& p) { m_replicatedLayerPosition = p; }
+
// Offset is origin of the renderer minus origin of the graphics layer (so either zero or negative).
IntSize offsetFromRenderer() const { return m_offsetFromRenderer; }
void setOffsetFromRenderer(const IntSize& offset) { m_offsetFromRenderer = offset; }
@@ -260,17 +274,17 @@ public:
// Return true if the animation is handled by the compositing system. If this returns
// false, the animation will be run by AnimationController.
- virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*keyframesName*/, double /*beginTime*/) { return false; }
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*keyframesName*/, double /*timeOffset*/) { return false; }
virtual void removeAnimationsForProperty(AnimatedPropertyID) { }
virtual void removeAnimationsForKeyframes(const String& /* keyframesName */) { }
- virtual void pauseAnimation(const String& /* keyframesName */) { }
+ virtual void pauseAnimation(const String& /* keyframesName */, double /*timeOffset*/) { }
virtual void suspendAnimations(double time);
virtual void resumeAnimations();
// Layer contents
virtual void setContentsToImage(Image*) { }
- virtual void setContentsToVideo(PlatformLayer*) { }
+ virtual void setContentsToMedia(PlatformLayer*) { } // video or plug-in
virtual void setContentsBackgroundColor(const Color&) { }
#if ENABLE(3D_CANVAS)
@@ -279,6 +293,8 @@ public:
#endif
// Callback from the underlying graphics system to draw layer contents.
void paintGraphicsLayerContents(GraphicsContext&, const IntRect& clip);
+ // Callback from the underlying graphics system when the layer has been displayed
+ virtual void didDisplay(PlatformLayer*) { }
virtual PlatformLayer* platformLayer() const { return 0; }
@@ -327,6 +343,10 @@ protected:
virtual void setOpacityInternal(float) { }
+ // The layer being replicated.
+ GraphicsLayer* replicatedLayer() const { return m_replicatedLayer; }
+ virtual void setReplicatedLayer(GraphicsLayer* layer) { m_replicatedLayer = layer; }
+
GraphicsLayer(GraphicsLayerClient*);
void dumpProperties(TextStream&, int indent) const;
@@ -365,6 +385,11 @@ protected:
GraphicsLayer* m_maskLayer; // Reference to mask layer. We don't own this.
+ GraphicsLayer* m_replicaLayer; // A layer that replicates this layer. We only allow one, for now.
+ // The replica is not parented; this is the primary reference to it.
+ GraphicsLayer* m_replicatedLayer; // For a replica layer, a reference to the original layer.
+ FloatPoint m_replicatedLayerPosition; // For a replica layer, the position of the replica.
+
IntRect m_contentsRect;
int m_repaintCount;
diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h
index f25169b..234104a 100644
--- a/WebCore/platform/graphics/Image.h
+++ b/WebCore/platform/graphics/Image.h
@@ -154,6 +154,7 @@ public:
#if PLATFORM(GTK)
virtual GdkPixbuf* getGdkPixbuf() { return 0; }
+ static PassRefPtr<Image> loadPlatformThemeIcon(const char* name, int size);
#endif
protected:
diff --git a/WebCore/platform/graphics/ImageSource.cpp b/WebCore/platform/graphics/ImageSource.cpp
index bf7ae21..c2366c1 100644
--- a/WebCore/platform/graphics/ImageSource.cpp
+++ b/WebCore/platform/graphics/ImageSource.cpp
@@ -35,12 +35,6 @@
#include "ImageDecoder.h"
#endif
-#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
-#ifndef IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS
-#define IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS (1024 * 1024)
-#endif
-#endif
-
namespace WebCore {
ImageSource::ImageSource()
@@ -81,6 +75,9 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
if (!m_decoder) {
m_decoder = static_cast<NativeImageSourcePtr>(ImageDecoder::create(*data));
#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
+#ifndef IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS
+#define IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS (1024 * 1024)
+#endif
if (m_decoder)
m_decoder->setMaxNumPixels(IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS);
#endif
diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h
index 083c7b0..cc40f5e 100644
--- a/WebCore/platform/graphics/ImageSource.h
+++ b/WebCore/platform/graphics/ImageSource.h
@@ -55,7 +55,7 @@ class NativeImageSkia;
#endif
#elif PLATFORM(HAIKU)
class BBitmap;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
#include "SharedBitmap.h"
#endif
@@ -105,7 +105,7 @@ typedef wxBitmap* NativeImagePtr;
typedef cairo_surface_t* NativeImagePtr;
#elif PLATFORM(HAIKU)
typedef BBitmap* NativeImagePtr;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
typedef RefPtr<SharedBitmap> NativeImagePtr;
#endif
#endif
diff --git a/WebCore/platform/graphics/IntRect.cpp b/WebCore/platform/graphics/IntRect.cpp
index 622e525..188b5f9 100644
--- a/WebCore/platform/graphics/IntRect.cpp
+++ b/WebCore/platform/graphics/IntRect.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 2006, 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
@@ -10,17 +10,17 @@
* 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.
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -104,4 +104,15 @@ void IntRect::scale(float s)
m_size.setHeight((int)(height() * s));
}
+IntRect unionRect(const Vector<IntRect>& rects)
+{
+ IntRect result;
+
+ size_t count = rects.size();
+ for (size_t i = 0; i < count; ++i)
+ result.unite(rects[i]);
+
+ return result;
}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h
index 97b21bc..e3633df 100644
--- a/WebCore/platform/graphics/IntRect.h
+++ b/WebCore/platform/graphics/IntRect.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2003, 2006, 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
@@ -10,17 +10,17 @@
* 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.
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef IntRect_h
@@ -28,12 +28,13 @@
#include "IntPoint.h"
#include <wtf/Platform.h>
+#include <wtf/Vector.h>
#if PLATFORM(CG)
typedef struct CGRect CGRect;
#endif
-#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
typedef struct CGRect NSRect;
#else
@@ -162,7 +163,7 @@ public:
#endif
#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
- || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
operator NSRect() const;
#endif
@@ -185,6 +186,8 @@ inline IntRect unionRect(const IntRect& a, const IntRect& b)
return c;
}
+IntRect unionRect(const Vector<IntRect>&);
+
inline bool operator==(const IntRect& a, const IntRect& b)
{
return a.location() == b.location() && a.size() == b.size();
@@ -200,7 +203,7 @@ IntRect enclosingIntRect(const CGRect&);
#endif
#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \
- || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+ || (PLATFORM(CHROMIUM) && OS(DARWIN))
IntRect enclosingIntRect(const NSRect&);
#endif
diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h
index b242784..13d9e22 100644
--- a/WebCore/platform/graphics/IntSize.h
+++ b/WebCore/platform/graphics/IntSize.h
@@ -69,7 +69,8 @@ public:
void setHeight(int height) { m_height = height; }
bool isEmpty() const { return m_width <= 0 || m_height <= 0; }
-
+ bool isZero() const { return !m_width && !m_height; }
+
void expand(int width, int height)
{
m_width += width;
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
index 4c66c50..aed9c95 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * 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
@@ -39,7 +39,7 @@
#if PLATFORM(MAC)
#include "MediaPlayerPrivateQTKit.h"
-#elif PLATFORM(WINCE) && !PLATFORM(QT)
+#elif OS(WINCE) && !PLATFORM(QT)
#include "MediaPlayerPrivateWince.h"
#elif PLATFORM(WIN)
#include "MediaPlayerPrivateQuickTimeWin.h"
@@ -83,8 +83,6 @@ public:
virtual void seek(float) { }
virtual bool seeking() const { return false; }
- virtual void setEndTime(float) { }
-
virtual void setRate(float) { }
virtual void setPreservesPitch(bool) { }
virtual bool paused() const { return false; }
@@ -100,9 +98,6 @@ public:
virtual float maxTimeSeekable() const { return 0; }
virtual PassRefPtr<TimeRanges> buffered() const { return TimeRanges::create(); }
- virtual int dataRate() const { return 0; }
-
- virtual bool totalBytesKnown() const { return false; }
virtual unsigned totalBytes() const { return 0; }
virtual unsigned bytesLoaded() const { return 0; }
@@ -252,7 +247,8 @@ void MediaPlayer::load(const String& url, const ContentType& contentType)
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
m_private->setMediaPlayerProxy(m_playerProxy);
#endif
-
+ m_private->setAutobuffer(autobuffer());
+ m_private->setPreservesPitch(preservesPitch());
}
if (m_private)
@@ -261,6 +257,11 @@ void MediaPlayer::load(const String& url, const ContentType& contentType)
m_private.set(createNullMediaPlayer(this));
}
+bool MediaPlayer::hasAvailableVideoFrame() const
+{
+ return m_private->hasAvailableVideoFrame();
+}
+
bool MediaPlayer::canLoadPoster() const
{
return m_private->canLoadPoster();
@@ -412,16 +413,6 @@ void MediaPlayer::setPreservesPitch(bool preservesPitch)
m_private->setPreservesPitch(preservesPitch);
}
-int MediaPlayer::dataRate() const
-{
- return m_private->dataRate();
-}
-
-void MediaPlayer::setEndTime(float time)
-{
- m_private->setEndTime(time);
-}
-
PassRefPtr<TimeRanges> MediaPlayer::buffered()
{
return m_private->buffered();
@@ -437,16 +428,6 @@ unsigned MediaPlayer::bytesLoaded()
return m_private->bytesLoaded();
}
-bool MediaPlayer::totalBytesKnown()
-{
- return m_private->totalBytesKnown();
-}
-
-unsigned MediaPlayer::totalBytes()
-{
- return m_private->totalBytes();
-}
-
void MediaPlayer::setSize(const IntSize& size)
{
m_size = size;
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index ec8ac33..fa85cfd 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * 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
@@ -163,8 +163,6 @@ public:
float startTime() const;
- void setEndTime(float time);
-
float rate() const;
void setRate(float);
@@ -175,8 +173,6 @@ public:
float maxTimeSeekable();
unsigned bytesLoaded();
- bool totalBytesKnown();
- unsigned totalBytes();
float volume() const;
void setVolume(float);
@@ -184,8 +180,6 @@ public:
bool hasClosedCaptions() const;
void setClosedCaptionsVisible(bool closedCaptionsVisible);
- int dataRate() const;
-
bool autobuffer() const;
void setAutobuffer(bool);
@@ -213,6 +207,8 @@ public:
MediaPlayerClient* mediaPlayerClient() const { return m_mediaPlayerClient; }
+ bool hasAvailableVideoFrame() const;
+
bool canLoadPoster() const;
void setPoster(const String&);
diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h
index 03906bd..6cf12ba 100644
--- a/WebCore/platform/graphics/MediaPlayerPrivate.h
+++ b/WebCore/platform/graphics/MediaPlayerPrivate.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -67,8 +67,6 @@ public:
virtual float startTime() const { return 0; }
- virtual void setEndTime(float) = 0;
-
virtual void setRate(float) = 0;
virtual void setPreservesPitch(bool) { }
@@ -85,10 +83,6 @@ public:
virtual float maxTimeSeekable() const = 0;
virtual PassRefPtr<TimeRanges> buffered() const = 0;
- virtual int dataRate() const = 0;
-
- virtual bool totalBytesKnown() const { return totalBytes() > 0; }
- virtual unsigned totalBytes() const = 0;
virtual unsigned bytesLoaded() const = 0;
virtual void setSize(const IntSize&) = 0;
@@ -99,6 +93,8 @@ public:
virtual void setAutobuffer(bool) { };
+ virtual bool hasAvailableVideoFrame() const { return readyState() >= MediaPlayer::HaveCurrentData; }
+
virtual bool canLoadPoster() const { return false; }
virtual void setPoster(const String&) { }
diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h
index 6618fb7..79d6cc4 100644
--- a/WebCore/platform/graphics/Path.h
+++ b/WebCore/platform/graphics/Path.h
@@ -34,10 +34,7 @@
#if PLATFORM(CG)
typedef struct CGPath PlatformPath;
#elif PLATFORM(QT)
-#include <qglobal.h>
-QT_BEGIN_NAMESPACE
-class QPainterPath;
-QT_END_NAMESPACE
+#include <qpainterpath.h>
typedef QPainterPath PlatformPath;
#elif PLATFORM(WX) && USE(WXGC)
class wxGraphicsPath;
@@ -53,7 +50,7 @@ typedef SkPath PlatformPath;
#elif PLATFORM(HAIKU)
class BRegion;
typedef BRegion PlatformPath;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
namespace WebCore {
class PlatformPath;
}
@@ -61,6 +58,13 @@ namespace WebCore {
typedef void PlatformPath;
#endif
+#if PLATFORM(QT)
+/* QPainterPath is valued based */
+typedef PlatformPath PlatformPathPtr;
+#else
+typedef PlatformPath* PlatformPathPtr;
+#endif
+
namespace WebCore {
class FloatPoint;
@@ -131,7 +135,7 @@ namespace WebCore {
String debugString() const;
- PlatformPath* platformPath() const { return m_path; }
+ PlatformPathPtr platformPath() const { return m_path; }
static Path createRoundedRectangle(const FloatRect&, const FloatSize& roundingRadii);
static Path createRoundedRectangle(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius);
@@ -144,7 +148,7 @@ namespace WebCore {
void transform(const TransformationMatrix&);
private:
- PlatformPath* m_path;
+ PlatformPathPtr m_path;
};
}
diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h
index aa0a357..f7f612a 100644
--- a/WebCore/platform/graphics/Pattern.h
+++ b/WebCore/platform/graphics/Pattern.h
@@ -56,7 +56,7 @@ typedef wxBrush* PlatformPatternPtr;
#elif PLATFORM(HAIKU)
#include <interface/GraphicsDefs.h>
typedef pattern* PlatformPatternPtr;
-#elif PLATFORM(WINCE)
+#elif OS(WINCE)
typedef void* PlatformPatternPtr;
#endif
diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h
index 387a5c7..09ed0fc 100644
--- a/WebCore/platform/graphics/SimpleFontData.h
+++ b/WebCore/platform/graphics/SimpleFontData.h
@@ -28,14 +28,14 @@
#include "FontPlatformData.h"
#include "GlyphPageTreeNode.h"
#include "GlyphWidthMap.h"
-#include "TextRenderingMode.h"
+#include "TypesettingFeatures.h"
#include <wtf/OwnPtr.h>
#if USE(ATSUI)
typedef struct OpaqueATSUStyle* ATSUStyle;
#endif
-#if PLATFORM(WIN) && !PLATFORM(WINCE)
+#if PLATFORM(WIN) && !OS(WINCE)
#include <usp10.h>
#endif
@@ -115,13 +115,13 @@ public:
virtual String description() const;
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
NSFont* getNSFont() const { return m_platformData.font(); }
#endif
#if USE(CORE_TEXT)
CTFontRef getCTFont() const;
- CFDictionaryRef getCFStringAttributes(TextRenderingMode) const;
+ CFDictionaryRef getCFStringAttributes(TypesettingFeatures) const;
#endif
#if USE(ATSUI)
@@ -140,7 +140,7 @@ public:
#if PLATFORM(WIN)
bool isSystemFont() const { return m_isSystemFont; }
-#if !PLATFORM(WINCE) // disable unused members to save space
+#if !OS(WINCE) // disable unused members to save space
SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; }
#endif
@@ -162,7 +162,7 @@ private:
void commonInit();
-#if PLATFORM(WIN) && !PLATFORM(WINCE)
+#if PLATFORM(WIN) && !OS(WINCE)
void initGDIFont();
void platformCommonDestroy();
float widthForGDIGlyph(Glyph glyph) const;
@@ -211,8 +211,7 @@ private:
#if USE(ATSUI)
public:
- mutable ATSUStyle m_ATSUStyle;
- mutable bool m_ATSUStyleInitialized;
+ mutable HashMap<unsigned, ATSUStyle> m_ATSUStyleMap;
mutable bool m_ATSUMirrors;
mutable bool m_checkedShapesArabic;
mutable bool m_shapesArabic;
@@ -222,12 +221,12 @@ private:
#if USE(CORE_TEXT)
mutable RetainPtr<CTFontRef> m_CTFont;
- mutable RetainPtr<CFDictionaryRef> m_CFStringAttributes;
+ mutable HashMap<unsigned, RetainPtr<CFDictionaryRef> > m_CFStringAttributes;
#endif
#if PLATFORM(WIN)
bool m_isSystemFont;
-#if !PLATFORM(WINCE) // disable unused members to save space
+#if !OS(WINCE) // disable unused members to save space
mutable SCRIPT_CACHE m_scriptCache;
mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
#endif
diff --git a/WebCore/platform/graphics/TypesettingFeatures.h b/WebCore/platform/graphics/TypesettingFeatures.h
new file mode 100644
index 0000000..aa46beb
--- /dev/null
+++ b/WebCore/platform/graphics/TypesettingFeatures.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TypesettingFeatures_h
+#define TypesettingFeatures_h
+
+namespace WebCore {
+ enum TypesettingFeature {
+ Kerning = 1 << 0,
+ Ligatures = 1 << 1,
+ };
+
+ typedef unsigned TypesettingFeatures;
+} // namespace WebCore
+
+#endif // TypesettingFeatures_h
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index 14034fd..d866b6c 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -606,12 +606,16 @@ void GraphicsContext::clipPath(WindRule clipRule)
cairo_clip(cr);
}
-void GraphicsContext::drawFocusRing(const Color& color)
+void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color)
{
if (paintingDisabled())
return;
- const Vector<IntRect>& rects = focusRingRects();
unsigned rectCount = rects.size();
cairo_t* cr = m_data->cr;
@@ -632,14 +636,14 @@ void GraphicsContext::drawFocusRing(const Color& color)
cairo_set_line_width(cr, 2.0f);
setPlatformStrokeStyle(DottedStroke);
#else
- int radius = (focusRingWidth() - 1) / 2;
+ int radius = (width - 1) / 2;
for (unsigned i = 0; i < rectCount; i++)
addPath(Path::createRoundedRectangle(rects[i], FloatSize(radius, radius)));
// Force the alpha to 50%. This matches what the Mac does with outline rings.
Color ringColor(color.red(), color.green(), color.blue(), 127);
setColor(cr, ringColor);
- cairo_set_line_width(cr, focusRingWidth());
+ cairo_set_line_width(cr, width);
setPlatformStrokeStyle(SolidStroke);
#endif
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
index 54e1217..cedc684 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -33,8 +33,8 @@
#include <wtf/MathExtras.h>
#if PLATFORM(GTK)
-#include <gdk/gdk.h>
#include <pango/pango.h>
+typedef struct _GdkExposeEvent GdkExposeEvent;
#elif PLATFORM(WIN)
#include <cairo-win32.h>
#endif
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index d991c80..124c7cf 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -132,7 +132,7 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
pixelColor = Color(lookUpTable[pixelColor.red()],
lookUpTable[pixelColor.green()],
lookUpTable[pixelColor.blue()],
- lookUpTable[pixelColor.alpha()]);
+ pixelColor.alpha());
*pixel = premultipliedARGBFromColor(pixelColor);
}
}
diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp
index 40aacc5..e514fa3 100644
--- a/WebCore/platform/graphics/cg/ColorCG.cpp
+++ b/WebCore/platform/graphics/cg/ColorCG.cpp
@@ -68,7 +68,7 @@ Color::Color(CGColorRef color)
m_color = makeRGBA(r * 255, g * 255, b * 255, a * 255);
}
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
CGColorRef createCGColor(const Color& c)
{
@@ -89,7 +89,7 @@ CGColorRef createCGColor(const Color& c)
return color;
}
-#endif // PLATFORM(WIN_OS)
+#endif // OS(WINDOWS)
}
diff --git a/WebCore/platform/graphics/cg/GradientCG.cpp b/WebCore/platform/graphics/cg/GradientCG.cpp
index 05a0aad..e9b5de7 100644
--- a/WebCore/platform/graphics/cg/GradientCG.cpp
+++ b/WebCore/platform/graphics/cg/GradientCG.cpp
@@ -36,10 +36,15 @@ namespace WebCore {
void Gradient::platformDestroy()
{
+#ifdef BUILDING_ON_TIGER
CGShadingRelease(m_gradient);
+#else
+ CGGradientRelease(m_gradient);
+#endif
m_gradient = 0;
}
+#ifdef BUILDING_ON_TIGER
static void gradientCallback(void* info, const CGFloat* in, CGFloat* out)
{
float r, g, b, a;
@@ -69,11 +74,55 @@ CGShadingRef Gradient::platformGradient()
return m_gradient;
}
+#else
+CGGradientRef Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+
+ sortStopsIfNecessary();
+
+ const int cReservedStops = 3;
+ Vector<CGFloat, 4 * cReservedStops> colorComponents;
+ colorComponents.reserveCapacity(m_stops.size() * 4); // RGBA components per stop
+
+ Vector<CGFloat, cReservedStops> locations;
+ locations.reserveCapacity(m_stops.size());
+
+ for (size_t i = 0; i < m_stops.size(); ++i) {
+ colorComponents.uncheckedAppend(m_stops[i].red);
+ colorComponents.uncheckedAppend(m_stops[i].green);
+ colorComponents.uncheckedAppend(m_stops[i].blue);
+ colorComponents.uncheckedAppend(m_stops[i].alpha);
+
+ locations.uncheckedAppend(m_stops[i].stop);
+ }
+
+ m_gradient = CGGradientCreateWithColorComponents(colorSpace, colorComponents.data(), locations.data(), m_stops.size());
+
+ return m_gradient;
+}
+#endif
void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
{
context->clip(rect);
+ paint(context);
+}
+
+void Gradient::paint(GraphicsContext* context)
+{
+#ifdef BUILDING_ON_TIGER
CGContextDrawShading(context->platformContext(), platformGradient());
+#else
+ CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
+ if (m_radial)
+ CGContextDrawRadialGradient(context->platformContext(), platformGradient(), m_p0, m_r0, m_p1, m_r1, extendOptions);
+ else
+ CGContextDrawLinearGradient(context->platformContext(), platformGradient(), m_p0, m_p1, extendOptions);
+#endif
}
} //namespace
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
index 39f06a6..b11ba66 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -43,7 +43,15 @@
#include <wtf/OwnArrayPtr.h>
#include <wtf/RetainPtr.h>
-#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN))
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+#include "WebCoreSystemInterface.h"
+#endif
+
+#if PLATFORM(WIN)
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN))
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
// Building on 10.6 or later: kCGInterpolationMedium is defined in the CGInterpolationQuality enum.
@@ -490,7 +498,7 @@ static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPat
}
} else {
// Setting mode to kCGPathStroke even if shouldStroke is false. In that case, we return false and mode will not be used,
- // but the compiler will not compain about an uninitialized variable.
+ // but the compiler will not complain about an uninitialized variable.
mode = kCGPathStroke;
}
@@ -547,7 +555,7 @@ void GraphicsContext::fillPath()
else
CGContextClip(context);
CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform());
- CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
+ m_common->state.fillGradient->paint(this);
CGContextRestoreGState(context);
return;
}
@@ -572,7 +580,7 @@ void GraphicsContext::strokePath()
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
CGContextConcatCTM(context, m_common->state.strokeGradient->gradientSpaceTransform());
- CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient());
+ m_common->state.strokeGradient->paint(this);
CGContextRestoreGState(context);
return;
}
@@ -596,7 +604,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
CGContextSaveGState(context);
CGContextClipToRect(context, rect);
CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform());
- CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
+ m_common->state.fillGradient->paint(this);
CGContextRestoreGState(context);
return;
}
@@ -739,56 +747,55 @@ void GraphicsContext::endTransparencyLayer()
m_data->m_userToDeviceTransformKnownToBeIdentity = false;
}
-void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace)
+void GraphicsContext::setPlatformShadow(const IntSize& offset, int blur, const Color& color, ColorSpace colorSpace)
{
if (paintingDisabled())
return;
- CGFloat width = size.width();
- CGFloat height = size.height();
+ CGFloat xOffset = offset.width();
+ CGFloat yOffset = offset.height();
CGFloat blurRadius = blur;
CGContextRef context = platformContext();
if (!m_common->state.shadowsIgnoreTransforms) {
- CGAffineTransform transform = CGContextGetCTM(context);
+ CGAffineTransform userToBaseCTM = wkGetUserToBaseCTM(context);
- CGFloat A = transform.a * transform.a + transform.b * transform.b;
- CGFloat B = transform.a * transform.c + transform.b * transform.d;
+ CGFloat A = userToBaseCTM.a * userToBaseCTM.a + userToBaseCTM.b * userToBaseCTM.b;
+ CGFloat B = userToBaseCTM.a * userToBaseCTM.c + userToBaseCTM.b * userToBaseCTM.d;
CGFloat C = B;
- CGFloat D = transform.c * transform.c + transform.d * transform.d;
+ CGFloat D = userToBaseCTM.c * userToBaseCTM.c + userToBaseCTM.d * userToBaseCTM.d;
CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D)))));
// Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0));
- CGSize sizeInDeviceSpace = CGSizeApplyAffineTransform(size, transform);
-
- width = sizeInDeviceSpace.width;
- height = sizeInDeviceSpace.height;
+ CGSize offsetInBaseSpace = CGSizeApplyAffineTransform(offset, userToBaseCTM);
+ xOffset = offsetInBaseSpace.width;
+ yOffset = offsetInBaseSpace.height;
}
// Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated
// to the desired integer.
static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
- if (width > 0)
- width += extraShadowOffset;
- else if (width < 0)
- width -= extraShadowOffset;
+ if (xOffset > 0)
+ xOffset += extraShadowOffset;
+ else if (xOffset < 0)
+ xOffset -= extraShadowOffset;
- if (height > 0)
- height += extraShadowOffset;
- else if (height < 0)
- height -= extraShadowOffset;
+ if (yOffset > 0)
+ yOffset += extraShadowOffset;
+ else if (yOffset < 0)
+ yOffset -= extraShadowOffset;
// Check for an invalid color, as this means that the color was not set for the shadow
// and we should therefore just use the default shadow color.
if (!color.isValid())
- CGContextSetShadow(context, CGSizeMake(width, height), blurRadius);
+ CGContextSetShadow(context, CGSizeMake(xOffset, yOffset), blurRadius);
else {
RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColorWithColorSpace(color, colorSpace));
CGContextSetShadowWithColor(context,
- CGSizeMake(width, height),
+ CGSizeMake(xOffset, yOffset),
blurRadius,
colorCG.get());
}
@@ -838,7 +845,7 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth)
CGContextAddRect(context, r);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
- CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient());
+ m_common->state.strokeGradient->paint(this);
CGContextRestoreGState(context);
return;
}
diff --git a/WebCore/platform/graphics/cg/PatternCG.cpp b/WebCore/platform/graphics/cg/PatternCG.cpp
index 63628f4..26f402b 100644
--- a/WebCore/platform/graphics/cg/PatternCG.cpp
+++ b/WebCore/platform/graphics/cg/PatternCG.cpp
@@ -61,7 +61,7 @@ CGPatternRef Pattern::createPlatformPattern(const TransformationMatrix& userSpac
// If FLT_MAX should also be used for xStep or yStep, nothing is rendered. Using fractions of FLT_MAX also
// result in nothing being rendered.
- // INT_MAX is almost correct, but there seems to be some number wrapping occuring making the fill
+ // INT_MAX is almost correct, but there seems to be some number wrapping occurring making the fill
// pattern is not filled correctly.
// To make error of floating point less than 0.5, we use the half of the number of mantissa of float (1 << 22).
CGFloat xStep = m_repeatX ? tileRect.width() : (1 << 22);
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
index 6bd7d7c..6432e17 100644
--- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
@@ -32,11 +32,11 @@
#include "config.h"
#include "FontCustomPlatformData.h"
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
#include "Base64.h"
#include "ChromiumBridge.h"
#include "OpenTypeUtilities.h"
-#elif PLATFORM(LINUX)
+#elif OS(LINUX)
#include "SkStream.h"
#endif
@@ -45,9 +45,9 @@
#include "OpenTypeSanitizer.h"
#include "SharedBuffer.h"
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
#include <objbase.h>
-#elif PLATFORM(LINUX)
+#elif OS(LINUX)
#include <cstring>
#endif
@@ -55,10 +55,10 @@ namespace WebCore {
FontCustomPlatformData::~FontCustomPlatformData()
{
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
if (m_fontReference)
RemoveFontMemResourceEx(m_fontReference);
-#elif PLATFORM(LINUX)
+#elif OS(LINUX)
if (m_fontReference)
m_fontReference->unref();
#endif
@@ -66,7 +66,7 @@ FontCustomPlatformData::~FontCustomPlatformData()
FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode mode)
{
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
ASSERT(m_fontReference);
LOGFONT logFont;
@@ -99,7 +99,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
HFONT hfont = CreateFontIndirect(&logFont);
return FontPlatformData(hfont, size);
-#elif PLATFORM(LINUX)
+#elif OS(LINUX)
ASSERT(m_fontReference);
return FontPlatformData(m_fontReference, size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic());
#else
@@ -108,7 +108,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
#endif
}
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
// Creates a unique and unpredictable font name, in order to avoid collisions and to
// not allow access from CSS.
static String createUniqueFontName()
@@ -123,7 +123,7 @@ static String createUniqueFontName()
}
#endif
-#if PLATFORM(LINUX)
+#if OS(LINUX)
class RemoteFontStream : public SkStream {
public:
explicit RemoteFontStream(PassRefPtr<SharedBuffer> buffer)
@@ -180,7 +180,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
buffer = transcodeBuffer.get();
#endif
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
// Introduce the font to GDI. AddFontMemResourceEx should be used with care, because it will pollute the process's
// font namespace (Windows has no API for creating an HFONT from data without exposing the font to the
// entire process first).
@@ -189,9 +189,9 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
if (!fontReference)
return 0;
return new FontCustomPlatformData(fontReference, fontName);
-#elif PLATFORM(LINUX)
- RemoteFontStream stream(buffer);
- SkTypeface* typeface = SkTypeface::CreateFromStream(&stream);
+#elif OS(LINUX)
+ RemoteFontStream* stream = new RemoteFontStream(buffer);
+ SkTypeface* typeface = SkTypeface::CreateFromStream(stream);
if (!typeface)
return 0;
return new FontCustomPlatformData(typeface);
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
index a42f1ec..e1fbd48 100644
--- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
@@ -35,10 +35,10 @@
#include "FontRenderingMode.h"
#include <wtf/Noncopyable.h>
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
#include "PlatformString.h"
#include <windows.h>
-#elif PLATFORM(LINUX)
+#elif OS(LINUX)
#include "SkTypeface.h"
#endif
@@ -48,12 +48,12 @@ class FontPlatformData;
class SharedBuffer;
struct FontCustomPlatformData : Noncopyable {
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
FontCustomPlatformData(HANDLE fontReference, const String& name)
: m_fontReference(fontReference)
, m_name(name)
{}
-#elif PLATFORM(LINUX)
+#elif OS(LINUX)
explicit FontCustomPlatformData(SkTypeface* typeface)
: m_fontReference(typeface)
{}
@@ -64,10 +64,10 @@ struct FontCustomPlatformData : Noncopyable {
FontPlatformData fontPlatformData(int size, bool bold, bool italic,
FontRenderingMode = NormalRenderingMode);
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
HANDLE m_fontReference;
String m_name;
-#elif PLATFORM(LINUX)
+#elif OS(LINUX)
SkTypeface* m_fontReference;
#endif
};
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
index a4526a8..e76eca8 100644
--- a/WebCore/platform/graphics/chromium/FontLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -312,7 +312,8 @@ public:
private:
const TextRun& getTextRun(const TextRun& originalRun)
{
- // Convert the |originalRun| to NFC normalized form if combining diacritical marks
+ // Normalize the text run in two ways:
+ // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
// (U+0300..) are used in the run. This conversion is necessary since most OpenType
// fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
// their GSUB tables.
@@ -321,9 +322,12 @@ private:
// the API returns FALSE (= not normalized) for complex runs that don't require NFC
// normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
// Harfbuzz will do the same thing for us using the GSUB table.
+ // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
+ // for characters like '\n' otherwise.
for (unsigned i = 0; i < originalRun.length(); ++i) {
- UBlockCode block = ::ublock_getCode(originalRun[i]);
- if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
+ UChar ch = originalRun[i];
+ UBlockCode block = ::ublock_getCode(ch);
+ if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS || (Font::treatAsSpace(ch) && ch != ' ')) {
return getNormalizedTextRun(originalRun);
}
}
@@ -342,6 +346,11 @@ private:
normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error);
ASSERT(U_SUCCESS(error));
+ for (unsigned i = 0; i < normalizedString.length(); ++i) {
+ if (Font::treatAsSpace(m_normalizedBuffer[i]))
+ m_normalizedBuffer[i] = ' ';
+ }
+
m_normalizedRun.set(new TextRun(originalRun));
m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length());
return *m_normalizedRun;
@@ -391,6 +400,8 @@ private:
m_item.attributes = new HB_GlyphAttributes[m_maxGlyphs];
m_item.advances = new HB_Fixed[m_maxGlyphs];
m_item.offsets = new HB_FixedPoint[m_maxGlyphs];
+ // HB_FixedPoint is a struct, so we must use memset to clear it.
+ memset(m_item.offsets, 0, m_maxGlyphs * sizeof(HB_FixedPoint));
m_glyphs16 = new uint16_t[m_maxGlyphs];
m_xPositions = new SkScalar[m_maxGlyphs];
@@ -427,18 +438,19 @@ private:
void setGlyphXPositions(bool isRTL)
{
- m_pixelWidth = 0;
- for (unsigned i = 0; i < m_item.num_glyphs; ++i) {
- int index;
- if (isRTL)
- index = m_item.num_glyphs - (i + 1);
- else
- index = i;
+ double position = 0;
+ for (int iter = 0; iter < m_item.num_glyphs; ++iter) {
+ // Glyphs are stored in logical order, but for layout purposes we always go left to right.
+ int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;
m_glyphs16[i] = m_item.glyphs[i];
- m_xPositions[index] = m_offsetX + m_pixelWidth;
- m_pixelWidth += truncateFixedPointToInteger(m_item.advances[index]);
+ double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
+ m_xPositions[i] = m_offsetX + position + offsetX;
+
+ double advance = truncateFixedPointToInteger(m_item.advances[i]);
+ position += advance;
}
+ m_pixelWidth = position;
m_offsetX += m_pixelWidth;
}
diff --git a/WebCore/platform/graphics/chromium/FontPlatformData.h b/WebCore/platform/graphics/chromium/FontPlatformData.h
index c6f1912..871fec8 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformData.h
+++ b/WebCore/platform/graphics/chromium/FontPlatformData.h
@@ -31,9 +31,9 @@
#ifndef FontPlatformData_h
#define FontPlatformData_h
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
#include "FontPlatformDataChromiumWin.h"
-#elif defined(__linux__)
+#elif OS(LINUX)
#include "FontPlatformDataLinux.h"
#endif
diff --git a/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
index 621d674..be3b0d0 100644
--- a/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
+++ b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
@@ -30,7 +30,6 @@
#include "config.h"
-#include "Font.h"
#include "FontPlatformData.h"
#include "wtf/OwnArrayPtr.h"
@@ -42,7 +41,6 @@
extern "C" {
#include "harfbuzz-shaper.h"
-#include "harfbuzz-unicode.h"
}
// This file implements the callbacks which Harfbuzz requires by using Skia
@@ -67,29 +65,10 @@ static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_u
// HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
// |glyphs| array needs to be converted.
- // Additionally, if the CSS white-space property is inhibiting line
- // breaking, we might find end-of-line charactors rendered via the complex
- // text path. Fonts don't provide glyphs for these code points so, if we
- // find one, we simulate the space glyph being interposed in this case.
- // Because the input is variable-length per code point, we walk the input
- // in step with the output.
- // FIXME: it seems that this logic is duplicated in CoreTextController and UniscribeController
- ssize_t indexOfNextCodePoint = 0;
- uint16_t spaceGlyphNumber = 0;
for (int i = numGlyphs - 1; i >= 0; --i) {
- const uint32_t currentCodePoint = utf16_to_code_point(characters, length, &indexOfNextCodePoint);
-
uint16_t value;
// We use a memcpy to avoid breaking strict aliasing rules.
memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t));
-
- if (!value && Font::treatAsSpace(currentCodePoint)) {
- static const uint16_t spaceUTF16 = ' ';
- if (!spaceGlyphNumber)
- paint.textToGlyphs(&spaceUTF16, sizeof(spaceUTF16), &spaceGlyphNumber);
- value = spaceGlyphNumber;
- }
-
glyphs[i] = value;
}
@@ -188,15 +167,16 @@ static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* met
SkRect bounds;
paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
- metrics->x = SkiaScalarToHarfbuzzFixed(width);
+ metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
+ metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
+ metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
+ metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+
+ metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
// We can't actually get the |y| correct because Skia doesn't export
// the vertical advance. However, nor we do ever render vertical text at
// the moment so it's unimportant.
- metrics->y = 0;
- metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
- metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
- metrics->xOffset = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
- metrics->yOffset = SkiaScalarToHarfbuzzFixed(bounds.fTop);
+ metrics->yOffset = 0;
}
static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
index 6dcd595..80df2ec 100644
--- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
@@ -371,8 +371,11 @@ void TransparencyWin::initializeNewContext()
return;
m_drawContext = m_layerBuffer->context();
- if (needReferenceBitmap)
+ if (needReferenceBitmap) {
m_referenceBitmap = m_ownedBuffers->referenceBitmap();
+ if (!m_referenceBitmap || !m_referenceBitmap->getPixels())
+ return;
+ }
m_validLayer = true;
return;
}
diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
index f422157..bd19d14 100644
--- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp
+++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
@@ -184,6 +184,7 @@ void FEColorMatrix::apply(Filter* filter)
break;
case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(srcPixelArray, imageData, m_values);
+ setIsAlphaImage(true);
break;
}
diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
index 1d9cfff..f9aa011 100644
--- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
+++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
@@ -3,6 +3,7 @@
2004, 2005 Rob Buis <buis@kde.org>
2005 Eric Seidel <eric@webkit.org>
2009 Dirk Schulze <krit@webkit.org>
+ Copyright (C) Research In Motion Limited 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
@@ -140,7 +141,8 @@ static void linear(unsigned char* values, const ComponentTransferFunction& trans
static void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction)
{
for (unsigned i = 0; i < 256; ++i) {
- double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), transferFunction.exponent) + transferFunction.offset);
+ double exponent = transferFunction.exponent; // RCVT doesn't like passing a double and a float to pow, so promote this to double
+ double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), exponent) + transferFunction.offset);
val = std::max(0.0, std::min(255.0, val));
values[i] = static_cast<unsigned char>(val);
}
diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.h b/WebCore/platform/graphics/filters/FEComponentTransfer.h
index 773aba7..ab84cf0 100644
--- a/WebCore/platform/graphics/filters/FEComponentTransfer.h
+++ b/WebCore/platform/graphics/filters/FEComponentTransfer.h
@@ -25,7 +25,6 @@
#if ENABLE(FILTERS)
#include "FilterEffect.h"
-#include "SVGFEDisplacementMap.h"
#include "Filter.h"
#include <wtf/Vector.h>
diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp
index c540cb7..67d3d27 100644
--- a/WebCore/platform/graphics/filters/FEComposite.cpp
+++ b/WebCore/platform/graphics/filters/FEComposite.cpp
@@ -111,9 +111,7 @@ inline void arithmetic(const RefPtr<CanvasPixelArray>& srcPixelArrayA, CanvasPix
unsigned char i1 = srcPixelArrayA->get(pixelOffset + channel);
unsigned char i2 = srcPixelArrayB->get(pixelOffset + channel);
- unsigned char result = scaledK1 * i1 * i2 + k2 * i1 + k3 * i2 + scaledK4;
- if (channel == 3 && i1 == 0 && i2 == 0)
- result = 0;
+ double result = scaledK1 * i1 * i2 + k2 * i1 + k3 * i2 + scaledK4;
srcPixelArrayB->set(pixelOffset + channel, result);
}
}
diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp
index 38da70d..c62d988 100644
--- a/WebCore/platform/graphics/gtk/ImageGtk.cpp
+++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp
@@ -44,29 +44,30 @@ template <> void freeOwnedGPtr<GtkIconInfo>(GtkIconInfo* info)
namespace WebCore {
-static CString getIconFileNameOrFallback(const char* name, const char* fallback)
+static CString getThemeIconFileName(const char* name, int size)
{
- GOwnPtr<GtkIconInfo> info(gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(),
- name, 16, GTK_ICON_LOOKUP_NO_SVG));
- if (!info)
- return String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, fallback).utf8();
+ GtkIconInfo* iconInfo = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(),
+ name, size, GTK_ICON_LOOKUP_NO_SVG);
+ // Try to fallback on MISSING_IMAGE.
+ if (!iconInfo)
+ iconInfo = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(),
+ GTK_STOCK_MISSING_IMAGE, size,
+ GTK_ICON_LOOKUP_NO_SVG);
+ if (iconInfo) {
+ GOwnPtr<GtkIconInfo> info(iconInfo);
+ return CString(gtk_icon_info_get_filename(info.get()));
+ }
- return CString(gtk_icon_info_get_filename(info.get()));
+ // No icon was found, this can happen if not GTK theme is set. In
+ // that case an empty Image will be created.
+ return CString();
}
-static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(const char* name)
+static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(CString name)
{
- CString fileName;
-
- // Find the path for the image
- if (strcmp("missingImage", name) == 0)
- fileName = getIconFileNameOrFallback(GTK_STOCK_MISSING_IMAGE, "missingImage");
- else
- fileName = String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, name).utf8();
-
GOwnPtr<gchar> content;
gsize length;
- if (!g_file_get_contents(fileName.data(), &content.outPtr(), &length, 0))
+ if (!g_file_get_contents(name.data(), &content.outPtr(), &length, 0))
return SharedBuffer::create();
return SharedBuffer::create(content.get(), length);
@@ -80,14 +81,32 @@ void BitmapImage::invalidatePlatformData()
{
}
-PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+PassRefPtr<Image> loadImageFromFile(CString fileName)
{
RefPtr<BitmapImage> img = BitmapImage::create();
- RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(name);
- img->setData(buffer.release(), true);
+ if (!fileName.isNull()) {
+ RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(fileName);
+ img->setData(buffer.release(), true);
+ }
return img.release();
}
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ CString fileName;
+ if (!strcmp("missingImage", name))
+ fileName = getThemeIconFileName(GTK_STOCK_MISSING_IMAGE, 16);
+ if (fileName.isNull())
+ fileName = String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, name).utf8();
+
+ return loadImageFromFile(fileName);
+}
+
+PassRefPtr<Image> Image::loadPlatformThemeIcon(const char* name, int size)
+{
+ return loadImageFromFile(getThemeIconFileName(name, size));
+}
+
static inline unsigned char* getCairoSurfacePixel(unsigned char* data, uint x, uint y, uint rowStride)
{
return data + (y * rowStride) + x * 4;
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index a023dae..41f90f0 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -29,6 +29,9 @@
#include "CString.h"
#include "DataSourceGStreamer.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameView.h"
#include "GraphicsContext.h"
#include "IntRect.h"
#include "KURL.h"
@@ -36,6 +39,7 @@
#include "MediaPlayer.h"
#include "NotImplemented.h"
#include "ScrollView.h"
+#include "SecurityOrigin.h"
#include "TimeRanges.h"
#include "VideoSinkGStreamer.h"
#include "Widget.h"
@@ -46,6 +50,7 @@
#include <gst/video/video.h>
#include <limits>
#include <math.h>
+#include <webkit/webkitwebview.h>
#include <wtf/gtk/GOwnPtr.h>
using namespace std;
@@ -59,9 +64,24 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo
MediaPlayer::NetworkState error;
MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
gint percent = 0;
+ bool issueError = true;
+ bool attemptNextLocation = false;
+
+ if (message->structure) {
+ const gchar* messageTypeName = gst_structure_get_name(message->structure);
+
+ // Redirect messages are sent from elements, like qtdemux, to
+ // notify of the new location(s) of the media.
+ if (!g_strcmp0(messageTypeName, "redirect")) {
+ mp->mediaLocationChanged(message);
+ return true;
+ }
+ }
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_ERROR:
+ if (mp && mp->pipelineReset())
+ break;
gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message);
@@ -72,13 +92,18 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo
|| err->code == GST_CORE_ERROR_MISSING_PLUGIN
|| err->code == GST_RESOURCE_ERROR_NOT_FOUND)
error = MediaPlayer::FormatError;
- else if (err->domain == GST_STREAM_ERROR)
+ else if (err->domain == GST_STREAM_ERROR) {
error = MediaPlayer::DecodeError;
- else if (err->domain == GST_RESOURCE_ERROR)
+ attemptNextLocation = true;
+ } else if (err->domain == GST_RESOURCE_ERROR)
error = MediaPlayer::NetworkError;
- if (mp)
- mp->loadingFailed(error);
+ if (mp) {
+ if (attemptNextLocation)
+ issueError = !mp->loadNextLocation();
+ if (issueError)
+ mp->loadingFailed(error);
+ }
break;
case GST_MESSAGE_EOS:
LOG_VERBOSE(Media, "End of Stream");
@@ -91,6 +116,10 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo
gst_message_parse_buffering(message, &percent);
LOG_VERBOSE(Media, "Buffering %d", percent);
break;
+ case GST_MESSAGE_DURATION:
+ LOG_VERBOSE(Media, "Duration changed");
+ mp->durationChanged();
+ break;
default:
LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s",
GST_MESSAGE_TYPE_NAME(message));
@@ -99,6 +128,69 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo
return true;
}
+void mediaPlayerPrivateSourceChangedCallback(GObject *object, GParamSpec *pspec, gpointer data)
+{
+ MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ GstElement* element;
+
+ g_object_get(mp->m_playBin, "source", &element, NULL);
+ gst_object_replace((GstObject**) &mp->m_source, (GstObject*) element);
+
+ if (element) {
+ GParamSpec* pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(element), "cookies");
+
+ // First check if the source element has a cookies property
+ // of the format we expect
+ if (!pspec || pspec->value_type != G_TYPE_STRV)
+ return;
+
+ // Then get the cookies for the URI and set them
+ SoupSession* session = webkit_get_default_session();
+ SoupCookieJar* cookieJar = SOUP_COOKIE_JAR(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
+
+ char* location;
+ g_object_get(element, "location", &location, NULL);
+
+ SoupURI* uri = soup_uri_new(location);
+ g_free(location);
+
+ // Let Apple web servers know we want to access their nice movie trailers.
+ if (g_str_equal(uri->host, "movies.apple.com"))
+ g_object_set(element, "user-agent", "Quicktime/7.2.0", NULL);
+
+ char* cookies = soup_cookie_jar_get_cookies(cookieJar, uri, FALSE);
+ soup_uri_free(uri);
+
+ char* cookiesStrv[] = {cookies, NULL};
+ g_object_set(element, "cookies", cookiesStrv, NULL);
+ g_free(cookies);
+
+ Frame* frame = mp->m_player->frameView() ? mp->m_player->frameView()->frame() : 0;
+ Document* document = frame ? frame->document() : 0;
+ if (document) {
+ GstStructure* extraHeaders = gst_structure_new("extra-headers",
+ "Referer", G_TYPE_STRING,
+ document->documentURI().utf8().data(), 0);
+ g_object_set(element, "extra-headers", extraHeaders, NULL);
+ gst_structure_free(extraHeaders);
+ }
+ }
+
+ gst_object_unref(element);
+}
+
+void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
+{
+ MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ mp->volumeChanged();
+}
+
+gboolean notifyVolumeIdleCallback(MediaPlayer* mp)
+{
+ mp->volumeChanged();
+ return FALSE;
+}
+
static float playbackPosition(GstElement* playbin)
{
@@ -114,8 +206,8 @@ static float playbackPosition(GstElement* playbin)
gint64 position;
gst_query_parse_position(query, 0, &position);
- // Position is available only if the pipeline is not in NULL or
- // READY state.
+ // Position is available only if the pipeline is not in GST_STATE_NULL or
+ // GST_STATE_READY state.
if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE))
ret = static_cast<float>(position) / static_cast<float>(GST_SECOND);
@@ -126,6 +218,7 @@ static float playbackPosition(GstElement* playbin)
return ret;
}
+
void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate)
{
g_return_if_fail(GST_IS_BUFFER(buffer));
@@ -146,7 +239,7 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
static bool gstInitialized = false;
-static bool do_gst_init()
+static bool doGstInit()
{
// FIXME: We should pass the arguments from the command line
if (!gstInitialized) {
@@ -165,7 +258,7 @@ static bool do_gst_init()
bool MediaPlayerPrivate::isAvailable()
{
- if (!do_gst_init())
+ if (!doGstInit())
return false;
GstElementFactory* factory = gst_element_factory_find("playbin2");
@@ -180,6 +273,7 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_playBin(0)
, m_videoSink(0)
+ , m_fpsSink(0)
, m_source(0)
, m_seekTime(0)
, m_changingRate(false)
@@ -190,19 +284,40 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_isStreaming(false)
, m_size(IntSize())
, m_buffer(0)
+ , m_mediaLocations(0)
+ , m_mediaLocationCurrentIndex(0)
+ , m_resetPipeline(false)
, m_paused(true)
, m_seeking(false)
+ , m_playbackRate(1)
, m_errorOccured(false)
+ , m_volumeIdleId(-1)
+ , m_mediaDuration(0.0)
{
- do_gst_init();
+ doGstInit();
}
MediaPlayerPrivate::~MediaPlayerPrivate()
{
+ if (m_volumeIdleId) {
+ g_source_remove(m_volumeIdleId);
+ m_volumeIdleId = -1;
+ }
+
if (m_buffer)
gst_buffer_unref(m_buffer);
m_buffer = 0;
+ if (m_mediaLocations) {
+ gst_structure_free(m_mediaLocations);
+ m_mediaLocations = 0;
+ }
+
+ if (m_source) {
+ gst_object_unref(m_source);
+ m_source = 0;
+ }
+
if (m_playBin) {
gst_element_set_state(m_playBin, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(m_playBin));
@@ -212,6 +327,11 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
g_object_unref(m_videoSink);
m_videoSink = 0;
}
+
+ if (m_fpsSink) {
+ g_object_unref(m_fpsSink);
+ m_fpsSink = 0;
+ }
}
void MediaPlayerPrivate::load(const String& url)
@@ -230,28 +350,35 @@ void MediaPlayerPrivate::load(const String& url)
pause();
}
-void MediaPlayerPrivate::play()
+bool MediaPlayerPrivate::changePipelineState(GstState newState)
{
- GstState state;
+ ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED);
+
+ GstState currentState;
GstState pending;
- gst_element_get_state(m_playBin, &state, &pending, 0);
- if (state != GST_STATE_PLAYING && pending != GST_STATE_PLAYING) {
- LOG_VERBOSE(Media, "Play");
- gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ gst_element_get_state(m_playBin, &currentState, &pending, 0);
+ if (currentState != newState && pending != newState) {
+ GstStateChangeReturn ret = gst_element_set_state(m_playBin, newState);
+ GstState pausedOrPlaying = newState == GST_STATE_PLAYING ? GST_STATE_PAUSED : GST_STATE_PLAYING;
+ if (currentState != pausedOrPlaying && ret == GST_STATE_CHANGE_FAILURE) {
+ loadingFailed(MediaPlayer::Empty);
+ return false;
+ }
}
+ return true;
}
-void MediaPlayerPrivate::pause()
+void MediaPlayerPrivate::play()
{
- GstState state;
- GstState pending;
+ if (changePipelineState(GST_STATE_PLAYING))
+ LOG_VERBOSE(Media, "Play");
+}
- gst_element_get_state(m_playBin, &state, &pending, 0);
- if (state != GST_STATE_PAUSED && pending != GST_STATE_PAUSED) {
+void MediaPlayerPrivate::pause()
+{
+ if (changePipelineState(GST_STATE_PAUSED))
LOG_VERBOSE(Media, "Pause");
- gst_element_set_state(m_playBin, GST_STATE_PAUSED);
- }
}
float MediaPlayerPrivate::duration() const
@@ -262,6 +389,9 @@ float MediaPlayerPrivate::duration() const
if (m_errorOccured)
return 0.0;
+ if (m_mediaDuration)
+ return m_mediaDuration;
+
GstFormat timeFormat = GST_FORMAT_TIME;
gint64 timeLength = 0;
@@ -293,7 +423,9 @@ float MediaPlayerPrivate::currentTime() const
void MediaPlayerPrivate::seek(float time)
{
- GstClockTime sec = (GstClockTime)(time * GST_SECOND);
+ // Avoid useless seeking.
+ if (time == playbackPosition(m_playBin))
+ return;
if (!m_playBin)
return;
@@ -304,6 +436,7 @@ void MediaPlayerPrivate::seek(float time)
if (m_errorOccured)
return;
+ GstClockTime sec = (GstClockTime)(time * GST_SECOND);
LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec));
if (!gst_element_seek(m_playBin, m_player->rate(),
GST_FORMAT_TIME,
@@ -317,11 +450,6 @@ void MediaPlayerPrivate::seek(float time)
}
}
-void MediaPlayerPrivate::setEndTime(float time)
-{
- notImplemented();
-}
-
void MediaPlayerPrivate::startEndPointTimerIfNeeded()
{
notImplemented();
@@ -384,7 +512,7 @@ bool MediaPlayerPrivate::hasVideo() const
{
gint currentVideo = -1;
if (m_playBin)
- g_object_get(G_OBJECT(m_playBin), "current-video", &currentVideo, NULL);
+ g_object_get(m_playBin, "current-video", &currentVideo, NULL);
return currentVideo > -1;
}
@@ -392,7 +520,7 @@ bool MediaPlayerPrivate::hasAudio() const
{
gint currentAudio = -1;
if (m_playBin)
- g_object_get(G_OBJECT(m_playBin), "current-audio", &currentAudio, NULL);
+ g_object_get(m_playBin, "current-audio", &currentAudio, NULL);
return currentAudio > -1;
}
@@ -401,11 +529,25 @@ void MediaPlayerPrivate::setVolume(float volume)
if (!m_playBin)
return;
- g_object_set(G_OBJECT(m_playBin), "volume", static_cast<double>(volume), NULL);
+ g_object_set(m_playBin, "volume", static_cast<double>(volume), NULL);
}
+void MediaPlayerPrivate::volumeChanged()
+{
+ if (m_volumeIdleId) {
+ g_source_remove(m_volumeIdleId);
+ m_volumeIdleId = -1;
+ }
+ m_volumeIdleId = g_idle_add((GSourceFunc) notifyVolumeIdleCallback, m_player);
+}
+
+
void MediaPlayerPrivate::setRate(float rate)
{
+ // Avoid useless playback rate update.
+ if (m_playbackRate == rate)
+ return;
+
GstState state;
GstState pending;
@@ -417,6 +559,7 @@ void MediaPlayerPrivate::setRate(float rate)
if (m_isStreaming)
return;
+ m_playbackRate = rate;
m_changingRate = true;
float currentPosition = playbackPosition(m_playBin) * GST_SECOND;
GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH);
@@ -452,12 +595,6 @@ void MediaPlayerPrivate::setRate(float rate)
g_object_set(m_playBin, "mute", mute, NULL);
}
-int MediaPlayerPrivate::dataRate() const
-{
- notImplemented();
- return 1;
-}
-
MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
{
return m_networkState;
@@ -512,13 +649,7 @@ unsigned MediaPlayerPrivate::bytesLoaded() const
if (!dur)
return 0;*/
- return 1;//totalBytes() * maxTime / dur;
-}
-
-bool MediaPlayerPrivate::totalBytesKnown() const
-{
- LOG_VERBOSE(Media, "totalBytesKnown");
- return totalBytes() > 0;
+ return 1; // totalBytes() * maxTime / dur;
}
unsigned MediaPlayerPrivate::totalBytes() const
@@ -573,6 +704,8 @@ void MediaPlayerPrivate::updateStates()
gst_element_state_get_name(state),
gst_element_state_get_name(pending));
+ m_resetPipeline = state <= GST_STATE_READY;
+
if (state == GST_STATE_READY)
m_readyState = MediaPlayer::HaveNothing;
else if (state == GST_STATE_PAUSED)
@@ -581,6 +714,11 @@ void MediaPlayerPrivate::updateStates()
if (state == GST_STATE_PLAYING) {
m_readyState = MediaPlayer::HaveEnoughData;
m_paused = false;
+ if (!m_mediaDuration) {
+ float newDuration = duration();
+ if (!isinf(newDuration))
+ m_mediaDuration = newDuration;
+ }
} else
m_paused = true;
@@ -595,10 +733,6 @@ void MediaPlayerPrivate::updateStates()
}
m_networkState = MediaPlayer::Loaded;
-
- g_object_get(m_playBin, "source", &m_source, NULL);
- if (!m_source)
- LOG_VERBOSE(Media, "m_source is 0");
break;
case GST_STATE_CHANGE_ASYNC:
LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
@@ -647,6 +781,105 @@ void MediaPlayerPrivate::updateStates()
}
}
+void MediaPlayerPrivate::mediaLocationChanged(GstMessage* message)
+{
+ if (m_mediaLocations)
+ gst_structure_free(m_mediaLocations);
+
+ if (message->structure) {
+ // This structure can contain:
+ // - both a new-location string and embedded locations structure
+ // - or only a new-location string.
+ m_mediaLocations = gst_structure_copy(message->structure);
+ const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
+
+ if (locations)
+ m_mediaLocationCurrentIndex = gst_value_list_get_size(locations) -1;
+
+ loadNextLocation();
+ }
+}
+
+bool MediaPlayerPrivate::loadNextLocation()
+{
+ if (!m_mediaLocations)
+ return false;
+
+ const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
+ const gchar* newLocation = 0;
+
+ if (!locations) {
+ // Fallback on new-location string.
+ newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
+ if (!newLocation)
+ return false;
+ }
+
+ if (!newLocation) {
+ if (m_mediaLocationCurrentIndex < 0) {
+ m_mediaLocations = 0;
+ return false;
+ }
+
+ const GValue* location = gst_value_list_get_value(locations,
+ m_mediaLocationCurrentIndex);
+ const GstStructure* structure = gst_value_get_structure(location);
+
+ if (!structure) {
+ m_mediaLocationCurrentIndex--;
+ return false;
+ }
+
+ newLocation = gst_structure_get_string(structure, "new-location");
+ }
+
+ if (newLocation) {
+ // Found a candidate. new-location is not always an absolute url
+ // though. We need to take the base of the current url and
+ // append the value of new-location to it.
+
+ gchar* currentLocation = 0;
+ g_object_get(m_playBin, "uri", &currentLocation, NULL);
+
+ KURL currentUrl(KURL(), currentLocation);
+ g_free(currentLocation);
+
+ KURL newUrl;
+
+ if (gst_uri_is_valid(newLocation))
+ newUrl = KURL(KURL(), newLocation);
+ else
+ newUrl = KURL(KURL(), currentUrl.baseAsString() + newLocation);
+
+ RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(currentUrl);
+ if (securityOrigin->canRequest(newUrl)) {
+ LOG_VERBOSE(Media, "New media url: %s", newUrl.string().utf8().data());
+
+ // Reset player states.
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+
+ // Reset pipeline state.
+ m_resetPipeline = true;
+ gst_element_set_state(m_playBin, GST_STATE_READY);
+
+ GstState state;
+ gst_element_get_state(m_playBin, &state, 0, 0);
+ if (state <= GST_STATE_READY) {
+ // Set the new uri and start playing.
+ g_object_set(m_playBin, "uri", newUrl.string().utf8().data(), NULL);
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ return true;
+ }
+ }
+ }
+ m_mediaLocationCurrentIndex--;
+ return false;
+
+}
+
void MediaPlayerPrivate::loadStateChanged()
{
updateStates();
@@ -663,14 +896,30 @@ void MediaPlayerPrivate::timeChanged()
m_player->timeChanged();
}
-void MediaPlayerPrivate::volumeChanged()
+void MediaPlayerPrivate::didEnd()
{
- m_player->volumeChanged();
+ // EOS was reached but in case of reverse playback the position is
+ // not always 0. So to not confuse the HTMLMediaElement we
+ // synchronize position and duration values.
+ float now = currentTime();
+ if (now > 0)
+ m_mediaDuration = now;
+ gst_element_set_state(m_playBin, GST_STATE_PAUSED);
+
+ timeChanged();
}
-void MediaPlayerPrivate::didEnd()
+void MediaPlayerPrivate::durationChanged()
{
- timeChanged();
+ // Reset cached media duration
+ m_mediaDuration = 0;
+
+ // And re-cache it if possible.
+ float newDuration = duration();
+ if (!isinf(newDuration))
+ m_mediaDuration = newDuration;
+
+ m_player->durationChanged();
}
void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error)
@@ -711,7 +960,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
return;
int width = 0, height = 0;
- GstCaps *caps = gst_buffer_get_caps(m_buffer);
+ GstCaps* caps = gst_buffer_get_caps(m_buffer);
GstVideoFormat format;
if (!gst_video_format_parse_caps(caps, &format, &width, &height)) {
@@ -751,7 +1000,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
static HashSet<String> mimeTypeCache()
{
- do_gst_init();
+ doGstInit();
static HashSet<String> cache;
static bool typeListInitialized = false;
@@ -814,11 +1063,11 @@ static HashSet<String> mimeTypeCache()
if (G_VALUE_TYPE(layer) == GST_TYPE_INT_RANGE) {
gint minLayer = gst_value_get_int_range_min(layer);
gint maxLayer = gst_value_get_int_range_max(layer);
- if (minLayer <= 1 <= maxLayer)
+ if (minLayer <= 1 && 1 <= maxLayer)
cache.add(String("audio/mp1"));
- if (minLayer <= 2 <= maxLayer)
+ if (minLayer <= 2 && 2 <= maxLayer)
cache.add(String("audio/mp2"));
- if (minLayer <= 3 <= maxLayer)
+ if (minLayer <= 3 && 3 <= maxLayer)
cache.add(String("audio/mp3"));
}
}
@@ -887,13 +1136,29 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
gst_object_unref(bus);
- g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(),
- "volume", static_cast<double>(m_player->volume()), NULL);
+ g_object_set(m_playBin, "uri", url.utf8().data(), NULL);
+
+ g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
+ g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
m_videoSink = webkit_video_sink_new();
g_object_ref_sink(m_videoSink);
- g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
+
+ WTFLogChannel* channel = getChannelFromName("Media");
+ if (channel->state == WTFLogChannelOn) {
+ m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) {
+ g_object_set(m_fpsSink, "video-sink", m_videoSink, NULL);
+ g_object_ref_sink(m_fpsSink);
+ g_object_set(m_playBin, "video-sink", m_fpsSink, NULL);
+ } else {
+ m_fpsSink = 0;
+ g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
+ LOG(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18");
+ }
+ } else
+ g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
}
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
index 6ab8edb..ec55b29 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
@@ -39,16 +39,19 @@ typedef struct _GstBus GstBus;
namespace WebCore {
- class GraphicsContext;
- class IntSize;
- class IntRect;
- class String;
+class GraphicsContext;
+class IntSize;
+class IntRect;
+class String;
- gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
+gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
+void mediaPlayerPrivateVolumeChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
+void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
- class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
- friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate);
+ friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer* buffer, MediaPlayerPrivate* playerPrivate);
+ friend void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
public:
static void registerMediaEngine(MediaEngineRegistrar);
@@ -60,6 +63,7 @@ namespace WebCore {
void load(const String &url);
void cancelLoad();
+ bool loadNextLocation();
void play();
void pause();
@@ -70,12 +74,10 @@ namespace WebCore {
float duration() const;
float currentTime() const;
void seek(float);
- void setEndTime(float);
void setRate(float);
void setVolume(float);
-
- int dataRate() const;
+ void volumeChanged();
MediaPlayer::NetworkState networkState() const;
MediaPlayer::ReadyState readyState() const;
@@ -83,17 +85,17 @@ namespace WebCore {
PassRefPtr<TimeRanges> buffered() const;
float maxTimeSeekable() const;
unsigned bytesLoaded() const;
- bool totalBytesKnown() const;
unsigned totalBytes() const;
void setVisible(bool);
void setSize(const IntSize&);
+ void mediaLocationChanged(GstMessage*);
void loadStateChanged();
void sizeChanged();
void timeChanged();
- void volumeChanged();
void didEnd();
+ void durationChanged();
void loadingFailed(MediaPlayer::NetworkState);
void repaint();
@@ -103,6 +105,8 @@ namespace WebCore {
bool supportsFullscreen() const;
+ bool pipelineReset() const { return m_resetPipeline; }
+
private:
MediaPlayerPrivate(MediaPlayer*);
static MediaPlayerPrivateInterface* create(MediaPlayer* player);
@@ -118,11 +122,13 @@ namespace WebCore {
void startEndPointTimerIfNeeded();
void createGSTPlayBin(String url);
+ bool changePipelineState(GstState state);
private:
MediaPlayer* m_player;
GstElement* m_playBin;
GstElement* m_videoSink;
+ GstElement* m_fpsSink;
GstElement* m_source;
GstClockTime m_seekTime;
bool m_changingRate;
@@ -134,10 +140,15 @@ namespace WebCore {
mutable bool m_isStreaming;
IntSize m_size;
GstBuffer* m_buffer;
-
+ GstStructure* m_mediaLocations;
+ gint m_mediaLocationCurrentIndex;
+ bool m_resetPipeline;
bool m_paused;
bool m_seeking;
+ float m_playbackRate;
bool m_errorOccured;
+ guint m_volumeIdleId;
+ gfloat m_mediaDuration;
};
}
diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
index 4728d56..6038c6a 100644
--- a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
+++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
@@ -204,12 +204,16 @@ void GraphicsContext::clip(const FloatRect& rect)
m_data->m_view->ConstrainClippingRegion(&region);
}
-void GraphicsContext::drawFocusRing(const Color& color)
+void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
{
if (paintingDisabled())
return;
- const Vector<IntRect>& rects = focusRingRects();
unsigned rectCount = rects.size();
// FIXME: maybe we should implement this with BShape?
diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.mm b/WebCore/platform/graphics/mac/Canvas3DLayer.mm
index 94819d4..59a7384 100644
--- a/WebCore/platform/graphics/mac/Canvas3DLayer.mm
+++ b/WebCore/platform/graphics/mac/Canvas3DLayer.mm
@@ -33,8 +33,9 @@
#import "GraphicsLayer.h"
#import <QuartzCore/QuartzCore.h>
#import <OpenGL/OpenGL.h>
+#import <wtf/FastMalloc.h>
#import <wtf/RetainPtr.h>
-#include <wtf/FastMalloc.h>
+#import <wtf/UnusedParam.h>
using namespace WebCore;
@@ -140,6 +141,13 @@ static void freeData(void *, const void *data, size_t /* size */)
return image;
}
+- (void)display
+{
+ [super display];
+ if (m_layerOwner)
+ m_layerOwner->didDisplay(self);
+}
+
@end
@implementation Canvas3DLayer(WebLayerAdditions)
diff --git a/WebCore/platform/graphics/mac/ComplexTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp
index 265b2c3..7d12b61 100644
--- a/WebCore/platform/graphics/mac/ComplexTextController.cpp
+++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp
@@ -29,6 +29,13 @@
#include "Font.h"
#include "TextBreakIterator.h"
+#include <wtf/StdLibExtras.h>
+
+#if defined(BUILDING_ON_LEOPARD)
+// Undefined when compiling agains the 10.5 SDK.
+#define kCTVersionNumber10_6 0x00030000
+#endif
+
using namespace std;
namespace WebCore {
@@ -106,7 +113,7 @@ int ComplexTextController::offsetForPosition(int h, bool includePartialGlyphs)
else
hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : complexTextRun.stringLength());
- // FIXME: Instead of dividing the glyph's advance equially between the characters, this
+ // FIXME: Instead of dividing the glyph's advance equally between the characters, this
// could use the glyph's "ligature carets". However, there is no Core Text API to get the
// ligature carets.
CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
@@ -263,6 +270,62 @@ void ComplexTextController::collectComplexTextRuns()
collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData);
}
+#if USE(CORE_TEXT) && USE(ATSUI)
+static inline bool shouldUseATSUIAPI()
+{
+ enum TypeRenderingAPIToUse { UnInitialized, UseATSUI, UseCoreText };
+ DEFINE_STATIC_LOCAL(TypeRenderingAPIToUse, apiToUse, (UnInitialized));
+
+ if (UNLIKELY(apiToUse == UnInitialized)) {
+ if (&CTGetCoreTextVersion != 0 && CTGetCoreTextVersion() >= kCTVersionNumber10_6)
+ apiToUse = UseCoreText;
+ else
+ apiToUse = UseATSUI;
+ }
+
+ return apiToUse == UseATSUI;
+}
+#endif
+
+CFIndex ComplexTextController::ComplexTextRun::indexAt(size_t i) const
+{
+#if USE(CORE_TEXT) && USE(ATSUI)
+ return shouldUseATSUIAPI() ? m_atsuiIndices[i] : m_coreTextIndices[i];
+#elif USE(ATSUI)
+ return m_atsuiIndices[i];
+#elif USE(CORE_TEXT)
+ return m_coreTextIndices[i];
+#endif
+}
+
+void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+{
+#if USE(CORE_TEXT) && USE(ATSUI)
+ if (shouldUseATSUIAPI())
+ return collectComplexTextRunsForCharactersATSUI(cp, length, stringLocation, fontData);
+ return collectComplexTextRunsForCharactersCoreText(cp, length, stringLocation, fontData);
+#elif USE(ATSUI)
+ return collectComplexTextRunsForCharactersATSUI(cp, length, stringLocation, fontData);
+#elif USE(CORE_TEXT)
+ return collectComplexTextRunsForCharactersCoreText(cp, length, stringLocation, fontData);
+#endif
+}
+
+ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
+ : m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+{
+#if USE(CORE_TEXT) && USE(ATSUI)
+ shouldUseATSUIAPI() ? createTextRunFromFontDataATSUI(ltr) : createTextRunFromFontDataCoreText(ltr);
+#elif USE(ATSUI)
+ createTextRunFromFontDataATSUI(ltr);
+#elif USE(CORE_TEXT)
+ createTextRunFromFontDataCoreText(ltr);
+#endif
+}
+
void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
{
if (static_cast<int>(offset) > m_end)
diff --git a/WebCore/platform/graphics/mac/ComplexTextController.h b/WebCore/platform/graphics/mac/ComplexTextController.h
index 7a915e2..3fec18a 100644
--- a/WebCore/platform/graphics/mac/ComplexTextController.h
+++ b/WebCore/platform/graphics/mac/ComplexTextController.h
@@ -39,6 +39,11 @@ class Font;
class SimpleFontData;
class TextRun;
+// ComplexTextController is responsible for rendering and measuring glyphs for
+// complex scripts on OS X.
+// The underlying API can be selected at compile time based on USE(ATSUI) and
+// USE(CORE_TEXT). If both are defined then the Core Text APIs are used for
+// OS Versions >= 10.6, ATSUI is used otherwise.
class ComplexTextController {
public:
ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0);
@@ -65,7 +70,8 @@ private:
{
return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength));
}
-#elif USE(ATSUI)
+#endif
+#if USE(ATSUI)
static PassRefPtr<ComplexTextRun> create(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride)
{
return adoptRef(new ComplexTextRun(atsuTextLayout, fontData, characters, stringLocation, stringLength, ltr, directionalOverride));
@@ -81,15 +87,18 @@ private:
const UChar* characters() const { return m_characters; }
unsigned stringLocation() const { return m_stringLocation; }
size_t stringLength() const { return m_stringLength; }
- CFIndex indexAt(size_t i) const { return m_indices[i]; }
+ ALWAYS_INLINE CFIndex indexAt(size_t i) const;
const CGGlyph* glyphs() const { return m_glyphs; }
const CGSize* advances() const { return m_advances; }
private:
#if USE(CORE_TEXT)
ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength);
-#elif USE(ATSUI)
+ void createTextRunFromFontDataCoreText(bool ltr);
+#endif
+#if USE(ATSUI)
ComplexTextRun(ATSUTextLayout, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride);
+ void createTextRunFromFontDataATSUI(bool ltr);
#endif
ComplexTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr);
@@ -101,7 +110,7 @@ private:
#endif
#if USE(CORE_TEXT)
- RetainPtr<CTRunRef> m_CTRun;
+ RetainPtr<CTRunRef> m_coreTextRun;
#endif
unsigned m_glyphCount;
const SimpleFontData* m_fontData;
@@ -109,10 +118,11 @@ private:
unsigned m_stringLocation;
size_t m_stringLength;
#if USE(CORE_TEXT)
- RetainPtr<CFMutableDataRef> m_indicesData;
- const CFIndex* m_indices;
-#elif USE(ATSUI)
- Vector<CFIndex, 64> m_indices;
+ RetainPtr<CFMutableDataRef> m_coreTextIndicesData;
+ const CFIndex* m_coreTextIndices;
+#endif
+#if USE(ATSUI)
+ Vector<CFIndex, 64> m_atsuiIndices;
#endif
Vector<CGGlyph, 64> m_glyphsVector;
const CGGlyph* m_glyphs;
@@ -125,7 +135,12 @@ private:
};
void collectComplexTextRuns();
+
+ // collectComplexTextRunsForCharacters() is a stub function that calls through to the ATSUI or Core Text variants based
+ // on the API in use.
void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
+ void collectComplexTextRunsForCharactersATSUI(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
+ void collectComplexTextRunsForCharactersCoreText(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
void adjustGlyphsAndAdvances();
const Font& m_font;
diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp
index 78c588f..48aa174 100644
--- a/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp
+++ b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp
@@ -45,7 +45,7 @@ OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayo
ComplexTextRun* complexTextRun = reinterpret_cast<ComplexTextRun*>(refCon);
OSStatus status;
ItemCount count;
- ATSLayoutRecord *layoutRecords;
+ ATSLayoutRecord* layoutRecords;
status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, reinterpret_cast<void**>(&layoutRecords), &count);
if (status != noErr) {
@@ -66,7 +66,7 @@ OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayo
complexTextRun->m_glyphCount = count;
complexTextRun->m_glyphsVector.reserveCapacity(count);
complexTextRun->m_advancesVector.reserveCapacity(count);
- complexTextRun->m_indices.reserveCapacity(count);
+ complexTextRun->m_atsuiIndices.reserveCapacity(count);
bool atBeginning = true;
CGFloat lastX = 0;
@@ -77,7 +77,7 @@ OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayo
continue;
}
complexTextRun->m_glyphsVector.uncheckedAppend(layoutRecords[j].glyphID);
- complexTextRun->m_indices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset);
+ complexTextRun->m_atsuiIndices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset);
CGFloat x = FixedToFloat(layoutRecords[j].realPos);
if (!atBeginning)
complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(x - lastX, 0));
@@ -219,33 +219,29 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(ATSUTextLayout atsuTextLay
status = ATSUDisposeTextLayout(atsuTextLayout);
}
-ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
- : m_fontData(fontData)
- , m_characters(characters)
- , m_stringLocation(stringLocation)
- , m_stringLength(stringLength)
+void ComplexTextController::ComplexTextRun::createTextRunFromFontDataATSUI(bool ltr)
{
- m_indices.reserveCapacity(stringLength);
+ m_atsuiIndices.reserveCapacity(m_stringLength);
unsigned r = 0;
- while (r < stringLength) {
- m_indices.uncheckedAppend(r);
- if (U_IS_SURROGATE(characters[r])) {
- ASSERT(r + 1 < stringLength);
- ASSERT(U_IS_SURROGATE_LEAD(characters[r]));
- ASSERT(U_IS_TRAIL(characters[r + 1]));
+ while (r < m_stringLength) {
+ m_atsuiIndices.uncheckedAppend(r);
+ if (U_IS_SURROGATE(m_characters[r])) {
+ ASSERT(r + 1 < m_stringLength);
+ ASSERT(U_IS_SURROGATE_LEAD(m_characters[r]));
+ ASSERT(U_IS_TRAIL(m_characters[r + 1]));
r += 2;
} else
r++;
}
- m_glyphCount = m_indices.size();
+ m_glyphCount = m_atsuiIndices.size();
if (!ltr) {
for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
- std::swap(m_indices[r], m_indices[end]);
+ std::swap(m_atsuiIndices[r], m_atsuiIndices[end]);
}
m_glyphsVector.fill(0, m_glyphCount);
m_glyphs = m_glyphsVector.data();
- m_advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), m_glyphCount);
+ m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount);
m_advances = m_advancesVector.data();
}
@@ -261,33 +257,37 @@ static bool fontHasMirroringInfo(ATSUFontID fontID)
return false;
}
-static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode)
+static void disableLigatures(const SimpleFontData* fontData, ATSUStyle atsuStyle, TypesettingFeatures typesettingFeatures)
{
// Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are
// in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example.
// See bugzilla 5166.
- if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures())
+ if ((typesettingFeatures & Ligatures) || fontData->platformData().allowsLigatures())
return;
ATSUFontFeatureType featureTypes[] = { kLigaturesType };
ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };
- OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors);
+ OSStatus status = ATSUSetFontFeatures(atsuStyle, 1, featureTypes, featureSelectors);
if (status != noErr)
LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", static_cast<int>(status));
}
-static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode)
+static ATSUStyle initializeATSUStyle(const SimpleFontData* fontData, TypesettingFeatures typesettingFeatures)
{
- if (fontData->m_ATSUStyleInitialized)
- return;
+ unsigned key = typesettingFeatures + 1;
+ pair<HashMap<unsigned, ATSUStyle>::iterator, bool> addResult = fontData->m_ATSUStyleMap.add(key, 0);
+ ATSUStyle& atsuStyle = addResult.first->second;
+ if (!addResult.second)
+ return atsuStyle;
ATSUFontID fontID = fontData->platformData().m_atsuFontID;
if (!fontID) {
LOG_ERROR("unable to get ATSUFontID for %p", fontData->platformData().font());
- return;
+ fontData->m_ATSUStyleMap.remove(addResult.first);
+ return 0;
}
- OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle);
+ OSStatus status = ATSUCreateStyle(&atsuStyle);
if (status != noErr)
LOG_ERROR("ATSUCreateStyle failed (%d)", static_cast<int>(status));
@@ -299,19 +299,18 @@ static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMod
ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };
ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &verticalFlip, &kerningInhibitFactor };
- bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision;
- status = ATSUSetAttributes(fontData->m_ATSUStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues);
+ bool allowKerning = typesettingFeatures & Kerning;
+ status = ATSUSetAttributes(atsuStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues);
if (status != noErr)
LOG_ERROR("ATSUSetAttributes failed (%d)", static_cast<int>(status));
fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID);
- disableLigatures(fontData, textMode);
-
- fontData->m_ATSUStyleInitialized = true;
+ disableLigatures(fontData, atsuStyle, typesettingFeatures);
+ return atsuStyle;
}
-void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+void ComplexTextController::collectComplexTextRunsForCharactersATSUI(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
{
if (!fontData) {
// Create a run of missing glyphs from the primary font.
@@ -322,13 +321,13 @@ void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp,
if (m_fallbackFonts && fontData != m_font.primaryFont())
m_fallbackFonts->add(fontData);
- initializeATSUStyle(fontData, m_font.fontDescription().textRenderingMode());
+ ATSUStyle atsuStyle = initializeATSUStyle(fontData, m_font.typesettingFeatures());
OSStatus status;
ATSUTextLayout atsuTextLayout;
UniCharCount runLength = length;
- status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &fontData->m_ATSUStyle, &atsuTextLayout);
+ status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &atsuStyle, &atsuTextLayout);
if (status != noErr) {
LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed with error %d", static_cast<int>(status));
return;
diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp
index c9daf84..dd5e96a 100644
--- a/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp
+++ b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp
@@ -29,35 +29,44 @@
#include "Font.h"
+#if defined(BUILDING_ON_LEOPARD)
+// The following symbols are SPI in 10.5.
+extern "C" {
+void CTRunGetAdvances(CTRunRef run, CFRange range, CGSize buffer[]);
+const CGSize* CTRunGetAdvancesPtr(CTRunRef run);
+extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
+}
+#endif
+
namespace WebCore {
ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength)
- : m_CTRun(ctRun)
+ : m_coreTextRun(ctRun)
, m_fontData(fontData)
, m_characters(characters)
, m_stringLocation(stringLocation)
, m_stringLength(stringLength)
{
- m_glyphCount = CTRunGetGlyphCount(m_CTRun.get());
- m_indices = CTRunGetStringIndicesPtr(m_CTRun.get());
- if (!m_indices) {
- m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
- CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex));
- m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get()));
- CTRunGetStringIndices(m_CTRun.get(), CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices));
+ m_glyphCount = CTRunGetGlyphCount(m_coreTextRun.get());
+ m_coreTextIndices = CTRunGetStringIndicesPtr(m_coreTextRun.get());
+ if (!m_coreTextIndices) {
+ m_coreTextIndicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
+ CFDataIncreaseLength(m_coreTextIndicesData.get(), m_glyphCount * sizeof(CFIndex));
+ m_coreTextIndices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_coreTextIndicesData.get()));
+ CTRunGetStringIndices(m_coreTextRun.get(), CFRangeMake(0, 0), const_cast<CFIndex*>(m_coreTextIndices));
}
- m_glyphs = CTRunGetGlyphsPtr(m_CTRun.get());
+ m_glyphs = CTRunGetGlyphsPtr(m_coreTextRun.get());
if (!m_glyphs) {
m_glyphsVector.grow(m_glyphCount);
- CTRunGetGlyphs(m_CTRun.get(), CFRangeMake(0, 0), m_glyphsVector.data());
+ CTRunGetGlyphs(m_coreTextRun.get(), CFRangeMake(0, 0), m_glyphsVector.data());
m_glyphs = m_glyphsVector.data();
}
- m_advances = CTRunGetAdvancesPtr(m_CTRun.get());
+ m_advances = CTRunGetAdvancesPtr(m_coreTextRun.get());
if (!m_advances) {
m_advancesVector.grow(m_glyphCount);
- CTRunGetAdvances(m_CTRun.get(), CFRangeMake(0, 0), m_advancesVector.data());
+ CTRunGetAdvances(m_coreTextRun.get(), CFRangeMake(0, 0), m_advancesVector.data());
m_advances = m_advancesVector.data();
}
@@ -65,20 +74,16 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const Simp
// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on
// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path.
-ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
- : m_fontData(fontData)
- , m_characters(characters)
- , m_stringLocation(stringLocation)
- , m_stringLength(stringLength)
+void ComplexTextController::ComplexTextRun::createTextRunFromFontDataCoreText(bool ltr)
{
Vector<CFIndex, 16> indices;
unsigned r = 0;
- while (r < stringLength) {
+ while (r < m_stringLength) {
indices.append(r);
- if (U_IS_SURROGATE(characters[r])) {
- ASSERT(r + 1 < stringLength);
- ASSERT(U_IS_SURROGATE_LEAD(characters[r]));
- ASSERT(U_IS_TRAIL(characters[r + 1]));
+ if (U_IS_SURROGATE(m_characters[r])) {
+ ASSERT(r + 1 < m_stringLength);
+ ASSERT(U_IS_SURROGATE_LEAD(m_characters[r]));
+ ASSERT(U_IS_TRAIL(m_characters[r + 1]));
r += 2;
} else
r++;
@@ -88,9 +93,9 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* font
for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
std::swap(indices[r], indices[end]);
}
- m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
- CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex));
- m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get()));
+ m_coreTextIndicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
+ CFDataAppendBytes(m_coreTextIndicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex));
+ m_coreTextIndices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_coreTextIndicesData.get()));
// Synthesize a run of missing glyphs.
m_glyphsVector.fill(0, m_glyphCount);
@@ -99,7 +104,7 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* font
m_advances = m_advancesVector.data();
}
-void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
{
if (!fontData) {
// Create a run of missing glyphs from the primary font.
@@ -112,7 +117,7 @@ void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp,
RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull));
- RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode())));
+ RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.typesettingFeatures())));
RetainPtr<CTTypesetterRef> typesetter;
diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
index 41f63a9..5e5e1f4 100644
--- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
+++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
@@ -29,28 +29,24 @@
#include "GraphicsContext3D.h"
-#include "CachedImage.h"
+#include "CanvasObject.h"
+#include "CString.h"
+#include "ImageBuffer.h"
+#include "NotImplemented.h"
#include "WebGLActiveInfo.h"
#include "WebGLArray.h"
#include "WebGLBuffer.h"
#include "WebGLFramebuffer.h"
#include "WebGLFloatArray.h"
#include "WebGLIntArray.h"
-#include "CanvasObject.h"
#include "WebGLProgram.h"
#include "WebGLRenderbuffer.h"
#include "WebGLShader.h"
#include "WebGLTexture.h"
#include "WebGLUnsignedByteArray.h"
-#include "CString.h"
-#include "HTMLCanvasElement.h"
-#include "HTMLImageElement.h"
-#include "ImageBuffer.h"
-#include "NotImplemented.h"
-#include "WebKitCSSMatrix.h"
-
#include <CoreGraphics/CGBitmapContext.h>
#include <OpenGL/CGLRenderers.h>
+#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -79,18 +75,29 @@ static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBi
attribs.append(static_cast<CGLPixelFormatAttribute>(0));
}
-PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create()
+PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs)
{
- OwnPtr<GraphicsContext3D> context(new GraphicsContext3D());
+ OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs));
return context->m_contextObj ? context.release() : 0;
}
-GraphicsContext3D::GraphicsContext3D()
- : m_contextObj(0)
+GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs)
+ : m_attrs(attrs)
+ , m_contextObj(0)
, m_texture(0)
, m_fbo(0)
, m_depthBuffer(0)
{
+ // FIXME: we need to take into account the user's requested
+ // context creation attributes, in particular stencil and
+ // antialias, and determine which could and could not be honored
+ // based on the capabilities of the OpenGL implementation.
+ m_attrs.alpha = true;
+ m_attrs.depth = true;
+ m_attrs.stencil = false;
+ m_attrs.antialias = false;
+ m_attrs.premultipliedAlpha = true;
+
Vector<CGLPixelFormatAttribute> attribs;
CGLPixelFormatObj pixelFormatObj = 0;
GLint numPixelFormats = 0;
@@ -262,7 +269,7 @@ void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer)
void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer)
{
ensureContext(m_contextObj);
- ::glBindFramebufferEXT(target, buffer ? (GLuint) buffer->object() : m_fbo);
+ ::glBindFramebufferEXT(target, (buffer && buffer->object()) ? (GLuint) buffer->object() : m_fbo);
}
void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer)
@@ -544,6 +551,11 @@ int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& na
return ::glGetAttribLocation((GLuint) program->object(), name.utf8().data());
}
+GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes()
+{
+ return m_attrs;
+}
+
unsigned long GraphicsContext3D::getError()
{
if (m_syntheticErrors.size() > 0) {
@@ -1115,55 +1127,38 @@ long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long
return reinterpret_cast<long>(pointer);
}
-// Assumes the texture you want to go into is bound
-static void imageToTexture(Image* image, unsigned target, unsigned level)
+// Returned pointer must be freed by fastFree()
+static bool imageToTexture(Image* image, GLubyte*& buffer, size_t& width, size_t& height)
{
if (!image)
- return;
+ return false;
CGImageRef textureImage = image->getCGImageRef();
if (!textureImage)
- return;
+ return false;
- size_t textureWidth = CGImageGetWidth(textureImage);
- size_t textureHeight = CGImageGetHeight(textureImage);
+ width = CGImageGetWidth(textureImage);
+ height = CGImageGetHeight(textureImage);
- GLubyte* textureData = (GLubyte*) fastMalloc(textureWidth * textureHeight * 4);
- if (!textureData)
- return;
+ buffer = (GLubyte*) fastMalloc(width * height * 4);
+ if (!buffer)
+ return false;
- CGContextRef textureContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, 8, textureWidth * 4,
+ CGContextRef textureContext = CGBitmapContextCreate(buffer, width, height, 8, width * 4,
CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast);
CGContextSetBlendMode(textureContext, kCGBlendModeCopy);
- CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)textureWidth, (CGFloat)textureHeight), textureImage);
+ CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)width, (CGFloat)height), textureImage);
CGContextRelease(textureContext);
-
- ::glTexImage2D(target, level, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
- fastFree(textureData);
+ return true;
}
-int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, WebGLArray* pixels)
+int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels)
{
// FIXME: Need to do bounds checking on the buffer here.
- ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels->baseAddress());
+ ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
return 0;
}
-int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, ImageData* pixels)
-{
- // FIXME: need to implement this form
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(internalformat);
- UNUSED_PARAM(width);
- UNUSED_PARAM(height);
- UNUSED_PARAM(border);
- UNUSED_PARAM(format);
- UNUSED_PARAM(type);
- UNUSED_PARAM(pixels);
- return -1;
-}
-
int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha)
{
// FIXME: need to support flipY and premultiplyAlpha
@@ -1172,85 +1167,43 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image,
ASSERT(image);
ensureContext(m_contextObj);
- imageToTexture(image, target, level);
+ GLubyte* buffer;
+ size_t width;
+ size_t height;
+ if (!imageToTexture(image, buffer, width, height))
+ return -1;
+
+ ::glTexImage2D(target, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+ fastFree(buffer);
return 0;
}
-
-int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha)
-{
- // FIXME: need to implement this form
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(video);
-
- // FIXME: need to support flipY and premultiplyAlpha
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
- return -1;
-}
-
-int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, WebGLArray* pixels)
-{
- // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(xoff);
- UNUSED_PARAM(yoff);
- UNUSED_PARAM(width);
- UNUSED_PARAM(height);
- UNUSED_PARAM(format);
- UNUSED_PARAM(type);
- UNUSED_PARAM(pixels);
- return -1;
-}
-
-int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, ImageData* pixels)
-{
- // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(xoff);
- UNUSED_PARAM(yoff);
- UNUSED_PARAM(width);
- UNUSED_PARAM(height);
- UNUSED_PARAM(format);
- UNUSED_PARAM(type);
- UNUSED_PARAM(pixels);
- return -1;
-}
-
-int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, Image* image, bool flipY, bool premultiplyAlpha)
+
+int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, void* pixels)
{
// FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(xoff);
- UNUSED_PARAM(yoff);
- UNUSED_PARAM(width);
- UNUSED_PARAM(height);
- UNUSED_PARAM(image);
-
- // FIXME: need to support flipY and premultiplyAlpha
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
- return -1;
+ // FIXME: Need to do bounds checking on the buffer here.
+ ::glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels);
+ return 0;
}
-int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha)
+int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, Image* image, bool flipY, bool premultiplyAlpha)
{
// FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(xoff);
- UNUSED_PARAM(yoff);
- UNUSED_PARAM(width);
- UNUSED_PARAM(height);
- UNUSED_PARAM(video);
-
- // FIXME: need to support flipY and premultiplyAlpha
+ // FIXME: need to support flipY and premultiplyAlpha
UNUSED_PARAM(flipY);
UNUSED_PARAM(premultiplyAlpha);
- return -1;
+ ASSERT(image);
+
+ ensureContext(m_contextObj);
+ GLubyte* buffer;
+ size_t width;
+ size_t height;
+ if (!imageToTexture(image, buffer, width, height))
+ return -1;
+
+ ::glTexSubImage2D(target, level, xoff, yoff, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+ fastFree(buffer);
+ return 0;
}
unsigned GraphicsContext3D::createBuffer()
diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
index 6c9b872..5f111f6 100644
--- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm
+++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
@@ -26,7 +26,7 @@
#import "config.h"
#import "GraphicsContext.h"
-#import "../cg/GraphicsContextPlatformPrivateCG.h"
+#import "GraphicsContextPlatformPrivateCG.h"
#import <AppKit/AppKit.h>
#import <wtf/StdLibExtras.h>
@@ -43,33 +43,55 @@ namespace WebCore {
// calls in this file are all exception-safe, so we don't block
// exceptions for those.
-void GraphicsContext::drawFocusRing(const Color& color)
+static void drawFocusRingToContext(CGContextRef context, RetainPtr<CGPathRef> focusRingPath, RetainPtr<CGColorRef> colorRef, int radius)
+{
+#ifdef BUILDING_ON_TIGER
+ CGContextBeginTransparencyLayer(context, 0);
+#endif
+ CGContextBeginPath(context);
+ CGContextAddPath(context, focusRingPath.get());
+ wkDrawFocusRing(context, colorRef.get(), radius);
+#ifdef BUILDING_ON_TIGER
+ CGContextEndTransparencyLayer(context);
+#endif
+}
+
+void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ int radius = (width - 1) / 2;
+ offset += radius;
+ RetainPtr<CGColorRef> colorRef;
+ if (color.isValid())
+ colorRef.adoptCF(createCGColor(color));
+
+ RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable());
+ unsigned pathCount = paths.size();
+ for (unsigned i = 0; i < pathCount; i++)
+ CGPathAddPath(focusRingPath.get(), 0, paths[i].platformPath());
+
+ drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius);
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
{
if (paintingDisabled())
return;
- int radius = (focusRingWidth() - 1) / 2;
- int offset = radius + focusRingOffset();
+ int radius = (width - 1) / 2;
+ offset += radius;
RetainPtr<CGColorRef> colorRef;
if (color.isValid())
colorRef.adoptCF(createCGColor(color));
RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable());
- const Vector<IntRect>& rects = focusRingRects();
unsigned rectCount = rects.size();
for (unsigned i = 0; i < rectCount; i++)
CGPathAddRect(focusRingPath.get(), 0, CGRectInset(rects[i], -offset, -offset));
- CGContextRef context = platformContext();
-#ifdef BUILDING_ON_TIGER
- CGContextBeginTransparencyLayer(context, NULL);
-#endif
- CGContextBeginPath(context);
- CGContextAddPath(context, focusRingPath.get());
- wkDrawFocusRing(context, colorRef.get(), radius);
-#ifdef BUILDING_ON_TIGER
- CGContextEndTransparencyLayer(context);
-#endif
+ drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius);
}
#ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp.
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
index 8024091..5362562 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
@@ -30,16 +30,16 @@
#include "GraphicsLayer.h"
#include "StringHash.h"
+#include "WebLayer.h"
+#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/RetainPtr.h>
@class CABasicAnimation;
@class CAKeyframeAnimation;
-@class CALayer;
@class CAMediaTimingFunction;
@class CAPropertyAnimation;
@class WebAnimationDelegate;
-@class WebLayer;
namespace WebCore {
@@ -64,6 +64,7 @@ public:
virtual void removeFromParent();
virtual void setMaskLayer(GraphicsLayer*);
+ virtual void setReplicatedLayer(GraphicsLayer*);
virtual void setPosition(const FloatPoint&);
virtual void setAnchorPoint(const FloatPoint3D&);
@@ -98,13 +99,13 @@ public:
virtual void suspendAnimations(double time);
virtual void resumeAnimations();
- virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double beginTime);
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double timeOffset);
virtual void removeAnimationsForProperty(AnimatedPropertyID);
virtual void removeAnimationsForKeyframes(const String& keyframesName);
- virtual void pauseAnimation(const String& keyframesName);
+ virtual void pauseAnimation(const String& keyframesName, double timeOffset);
virtual void setContentsToImage(Image*);
- virtual void setContentsToVideo(PlatformLayer*);
+ virtual void setContentsToMedia(PlatformLayer*);
#if ENABLE(3D_CANVAS)
virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*);
#endif
@@ -116,8 +117,9 @@ public:
virtual void setGeometryOrientation(CompositingCoordinatesOrientation);
+ virtual void didDisplay(PlatformLayer*);
+
void recursiveCommitChanges();
- void commitLayerChanges();
virtual void syncCompositingState();
@@ -127,13 +129,20 @@ protected:
private:
void updateOpacityOnLayer();
- WebLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
- WebLayer* hostLayerForSublayers() const;
- WebLayer* layerForSuperlayer() const;
+ CALayer* primaryLayer() const { return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); }
+ CALayer* hostLayerForSublayers() const;
+ CALayer* layerForSuperlayer() const;
CALayer* animatedLayer(AnimatedPropertyID property) const;
- bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double beginTime);
- bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double beginTime, const IntSize& boxSize);
+ typedef String CloneID; // Identifier for a given clone, based on original/replica branching down the tree.
+ static bool isReplicatedRootClone(const CloneID& cloneID) { return cloneID[0U] & 1; }
+
+ typedef HashMap<CloneID, RetainPtr<CALayer> > LayerMap;
+ LayerMap* primaryLayerClones() const { return m_structuralLayer.get() ? m_structuralLayerClones.get() : m_layerClones.get(); }
+ LayerMap* animatedLayerClones(AnimatedPropertyID property) const;
+
+ bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double timeOffset);
+ bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double timeOffset, const IntSize& boxSize);
// Return autoreleased animation (use RetainPtr?)
CABasicAnimation* createBasicAnimation(const Animation*, AnimatedPropertyID, bool additive);
@@ -153,6 +162,9 @@ private:
return m_runningKeyframeAnimations.find(keyframesName) != m_runningKeyframeAnimations.end();
}
+ void commitLayerChangesBeforeSublayers();
+ void commitLayerChangesAfterSublayers();
+
bool requiresTiledLayer(const FloatSize&) const;
void swapFromOrToTiledLayer(bool useTiledLayer);
@@ -161,8 +173,75 @@ private:
void setupContentsLayer(CALayer*);
CALayer* contentsLayer() const { return m_contentsLayer.get(); }
+
+ virtual void setReplicatedByLayer(GraphicsLayer*);
+
+ // Used to track the path down the tree for replica layers.
+ struct ReplicaState {
+ static const size_t maxReplicaDepth = 16;
+ enum ReplicaBranchType { ChildBranch = 0, ReplicaBranch = 1 };
+ ReplicaState(ReplicaBranchType firstBranch)
+ : m_replicaDepth(0)
+ {
+ push(firstBranch);
+ }
+
+ // Called as we walk down the tree to build replicas.
+ void push(ReplicaBranchType branchType)
+ {
+ m_replicaBranches.append(branchType);
+ if (branchType == ReplicaBranch)
+ ++m_replicaDepth;
+ }
+
+ void setBranchType(ReplicaBranchType branchType)
+ {
+ ASSERT(!m_replicaBranches.isEmpty());
+
+ if (m_replicaBranches.last() != branchType) {
+ if (branchType == ReplicaBranch)
+ ++m_replicaDepth;
+ else
+ --m_replicaDepth;
+ }
+
+ m_replicaBranches.last() = branchType;
+ }
+
+ void pop()
+ {
+ if (m_replicaBranches.last() == ReplicaBranch)
+ --m_replicaDepth;
+ m_replicaBranches.removeLast();
+ }
+
+ size_t depth() const { return m_replicaBranches.size(); }
+ size_t replicaDepth() const { return m_replicaDepth; }
+
+ CloneID cloneID() const;
+
+ private:
+ Vector<ReplicaBranchType> m_replicaBranches;
+ size_t m_replicaDepth;
+ };
+ CALayer *replicatedLayerRoot(ReplicaState&);
+
+ enum CloneLevel { RootCloneLevel, IntermediateCloneLevel };
+ CALayer *fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState&, CloneLevel);
+
+ CALayer *cloneLayer(CALayer *, CloneLevel);
+ CALayer *findOrMakeClone(CloneID, CALayer *, LayerMap*, CloneLevel);
+
+ void ensureCloneLayers(CloneID index, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel);
+
+ bool hasCloneLayers() const { return m_layerClones; }
+ void removeCloneLayers();
+ FloatPoint positionForCloneRootLayer() const;
+
+ void propagateLayerChangeToReplicas();
// All these "update" methods will be called inside a BEGIN_BLOCK_OBJC_EXCEPTIONS/END_BLOCK_OBJC_EXCEPTIONS block.
+ void updateLayerNames();
void updateSublayerList();
void updateLayerPosition();
void updateLayerSize();
@@ -172,25 +251,38 @@ private:
void updateMasksToBounds();
void updateContentsOpaque();
void updateBackfaceVisibility();
- void updateLayerPreserves3D();
+ void updateStructuralLayer();
void updateLayerDrawsContent();
void updateLayerBackgroundColor();
void updateContentsImage();
- void updateContentsVideo();
+ void updateContentsMediaLayer();
#if ENABLE(3D_CANVAS)
void updateContentsGraphicsContext3D();
#endif
void updateContentsRect();
void updateGeometryOrientation();
void updateMaskLayer();
+ void updateReplicatedLayers();
void updateLayerAnimations();
+
+ enum StructuralLayerPurpose {
+ NoStructuralLayer = 0,
+ StructuralLayerForPreserves3D,
+ StructuralLayerForReplicaFlattening
+ };
+ void ensureStructuralLayer(StructuralLayerPurpose);
+ StructuralLayerPurpose structuralLayerPurpose() const;
- void setAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, int index, double beginTime);
- bool removeAnimationFromLayer(AnimatedPropertyID, int index);
- void pauseAnimationOnLayer(AnimatedPropertyID, int index);
+ void setAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, const String& keyframesName, int index, double timeOffset);
+ bool removeAnimationFromLayer(AnimatedPropertyID, const String& keyframesName, int index);
+ void pauseAnimationOnLayer(AnimatedPropertyID, const String& keyframesName, int index, double timeOffset);
+ enum MoveOrCopy { Move, Copy };
+ void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID property, CALayer * fromLayer, CALayer * toLayer);
+ static void moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer * fromLayer, CALayer * toLayer);
+
enum LayerChange {
NoChange = 0,
NameChanged = 1 << 1,
@@ -210,27 +302,34 @@ private:
AnimationChanged = 1 << 15,
DirtyRectsChanged = 1 << 16,
ContentsImageChanged = 1 << 17,
- ContentsVideoChanged = 1 << 18,
+ ContentsMediaLayerChanged = 1 << 18,
#if ENABLE(3D_CANVAS)
ContentsGraphicsContext3DChanged = 1 << 19,
#endif
ContentsRectChanged = 1 << 20,
GeometryOrientationChanged = 1 << 21,
- MaskLayerChanged = 1 << 22
+ MaskLayerChanged = 1 << 22,
+ ReplicatedLayerChanged = 1 << 23
};
typedef unsigned LayerChangeFlags;
void noteLayerPropertyChanged(LayerChangeFlags flags);
+ void noteSublayersChanged();
void repaintLayerDirtyRects();
- RetainPtr<WebLayer> m_layer;
- RetainPtr<WebLayer> m_transformLayer;
- RetainPtr<CALayer> m_contentsLayer;
+ RetainPtr<WebLayer> m_layer; // The main layer
+ RetainPtr<CALayer> m_structuralLayer; // A layer used for structural reasons, like preserves-3d or replica-flattening. Is the parent of m_layer.
+ RetainPtr<CALayer> m_contentsLayer; // A layer used for inner content, like image and video
+
+ // References to clones of our layers, for replicated layers.
+ OwnPtr<LayerMap> m_layerClones;
+ OwnPtr<LayerMap> m_structuralLayerClones;
+ OwnPtr<LayerMap> m_contentsLayerClones;
enum ContentsLayerPurpose {
NoContentsLayer = 0,
ContentsLayerForImage,
- ContentsLayerForVideo
+ ContentsLayerForMedia
#if ENABLE(3D_CANVAS)
,ContentsLayerForGraphicsLayer3D
#endif
@@ -244,19 +343,19 @@ private:
RetainPtr<CGImageRef> m_pendingContentsImage;
struct LayerAnimation {
- LayerAnimation(CAPropertyAnimation* caAnim, const String& keyframesName, AnimatedPropertyID property, int index, double beginTime)
+ LayerAnimation(CAPropertyAnimation* caAnim, const String& keyframesName, AnimatedPropertyID property, int index, double timeOffset)
: m_animation(caAnim)
, m_keyframesName(keyframesName)
, m_property(property)
, m_index(index)
- , m_beginTime(beginTime)
+ , m_timeOffset(timeOffset)
{ }
RetainPtr<CAPropertyAnimation*> m_animation;
String m_keyframesName;
AnimatedPropertyID m_property;
int m_index;
- double m_beginTime;
+ double m_timeOffset;
};
Vector<LayerAnimation> m_uncomittedAnimations;
@@ -267,8 +366,16 @@ private:
HashSet<AnimatedProperty> m_transitionPropertiesToRemove;
- enum { Remove, Pause };
- typedef int AnimationProcessingAction;
+ enum Action { Remove, Pause };
+ struct AnimationProcessingAction {
+ AnimationProcessingAction(Action action = Remove, double timeOffset = 0)
+ : action(action)
+ , timeOffset(timeOffset)
+ {
+ }
+ Action action;
+ double timeOffset; // only used for pause
+ };
typedef HashMap<String, AnimationProcessingAction> AnimationsToProcessMap;
AnimationsToProcessMap m_keyframeAnimationsToProcess;
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
index dea6bfc..22e39f5 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
@@ -42,6 +42,7 @@
#import <QuartzCore/QuartzCore.h>
#import "RotateTransformOperation.h"
#import "ScaleTransformOperation.h"
+#import "StringBuilder.h"
#import "SystemTime.h"
#import "TranslateTransformOperation.h"
#import "WebLayer.h"
@@ -86,6 +87,10 @@ static double mediaTimeToCurrentTime(CFTimeInterval t)
} // namespace WebCore
+@interface CALayer(Private)
+- (void)setContentsChanged;
+@end
+
@interface WebAnimationDelegate : NSObject {
WebCore::GraphicsLayerCA* m_graphicsLayer;
}
@@ -246,12 +251,20 @@ static String propertyIdToString(AnimatedPropertyID property)
return "";
}
-static String animationIdentifier(AnimatedPropertyID property, int index)
+static String animationIdentifier(AnimatedPropertyID property, const String& keyframesName, int index)
{
- String animationId = propertyIdToString(property);
- animationId.append("_");
- animationId.append(String::number(index));
- return animationId;
+ StringBuilder builder;
+
+ builder.append(propertyIdToString(property));
+ builder.append("_");
+
+ if (!keyframesName.isEmpty()) {
+ builder.append(keyframesName);
+ builder.append("_");
+ }
+ builder.append("_");
+ builder.append(String::number(index));
+ return builder.toString();
}
#if !HAVE_MODERN_QUARTZCORE
@@ -392,9 +405,17 @@ GraphicsLayerCA::~GraphicsLayerCA()
[layer setLayerOwner:nil];
}
+ if (m_contentsLayer) {
+ if ([m_contentsLayer.get() respondsToSelector:@selector(setLayerOwner:)])
+ [(id)m_contentsLayer.get() setLayerOwner:nil];
+ }
+
// animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
[m_animationDelegate.get() setLayer:0];
+ // Release the clone layers inside the exception-handling block.
+ removeCloneLayers();
+
END_BLOCK_OBJC_EXCEPTIONS
}
@@ -414,7 +435,7 @@ bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
{
bool childrenChanged = GraphicsLayer::setChildren(children);
if (childrenChanged)
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
return childrenChanged;
}
@@ -422,31 +443,31 @@ bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
{
GraphicsLayer::addChild(childLayer);
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
}
void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
{
GraphicsLayer::addChildAtIndex(childLayer, index);
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
}
void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
{
GraphicsLayer::addChildBelow(childLayer, sibling);
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
}
void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
{
GraphicsLayer::addChildAbove(childLayer, sibling);
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
}
bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
{
if (GraphicsLayer::replaceChild(oldChild, newChild)) {
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
return true;
}
return false;
@@ -455,7 +476,7 @@ bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newCh
void GraphicsLayerCA::removeFromParent()
{
if (m_parent)
- static_cast<GraphicsLayerCA*>(m_parent)->noteLayerPropertyChanged(ChildrenChanged);
+ static_cast<GraphicsLayerCA*>(m_parent)->noteSublayersChanged();
GraphicsLayer::removeFromParent();
}
@@ -466,6 +487,30 @@ void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer)
GraphicsLayer::setMaskLayer(layer);
noteLayerPropertyChanged(MaskLayerChanged);
+
+ propagateLayerChangeToReplicas();
+
+ if (m_replicatedLayer)
+ static_cast<GraphicsLayerCA*>(m_replicatedLayer)->propagateLayerChangeToReplicas();
+}
+
+void GraphicsLayerCA::setReplicatedLayer(GraphicsLayer* layer)
+{
+ if (layer == m_replicatedLayer)
+ return;
+
+ GraphicsLayer::setReplicatedLayer(layer);
+ noteLayerPropertyChanged(ReplicatedLayerChanged);
+}
+
+void GraphicsLayerCA::setReplicatedByLayer(GraphicsLayer* layer)
+{
+ if (layer == m_replicaLayer)
+ return;
+
+ GraphicsLayer::setReplicatedByLayer(layer);
+ noteSublayersChanged();
+ noteLayerPropertyChanged(ReplicatedLayerChanged);
}
void GraphicsLayerCA::setPosition(const FloatPoint& point)
@@ -513,22 +558,41 @@ void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
noteLayerPropertyChanged(ChildrenTransformChanged);
}
-static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
+void GraphicsLayerCA::moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer *fromLayer, CALayer *toLayer)
{
for (int index = 0; ; ++index) {
- String animName = animationIdentifier(property, index);
+ String animName = animationIdentifier(property, keyframesName, index);
CAAnimation* anim = [fromLayer animationForKey:animName];
if (!anim)
break;
- [anim retain];
- [fromLayer removeAnimationForKey:animName];
- [toLayer addAnimation:anim forKey:animName];
- [anim release];
+ switch (operation) {
+ case Move:
+ [anim retain];
+ [fromLayer removeAnimationForKey:animName];
+ [toLayer addAnimation:anim forKey:animName];
+ [anim release];
+ break;
+
+ case Copy:
+ [toLayer addAnimation:anim forKey:animName];
+ break;
+ }
}
}
+void GraphicsLayerCA::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, CALayer *fromLayer, CALayer *toLayer)
+{
+ // Move transitions for this property.
+ moveOrCopyAllAnimationsForProperty(operation, property, "", fromLayer, toLayer);
+
+ // Look for running animations affecting this property.
+ KeyframeAnimationsMap::const_iterator end = m_runningKeyframeAnimations.end();
+ for (KeyframeAnimationsMap::const_iterator it = m_runningKeyframeAnimations.begin(); it != end; ++it)
+ moveOrCopyAllAnimationsForProperty(operation, property, it->first, fromLayer, toLayer);
+}
+
void GraphicsLayerCA::setPreserves3D(bool preserves3D)
{
if (preserves3D == m_preserves3D)
@@ -643,7 +707,7 @@ void GraphicsLayerCA::setContentsRect(const IntRect& rect)
noteLayerPropertyChanged(ContentsRectChanged);
}
-bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double beginTime)
+bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset)
{
if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
return false;
@@ -657,9 +721,9 @@ bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const Int
bool createdAnimations = false;
if (valueList.property() == AnimatedPropertyWebkitTransform)
- createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, beginTime, boxSize);
+ createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, timeOffset, boxSize);
else
- createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, beginTime);
+ createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, timeOffset);
if (createdAnimations)
noteLayerPropertyChanged(AnimationChanged);
@@ -681,22 +745,23 @@ void GraphicsLayerCA::removeAnimationsForKeyframes(const String& animationName)
if (!animationIsRunning(animationName))
return;
- m_keyframeAnimationsToProcess.add(animationName, Remove);
+ m_keyframeAnimationsToProcess.add(animationName, AnimationProcessingAction(Remove));
noteLayerPropertyChanged(AnimationChanged);
}
-void GraphicsLayerCA::pauseAnimation(const String& keyframesName)
+void GraphicsLayerCA::pauseAnimation(const String& keyframesName, double timeOffset)
{
if (!animationIsRunning(keyframesName))
return;
AnimationsToProcessMap::iterator it = m_keyframeAnimationsToProcess.find(keyframesName);
if (it != m_keyframeAnimationsToProcess.end()) {
+ AnimationProcessingAction& processingInfo = it->second;
// If an animation is scheduled to be removed, don't change the remove to a pause.
- if (it->second != Remove)
- it->second = Pause;
+ if (processingInfo.action != Remove)
+ processingInfo.action = Pause;
} else
- m_keyframeAnimationsToProcess.add(keyframesName, Pause);
+ m_keyframeAnimationsToProcess.add(keyframesName, AnimationProcessingAction(Pause, timeOffset));
noteLayerPropertyChanged(AnimationChanged);
}
@@ -716,26 +781,27 @@ void GraphicsLayerCA::setContentsToImage(Image* image)
}
m_contentsLayerPurpose = ContentsLayerForImage;
if (!m_contentsLayer)
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
} else {
m_pendingContentsImage = 0;
m_contentsLayerPurpose = NoContentsLayer;
if (m_contentsLayer)
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
}
noteLayerPropertyChanged(ContentsImageChanged);
}
-void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
+void GraphicsLayerCA::setContentsToMedia(PlatformLayer* mediaLayer)
{
- if (videoLayer != m_contentsLayer.get())
- noteLayerPropertyChanged(ChildrenChanged);
+ if (mediaLayer == m_contentsLayer)
+ return;
- m_contentsLayer = videoLayer;
- noteLayerPropertyChanged(ContentsVideoChanged);
+ m_contentsLayer = mediaLayer;
+ m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer;
- m_contentsLayerPurpose = videoLayer ? ContentsLayerForVideo : NoContentsLayer;
+ noteSublayersChanged();
+ noteLayerPropertyChanged(ContentsMediaLayerChanged);
}
void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation orientation)
@@ -760,6 +826,35 @@ void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation o
#endif
}
+void GraphicsLayerCA::didDisplay(PlatformLayer* layer)
+{
+ CALayer* sourceLayer;
+ LayerMap* layerCloneMap;
+
+ if (layer == m_layer) {
+ sourceLayer = m_layer.get();
+ layerCloneMap = m_layerClones.get();
+ } else if (layer == m_contentsLayer) {
+ sourceLayer = m_contentsLayer.get();
+ layerCloneMap = m_contentsLayerClones.get();
+ } else
+ return;
+
+ if (layerCloneMap) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currClone = it->second.get();
+ if (!currClone)
+ continue;
+
+ if ([currClone contents] != [sourceLayer contents])
+ [currClone setContents:[sourceLayer contents]];
+ else
+ [currClone setContentsChanged];
+ }
+ }
+}
+
void GraphicsLayerCA::syncCompositingState()
{
recursiveCommitChanges();
@@ -767,10 +862,10 @@ void GraphicsLayerCA::syncCompositingState()
void GraphicsLayerCA::recursiveCommitChanges()
{
- commitLayerChanges();
+ commitLayerChangesBeforeSublayers();
if (m_maskLayer)
- static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChanges();
+ static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesBeforeSublayers();
const Vector<GraphicsLayer*>& childLayers = children();
size_t numChildren = childLayers.size();
@@ -778,9 +873,17 @@ void GraphicsLayerCA::recursiveCommitChanges()
GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
curChild->recursiveCommitChanges();
}
+
+ if (m_replicaLayer)
+ static_cast<GraphicsLayerCA*>(m_replicaLayer)->recursiveCommitChanges();
+
+ if (m_maskLayer)
+ static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesAfterSublayers();
+
+ commitLayerChangesAfterSublayers();
}
-void GraphicsLayerCA::commitLayerChanges()
+void GraphicsLayerCA::commitLayerChangesBeforeSublayers()
{
if (!m_uncommittedChanges)
return;
@@ -788,20 +891,17 @@ void GraphicsLayerCA::commitLayerChanges()
BEGIN_BLOCK_OBJC_EXCEPTIONS
// Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to
- if (m_uncommittedChanges & Preserves3DChanged)
- updateLayerPreserves3D();
+ if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged))
+ updateStructuralLayer();
- if (m_uncommittedChanges & NameChanged) {
- if (m_transformLayer)
- [m_transformLayer.get() setName:("Transform layer " + name())];
- [m_layer.get() setName:name()];
- }
+ if (m_uncommittedChanges & NameChanged)
+ updateLayerNames();
if (m_uncommittedChanges & ContentsImageChanged) // Needs to happen before ChildrenChanged
updateContentsImage();
- if (m_uncommittedChanges & ContentsVideoChanged) // Needs to happen before ChildrenChanged
- updateContentsVideo();
+ if (m_uncommittedChanges & ContentsMediaLayerChanged) // Needs to happen before ChildrenChanged
+ updateContentsMediaLayer();
#if ENABLE(3D_CANVAS)
if (m_uncommittedChanges & ContentsGraphicsContext3DChanged) // Needs to happen before ChildrenChanged
@@ -859,40 +959,72 @@ void GraphicsLayerCA::commitLayerChanges()
if (m_uncommittedChanges & MaskLayerChanged)
updateMaskLayer();
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::commitLayerChangesAfterSublayers()
+{
+ if (!m_uncommittedChanges)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (m_uncommittedChanges & ReplicatedLayerChanged)
+ updateReplicatedLayers();
+
m_uncommittedChanges = NoChange;
END_BLOCK_OBJC_EXCEPTIONS
}
+void GraphicsLayerCA::updateLayerNames()
+{
+ switch (structuralLayerPurpose()) {
+ case StructuralLayerForPreserves3D:
+ [m_structuralLayer.get() setName:("Transform layer " + name())];
+ break;
+ case StructuralLayerForReplicaFlattening:
+ [m_structuralLayer.get() setName:("Replica flattening layer " + name())];
+ break;
+ case NoStructuralLayer:
+ break;
+ }
+ [m_layer.get() setName:name()];
+}
+
void GraphicsLayerCA::updateSublayerList()
{
NSMutableArray* newSublayers = nil;
- if (m_transformLayer) {
- // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind.
- newSublayers = [[NSMutableArray alloc] initWithObjects:m_layer.get(), nil];
- } else if (m_contentsLayer) {
- // FIXME: add the contents layer in the correct order with negative z-order children.
- // This does not cause visible rendering issues because currently contents layers are only used
- // for replaced elements that don't have children.
- newSublayers = [[NSMutableArray alloc] initWithObjects:m_contentsLayer.get(), nil];
- }
-
const Vector<GraphicsLayer*>& childLayers = children();
- size_t numChildren = childLayers.size();
- for (size_t i = 0; i < numChildren; ++i) {
- GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
-
- CALayer* childLayer = curChild->layerForSuperlayer();
- if (!newSublayers)
- newSublayers = [[NSMutableArray alloc] initWithObjects:childLayer, nil];
- else
+
+ if (m_structuralLayer || m_contentsLayer || childLayers.size() > 0) {
+ newSublayers = [[NSMutableArray alloc] init];
+
+ if (m_structuralLayer) {
+ // Add the replica layer first.
+ if (m_replicaLayer)
+ [newSublayers addObject:static_cast<GraphicsLayerCA*>(m_replicaLayer)->primaryLayer()];
+ // Add the primary layer. Even if we have negative z-order children, the primary layer always comes behind.
+ [newSublayers addObject:m_layer.get()];
+ } else if (m_contentsLayer) {
+ // FIXME: add the contents layer in the correct order with negative z-order children.
+ // This does not cause visible rendering issues because currently contents layers are only used
+ // for replaced elements that don't have children.
+ [newSublayers addObject:m_contentsLayer.get()];
+ }
+
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+ CALayer *childLayer = curChild->layerForSuperlayer();
[newSublayers addObject:childLayer];
- }
+ }
- [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
+ [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
+ }
- if (m_transformLayer) {
- safeSetSublayers(m_transformLayer.get(), newSublayers);
+ if (m_structuralLayer) {
+ safeSetSublayers(m_structuralLayer.get(), newSublayers);
if (m_contentsLayer) {
// If we have a transform layer, then the contents layer is parented in the
@@ -913,16 +1045,43 @@ void GraphicsLayerCA::updateLayerPosition()
m_position.y() + m_anchorPoint.y() * m_size.height());
[primaryLayer() setPosition:posPoint];
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CGPoint clonePosition = posPoint;
+ if (m_replicaLayer && isReplicatedRootClone(it->first)) {
+ // Maintain the special-case position for the root of a clone subtree,
+ // which we set up in replicatedLayerRoot().
+ clonePosition = positionForCloneRootLayer();
+ }
+ CALayer *currLayer = it->second.get();
+ [currLayer setPosition:clonePosition];
+ }
+ }
}
void GraphicsLayerCA::updateLayerSize()
{
CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height());
- if (m_transformLayer) {
- [m_transformLayer.get() setBounds:rect];
+ if (m_structuralLayer) {
+ [m_structuralLayer.get() setBounds:rect];
+
+ if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ [it->second.get() setBounds:rect];
+ }
+
// The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
[m_layer.get() setPosition:centerPoint];
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ [it->second.get() setPosition:centerPoint];
+ }
}
bool needTiledLayer = requiresTiledLayer(m_size);
@@ -930,6 +1089,11 @@ void GraphicsLayerCA::updateLayerSize()
swapFromOrToTiledLayer(needTiledLayer);
[m_layer.get() setBounds:rect];
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it)
+ [it->second.get() setBounds:rect];
+ }
// Contents transform may depend on height.
updateContentsTransform();
@@ -947,6 +1111,18 @@ void GraphicsLayerCA::updateAnchorPoint()
#if HAVE_MODERN_QUARTZCORE
[primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
#endif
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ [currLayer setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())];
+#if HAVE_MODERN_QUARTZCORE
+ [currLayer setAnchorPointZ:m_anchorPoint.z()];
+#endif
+ }
+ }
+
updateLayerPosition();
}
@@ -955,6 +1131,19 @@ void GraphicsLayerCA::updateTransform()
CATransform3D transform;
copyTransform(transform, m_transform);
[primaryLayer() setTransform:transform];
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ if (m_replicaLayer && isReplicatedRootClone(it->first)) {
+ // Maintain the special-case transform for the root of a clone subtree,
+ // which we set up in replicatedLayerRoot().
+ [currLayer setTransform:CATransform3DIdentity];
+ } else
+ [currLayer setTransform:transform];
+ }
+ }
}
void GraphicsLayerCA::updateChildrenTransform()
@@ -962,85 +1151,157 @@ void GraphicsLayerCA::updateChildrenTransform()
CATransform3D transform;
copyTransform(transform, m_childrenTransform);
[primaryLayer() setSublayerTransform:transform];
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ [currLayer setSublayerTransform:transform];
+ }
+ }
}
void GraphicsLayerCA::updateMasksToBounds()
{
[m_layer.get() setMasksToBounds:m_masksToBounds];
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ [currLayer setMasksToBounds:m_masksToBounds];
+ }
+ }
+
updateDebugIndicators();
}
void GraphicsLayerCA::updateContentsOpaque()
{
[m_layer.get() setOpaque:m_contentsOpaque];
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ [currLayer setOpaque:m_contentsOpaque];
+ }
+ }
}
void GraphicsLayerCA::updateBackfaceVisibility()
{
[m_layer.get() setDoubleSided:m_backfaceVisibility];
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ [currLayer setDoubleSided:m_backfaceVisibility];
+ }
+ }
}
-void GraphicsLayerCA::updateLayerPreserves3D()
+void GraphicsLayerCA::updateStructuralLayer()
{
- Class transformLayerClass = NSClassFromString(@"CATransformLayer");
- if (!transformLayerClass)
- return;
+ ensureStructuralLayer(structuralLayerPurpose());
+}
- if (m_preserves3D && !m_transformLayer) {
- // Create the transform layer.
- m_transformLayer.adoptNS([[transformLayerClass alloc] init]);
+void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose)
+{
+ if (purpose == NoStructuralLayer) {
+ if (m_structuralLayer) {
+ // Replace the transformLayer in the parent with this layer.
+ [m_layer.get() removeFromSuperlayer];
+ [[m_structuralLayer.get() superlayer] replaceSublayer:m_structuralLayer.get() with:m_layer.get()];
- // Turn off default animations.
- [m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_structuralLayer.get(), m_layer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_structuralLayer.get(), m_layer.get());
-#ifndef NDEBUG
- [m_transformLayer.get() setName:[NSString stringWithFormat:@"Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this]];
-#endif
- // Copy the position from this layer.
- updateLayerPosition();
- updateLayerSize();
- updateAnchorPoint();
- updateTransform();
- updateChildrenTransform();
-
- CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
- [m_layer.get() setPosition:point];
+ // Release the structural layer.
+ m_structuralLayer = 0;
- [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)];
- [m_layer.get() setTransform:CATransform3DIdentity];
-
- // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
- [m_layer.get() setOpacity:1];
+ // Update the properties of m_layer now that we no loner have a structural layer.
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
- // Move this layer to be a child of the transform layer.
- [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_transformLayer.get()];
- [m_transformLayer.get() addSublayer:m_layer.get()];
+ updateSublayerList();
+ updateOpacityOnLayer();
+ }
+ return;
+ }
+
+ bool structuralLayerChanged = false;
+
+ if (purpose == StructuralLayerForPreserves3D) {
+ Class transformLayerClass = NSClassFromString(@"CATransformLayer");
+ if (!transformLayerClass)
+ return;
- moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get());
+ if (m_structuralLayer && ![m_structuralLayer.get() isKindOfClass:transformLayerClass])
+ m_structuralLayer = 0;
- updateSublayerList();
- } else if (!m_preserves3D && m_transformLayer) {
- // Relace the transformLayer in the parent with this layer.
- [m_layer.get() removeFromSuperlayer];
- [[m_transformLayer.get() superlayer] replaceSublayer:m_transformLayer.get() with:m_layer.get()];
-
- moveAnimation(AnimatedPropertyWebkitTransform, m_transformLayer.get(), m_layer.get());
-
- // Release the transform layer.
- m_transformLayer = 0;
-
- updateLayerPosition();
- updateLayerSize();
- updateAnchorPoint();
- updateTransform();
- updateChildrenTransform();
+ if (!m_structuralLayer) {
+ m_structuralLayer.adoptNS([[transformLayerClass alloc] init]);
+ structuralLayerChanged = true;
+ }
+ } else {
+ if (m_structuralLayer && ![m_structuralLayer.get() isMemberOfClass:[CALayer self]])
+ m_structuralLayer = 0;
- updateSublayerList();
+ if (!m_structuralLayer) {
+ m_structuralLayer.adoptNS([[CALayer alloc] init]);
+ structuralLayerChanged = true;
+ }
}
+
+ if (!structuralLayerChanged)
+ return;
+
+ // Turn off default animations.
+ [m_structuralLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+
+ updateLayerNames();
+ // Update the properties of the structural layer.
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ // Set properties of m_layer to their default values, since these are expressed on on the structural layer.
+ CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ [m_layer.get() setPosition:point];
+ [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)];
+ [m_layer.get() setTransform:CATransform3DIdentity];
+ [m_layer.get() setOpacity:1];
+
+ // Move this layer to be a child of the transform layer.
+ [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_structuralLayer.get()];
+ [m_structuralLayer.get() addSublayer:m_layer.get()];
+
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_layer.get(), m_structuralLayer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_layer.get(), m_structuralLayer.get());
+
+ updateSublayerList();
updateOpacityOnLayer();
}
+GraphicsLayerCA::StructuralLayerPurpose GraphicsLayerCA::structuralLayerPurpose() const
+{
+ if (preserves3D())
+ return StructuralLayerForPreserves3D;
+
+ if (isReplicated())
+ return StructuralLayerForReplicaFlattening;
+
+ return NoStructuralLayer;
+}
+
void GraphicsLayerCA::updateLayerDrawsContent()
{
bool needTiledLayer = requiresTiledLayer(m_size);
@@ -1087,6 +1348,12 @@ void GraphicsLayerCA::updateContentsImage()
#endif
[m_contentsLayer.get() setContents:(id)m_pendingContentsImage.get()];
m_pendingContentsImage = 0;
+
+ if (m_contentsLayerClones) {
+ LayerMap::const_iterator end = m_contentsLayerClones->end();
+ for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it)
+ [it->second.get() setContents:[m_contentsLayer.get() contents]];
+ }
updateContentsRect();
} else {
@@ -1096,7 +1363,7 @@ void GraphicsLayerCA::updateContentsImage()
}
}
-void GraphicsLayerCA::updateContentsVideo()
+void GraphicsLayerCA::updateContentsMediaLayer()
{
// Video layer was set as m_contentsLayer, and will get parented in updateSublayerList().
if (m_contentsLayer) {
@@ -1131,6 +1398,15 @@ void GraphicsLayerCA::updateContentsRect()
[m_contentsLayer.get() setPosition:point];
[m_contentsLayer.get() setBounds:rect];
+
+ if (m_contentsLayerClones) {
+ LayerMap::const_iterator end = m_contentsLayerClones->end();
+ for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ [currLayer setPosition:point];
+ [currLayer setBounds:rect];
+ }
+ }
}
void GraphicsLayerCA::updateGeometryOrientation()
@@ -1152,8 +1428,74 @@ void GraphicsLayerCA::updateGeometryOrientation()
void GraphicsLayerCA::updateMaskLayer()
{
- CALayer* maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0;
+ CALayer *maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0;
[m_layer.get() setMask:maskCALayer];
+
+ LayerMap* maskLayerCloneMap = m_maskLayer ? static_cast<GraphicsLayerCA*>(m_maskLayer)->primaryLayerClones() : 0;
+
+ if (LayerMap* layerCloneMap = m_layerClones.get()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+
+ CALayer *maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(it->first).get() : 0;
+ [currLayer setMask:maskClone];
+ }
+ }
+}
+
+void GraphicsLayerCA::updateReplicatedLayers()
+{
+ // Clone the descendants of the replicated layer, and parent under us.
+ ReplicaState replicaState(ReplicaState::ReplicaBranch);
+
+ CALayer *replicaRoot = replicatedLayerRoot(replicaState);
+ if (!replicaRoot)
+ return;
+
+ if (m_structuralLayer)
+ [m_structuralLayer.get() insertSublayer:replicaRoot atIndex:0];
+ else
+ [m_layer.get() insertSublayer:replicaRoot atIndex:0];
+}
+
+// For now, this assumes that layers only ever have one replica, so replicaIndices contains only 0 and 1.
+GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const
+{
+ size_t depth = m_replicaBranches.size();
+
+ const size_t bitsPerUChar = sizeof(UChar) * 8;
+ size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar;
+
+ Vector<UChar> result(vectorSize);
+ result.fill(0);
+
+ // Create a string from the bit sequence which we can use to identify the clone.
+ // Note that the string may contain embedded nulls, but that's OK.
+ for (size_t i = 0; i < depth; ++i) {
+ UChar& currChar = result[i / bitsPerUChar];
+ currChar = (currChar << 1) | m_replicaBranches[i];
+ }
+
+ return String::adopt(result);
+}
+
+CALayer *GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState)
+{
+ // Limit replica nesting, to avoid 2^N explosion of replica layers.
+ if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth)
+ return nil;
+
+ GraphicsLayerCA* replicatedLayer = static_cast<GraphicsLayerCA*>(m_replicatedLayer);
+
+ CALayer *clonedLayerRoot = replicatedLayer->fetchCloneLayers(this, replicaState, RootCloneLevel);
+ FloatPoint cloneRootPosition = replicatedLayer->positionForCloneRootLayer();
+
+ // Replica root has no offset or transform
+ [clonedLayerRoot setPosition:cloneRootPosition];
+ [clonedLayerRoot setTransform:CATransform3DIdentity];
+
+ return clonedLayerRoot;
}
void GraphicsLayerCA::updateLayerAnimations()
@@ -1163,10 +1505,8 @@ void GraphicsLayerCA::updateLayerAnimations()
for (HashSet<AnimatedProperty>::const_iterator it = m_transitionPropertiesToRemove.begin(); it != end; ++it) {
AnimatedPropertyID currProperty = static_cast<AnimatedPropertyID>(*it);
// Remove all animations with this property in the key.
- // We can't tell if this property is animating via a transition or animation here, but
- // that's OK because the style system never sends both transitions and animations for the same property.
for (int index = 0; ; ++index) {
- if (!removeAnimationFromLayer(currProperty, index))
+ if (!removeAnimationFromLayer(currProperty, "", index))
break;
}
}
@@ -1182,21 +1522,21 @@ void GraphicsLayerCA::updateLayerAnimations()
if (animationIt == m_runningKeyframeAnimations.end())
continue;
- AnimationProcessingAction action = it->second;
+ const AnimationProcessingAction& processingInfo = it->second;
const Vector<AnimationPair>& animations = animationIt->second;
for (size_t i = 0; i < animations.size(); ++i) {
const AnimationPair& currPair = animations[i];
- switch (action) {
+ switch (processingInfo.action) {
case Remove:
- removeAnimationFromLayer(static_cast<AnimatedPropertyID>(currPair.first), currPair.second);
+ removeAnimationFromLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second);
break;
case Pause:
- pauseAnimationOnLayer(static_cast<AnimatedPropertyID>(currPair.first), currPair.second);
+ pauseAnimationOnLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second, processingInfo.timeOffset);
break;
}
}
- if (action == Remove)
+ if (processingInfo.action == Remove)
m_runningKeyframeAnimations.remove(currKeyframeName);
}
@@ -1207,7 +1547,7 @@ void GraphicsLayerCA::updateLayerAnimations()
if ((numAnimations = m_uncomittedAnimations.size())) {
for (size_t i = 0; i < numAnimations; ++i) {
const LayerAnimation& pendingAnimation = m_uncomittedAnimations[i];
- setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_index, pendingAnimation.m_beginTime);
+ setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_keyframesName, pendingAnimation.m_index, pendingAnimation.m_timeOffset);
if (!pendingAnimation.m_keyframesName.isEmpty()) {
// If this is a keyframe anim, we have to remember the association of keyframes name to property/index pairs,
@@ -1229,19 +1569,28 @@ void GraphicsLayerCA::updateLayerAnimations()
}
}
-void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, int index, double beginTime)
+void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset)
{
PlatformLayer* layer = animatedLayer(property);
- if (beginTime) {
- NSTimeInterval time = [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil];
- [caAnim setBeginTime:time];
- }
+ [caAnim setTimeOffset:timeOffset];
- String animationName = animationIdentifier(property, index);
+ String animationName = animationIdentifier(property, keyframesName, index);
[layer removeAnimationForKey:animationName];
[layer addAnimation:caAnim forKey:animationName];
+
+ if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ // Skip immediate replicas, since they move with the original.
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+ CALayer *currLayer = it->second.get();
+ [currLayer removeAnimationForKey:animationName];
+ [currLayer addAnimation:caAnim forKey:animationName];
+ }
+ }
}
// Workaround for <rdar://problem/7311367>
@@ -1259,18 +1608,29 @@ static void bug7311367Workaround(CALayer* transformLayer, const TransformationMa
[transformLayer setTransform:caTransform];
}
-bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int index)
+bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, const String& keyframesName, int index)
{
PlatformLayer* layer = animatedLayer(property);
- String animationName = animationIdentifier(property, index);
+ String animationName = animationIdentifier(property, keyframesName, index);
if (![layer animationForKey:animationName])
return false;
[layer removeAnimationForKey:animationName];
-
- bug7311367Workaround(m_transformLayer.get(), m_transform);
+ bug7311367Workaround(m_structuralLayer.get(), m_transform);
+
+ if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ // Skip immediate replicas, since they move with the original.
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+
+ CALayer *currLayer = it->second.get();
+ [currLayer removeAnimationForKey:animationName];
+ }
+ }
return true;
}
@@ -1290,11 +1650,11 @@ static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimati
#endif
}
-void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, int index)
+void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset)
{
PlatformLayer* layer = animatedLayer(property);
- String animationName = animationIdentifier(property, index);
+ String animationName = animationIdentifier(property, keyframesName, index);
CAAnimation* caAnim = [layer animationForKey:animationName];
if (!caAnim)
@@ -1319,10 +1679,23 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, int ind
pausedAnim = newAnim;
}
- double t = [layer convertTime:currentTimeToMediaTime(currentTime()) fromLayer:nil];
+ // pausedAnim has the beginTime of caAnim already.
[pausedAnim setSpeed:0];
- [pausedAnim setTimeOffset:t - [caAnim beginTime]];
+ [pausedAnim setTimeOffset:timeOffset];
+
[layer addAnimation:pausedAnim forKey:animationName]; // This will replace the running animation.
+
+ // Pause the animations on the clones too.
+ if (LayerMap* layerCloneMap = animatedLayerClones(property)) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ // Skip immediate replicas, since they move with the original.
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+ CALayer *currLayer = it->second.get();
+ [currLayer addAnimation:pausedAnim forKey:animationName];
+ }
+ }
}
#if ENABLE(3D_CANVAS)
@@ -1337,7 +1710,7 @@ void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* gr
m_platformGraphicsContext3D = context;
m_platformTexture = texture;
- noteLayerPropertyChanged(ChildrenChanged);
+ noteSublayersChanged();
BEGIN_BLOCK_OBJC_EXCEPTIONS
@@ -1346,9 +1719,11 @@ void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* gr
m_contentsLayer.adoptNS([[Canvas3DLayer alloc] initWithContext:static_cast<CGLContextObj>(m_platformGraphicsContext3D) texture:static_cast<GLuint>(m_platformTexture)]);
#ifndef NDEBUG
[m_contentsLayer.get() setName:@"3D Layer"];
-#endif
+#endif
+ [m_contentsLayer.get() setLayerOwner:this];
} else {
// remove the inner layer
+ [m_contentsLayer.get() setLayerOwner:0];
m_contentsLayer = 0;
}
@@ -1370,7 +1745,7 @@ void GraphicsLayerCA::repaintLayerDirtyRects()
m_dirtyRects.clear();
}
-bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double beginTime)
+bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset)
{
ASSERT(valueList.property() != AnimatedPropertyWebkitTransform);
@@ -1396,14 +1771,14 @@ bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valu
if (!valuesOK)
return false;
- m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, beginTime));
+ m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset));
END_BLOCK_OBJC_EXCEPTIONS;
return true;
}
-bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double beginTime, const IntSize& boxSize)
+bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset, const IntSize& boxSize)
{
ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
@@ -1450,7 +1825,7 @@ bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValue
if (!validMatrices)
break;
- m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, beginTime));
+ m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset));
}
END_BLOCK_OBJC_EXCEPTIONS;
@@ -1663,25 +2038,42 @@ void GraphicsLayerCA::suspendAnimations(double time)
double t = currentTimeToMediaTime(time ? time : currentTime());
[primaryLayer() setSpeed:0];
[primaryLayer() setTimeOffset:t];
+
+ // Suspend the animations on the clones too.
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ [currLayer setSpeed:0 ];
+ [currLayer setTimeOffset:t];
+ }
+ }
}
void GraphicsLayerCA::resumeAnimations()
{
[primaryLayer() setSpeed:1];
[primaryLayer() setTimeOffset:0];
+
+ // Resume the animations on the clones too.
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ CALayer *currLayer = it->second.get();
+ [currLayer setSpeed:1];
+ [currLayer setTimeOffset:0];
+ }
+ }
}
-WebLayer* GraphicsLayerCA::hostLayerForSublayers() const
+CALayer* GraphicsLayerCA::hostLayerForSublayers() const
{
- return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+ return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get();
}
-WebLayer* GraphicsLayerCA::layerForSuperlayer() const
+CALayer* GraphicsLayerCA::layerForSuperlayer() const
{
- if (m_transformLayer)
- return m_transformLayer.get();
-
- return m_layer.get();
+ return m_structuralLayer ? m_structuralLayer.get() : m_layer.get();
}
CALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
@@ -1689,6 +2081,11 @@ CALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
}
+GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedPropertyID property) const
+{
+ return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones();
+}
+
PlatformLayer* GraphicsLayerCA::platformLayer() const
{
return primaryLayer();
@@ -1790,9 +2187,9 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
#endif
// move over animations
- moveAnimation(AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
- moveAnimation(AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
- moveAnimation(AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, oldLayer.get(), m_layer.get());
+ moveOrCopyAnimationsForProperty(Move, AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get());
// need to tell new layer to draw itself
setNeedsDisplay();
@@ -1847,9 +2244,232 @@ void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer)
}
}
+CALayer *GraphicsLayerCA::findOrMakeClone(CloneID cloneID, CALayer *sourceLayer, LayerMap* clones, CloneLevel cloneLevel)
+{
+ if (!sourceLayer)
+ return 0;
+
+ CALayer *resultLayer;
+
+ // Add with a dummy value to get an iterator for the insertion position, and a boolean that tells
+ // us whether there's an item there. This technique avoids two hash lookups.
+ RetainPtr<CALayer> dummy;
+ pair<LayerMap::iterator, bool> addResult = clones->add(cloneID, dummy);
+ if (!addResult.second) {
+ // Value was not added, so it exists already.
+ resultLayer = addResult.first->second.get();
+ } else {
+ resultLayer = cloneLayer(sourceLayer, cloneLevel);
+#ifndef NDEBUG
+ [resultLayer setName:[NSString stringWithFormat:@"Clone %d of layer %@", cloneID[0U], sourceLayer]];
+#endif
+ addResult.first->second = resultLayer;
+ }
+
+ return resultLayer;
+}
+
+void GraphicsLayerCA::ensureCloneLayers(CloneID cloneID, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel cloneLevel)
+{
+ structuralLayer = nil;
+ contentsLayer = nil;
+
+ if (!m_layerClones)
+ m_layerClones = new LayerMap;
+
+ if (!m_structuralLayerClones && m_structuralLayer)
+ m_structuralLayerClones = new LayerMap;
+
+ if (!m_contentsLayerClones && m_contentsLayer)
+ m_contentsLayerClones = new LayerMap;
+
+ primaryLayer = findOrMakeClone(cloneID, m_layer.get(), m_layerClones.get(), cloneLevel);
+ structuralLayer = findOrMakeClone(cloneID, m_structuralLayer.get(), m_structuralLayerClones.get(), cloneLevel);
+ contentsLayer = findOrMakeClone(cloneID, m_contentsLayer.get(), m_contentsLayerClones.get(), cloneLevel);
+}
+
+void GraphicsLayerCA::removeCloneLayers()
+{
+ m_layerClones = 0;
+ m_structuralLayerClones = 0;
+ m_contentsLayerClones = 0;
+}
+
+FloatPoint GraphicsLayerCA::positionForCloneRootLayer() const
+{
+ // This can get called during a sync when we've just removed the m_replicaLayer.
+ if (!m_replicaLayer)
+ return FloatPoint();
+
+ FloatPoint replicaPosition = m_replicaLayer->replicatedLayerPosition();
+ return FloatPoint(replicaPosition.x() + m_anchorPoint.x() * m_size.width(),
+ replicaPosition.y() + m_anchorPoint.y() * m_size.height());
+}
+
+void GraphicsLayerCA::propagateLayerChangeToReplicas()
+{
+ for (GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) {
+ GraphicsLayerCA* currLayerCA = static_cast<GraphicsLayerCA*>(currLayer);
+ if (!currLayerCA->hasCloneLayers())
+ break;
+
+ if (currLayerCA->replicaLayer())
+ static_cast<GraphicsLayerCA*>(currLayerCA->replicaLayer())->noteLayerPropertyChanged(ReplicatedLayerChanged);
+ }
+}
+
+CALayer *GraphicsLayerCA::fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState& replicaState, CloneLevel cloneLevel)
+{
+ CALayer *primaryLayer;
+ CALayer *structuralLayer;
+ CALayer *contentsLayer;
+ ensureCloneLayers(replicaState.cloneID(), primaryLayer, structuralLayer, contentsLayer, cloneLevel);
+
+ if (m_maskLayer) {
+ CALayer *maskClone = static_cast<GraphicsLayerCA*>(m_maskLayer)->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
+ [primaryLayer setMask:maskClone];
+ }
+
+ if (m_replicatedLayer) {
+ // We are a replica being asked for clones of our layers.
+ CALayer *replicaRoot = replicatedLayerRoot(replicaState);
+ if (!replicaRoot)
+ return nil;
+
+ if (structuralLayer) {
+ [structuralLayer insertSublayer:replicaRoot atIndex:0];
+ return structuralLayer;
+ }
+
+ [primaryLayer insertSublayer:replicaRoot atIndex:0];
+ return primaryLayer;
+ }
+
+ const Vector<GraphicsLayer*>& childLayers = children();
+ NSMutableArray* clonalSublayers = nil;
+
+ CALayer *replicaLayer = nil;
+ if (m_replicaLayer && m_replicaLayer != replicaRoot) {
+ // We have nested replicas. Ask the replica layer for a clone of its contents.
+ replicaState.setBranchType(ReplicaState::ReplicaBranch);
+ replicaLayer = static_cast<GraphicsLayerCA*>(m_replicaLayer)->fetchCloneLayers(replicaRoot, replicaState, RootCloneLevel);
+ replicaState.setBranchType(ReplicaState::ChildBranch);
+ }
+
+ if (replicaLayer || structuralLayer || contentsLayer || childLayers.size() > 0) {
+ clonalSublayers = [[NSMutableArray alloc] init];
+
+ if (structuralLayer) {
+ // Replicas render behind the actual layer content.
+ if (replicaLayer)
+ [clonalSublayers addObject:replicaLayer];
+
+ // Add the primary layer next. Even if we have negative z-order children, the primary layer always comes behind.
+ [clonalSublayers addObject:primaryLayer];
+ } else if (contentsLayer) {
+ // FIXME: add the contents layer in the correct order with negative z-order children.
+ // This does not cause visible rendering issues because currently contents layers are only used
+ // for replaced elements that don't have children.
+ [clonalSublayers addObject:contentsLayer];
+ }
+
+ replicaState.push(ReplicaState::ChildBranch);
+
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+
+ CALayer *childLayer = curChild->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel);
+ if (childLayer)
+ [clonalSublayers addObject:childLayer];
+ }
+
+ replicaState.pop();
+
+ [clonalSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
+ }
+
+ CALayer *result;
+ if (structuralLayer) {
+ [structuralLayer setSublayers:clonalSublayers];
+
+ if (contentsLayer) {
+ // If we have a transform layer, then the contents layer is parented in the
+ // primary layer (which is itself a child of the transform layer).
+ [primaryLayer setSublayers:nil];
+ [primaryLayer addSublayer:contentsLayer];
+ }
+
+ result = structuralLayer;
+ } else {
+ [primaryLayer setSublayers:clonalSublayers];
+ result = primaryLayer;
+ }
+
+ [clonalSublayers release];
+ return result;
+}
+
+CALayer *GraphicsLayerCA::cloneLayer(CALayer *layer, CloneLevel cloneLevel)
+{
+ static Class transformLayerClass = NSClassFromString(@"CATransformLayer");
+ CALayer *newLayer = nil;
+ if ([layer isKindOfClass:transformLayerClass])
+ newLayer = [transformLayerClass layer];
+ else
+ newLayer = [CALayer layer];
+
+ [newLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+
+ [newLayer setPosition:[layer position]];
+ [newLayer setBounds:[layer bounds]];
+ [newLayer setAnchorPoint:[layer anchorPoint]];
+#if HAVE_MODERN_QUARTZCORE
+ [newLayer setAnchorPointZ:[layer anchorPointZ]];
+#endif
+ [newLayer setTransform:[layer transform]];
+ [newLayer setSublayerTransform:[layer sublayerTransform]];
+ [newLayer setContents:[layer contents]];
+ [newLayer setMasksToBounds:[layer masksToBounds]];
+ [newLayer setDoubleSided:[layer isDoubleSided]];
+ [newLayer setOpaque:[layer isOpaque]];
+ [newLayer setBackgroundColor:[layer backgroundColor]];
+
+ if (cloneLevel == IntermediateCloneLevel) {
+ [newLayer setOpacity:[layer opacity]];
+ moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyWebkitTransform, layer, newLayer);
+ moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyOpacity, layer, newLayer);
+ }
+
+ if (showDebugBorders()) {
+ setLayerBorderColor(newLayer, Color(255, 122, 251));
+ [newLayer setBorderWidth:2];
+ }
+
+ return newLayer;
+}
+
void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity)
{
- [(preserves3D() ? m_layer.get() : primaryLayer()) setOpacity:accumulatedOpacity];
+ LayerMap* layerCloneMap = 0;
+
+ if (preserves3D()) {
+ [m_layer.get() setOpacity:accumulatedOpacity];
+ layerCloneMap = m_layerClones.get();
+ } else {
+ [primaryLayer() setOpacity:accumulatedOpacity];
+ layerCloneMap = primaryLayerClones();
+ }
+
+ if (layerCloneMap) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+ CALayer *currLayer = it->second.get();
+ [currLayer setOpacity:m_opacity];
+ }
+ }
}
void GraphicsLayerCA::updateOpacityOnLayer()
@@ -1860,9 +2480,27 @@ void GraphicsLayerCA::updateOpacityOnLayer()
distributeOpacity(parent() ? parent()->accumulatedOpacity() : 1);
#else
[primaryLayer() setOpacity:m_opacity];
+
+ if (LayerMap* layerCloneMap = primaryLayerClones()) {
+ LayerMap::const_iterator end = layerCloneMap->end();
+ for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) {
+ if (m_replicaLayer && isReplicatedRootClone(it->first))
+ continue;
+
+ CALayer *currLayer = it->second.get();
+ [currLayer setOpacity:m_opacity];
+ }
+
+ }
#endif
}
+void GraphicsLayerCA::noteSublayersChanged()
+{
+ noteLayerPropertyChanged(ChildrenChanged);
+ propagateLayerChangeToReplicas();
+}
+
void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
{
if (!m_uncommittedChanges && m_client)
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index 7aaf95d..e9f64be 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * 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
@@ -104,22 +104,19 @@ private:
bool hasClosedCaptions() const;
void setClosedCaptionsVisible(bool);
- void setEndTime(float time);
-
- int dataRate() const;
-
MediaPlayer::NetworkState networkState() const { return m_networkState; }
MediaPlayer::ReadyState readyState() const { return m_readyState; }
PassRefPtr<TimeRanges> buffered() const;
float maxTimeSeekable() const;
unsigned bytesLoaded() const;
- bool totalBytesKnown() const;
unsigned totalBytes() const;
void setVisible(bool);
void setSize(const IntSize&);
+ virtual bool hasAvailableVideoFrame() const;
+
void paint(GraphicsContext*, const IntRect&);
void paintCurrentFrameInContext(GraphicsContext*, const IntRect&);
@@ -176,18 +173,19 @@ private:
Timer<MediaPlayerPrivate> m_seekTimer;
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
- bool m_startedPlaying;
- bool m_isStreaming;
- bool m_visible;
IntRect m_rect;
FloatSize m_scaleFactor;
unsigned m_enabledTrackCount;
unsigned m_totalTrackCount;
- bool m_hasUnsupportedTracks;
float m_reportedDuration;
float m_cachedDuration;
float m_timeToRestore;
RetainPtr<QTMovieLayer> m_qtVideoLayer;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+ bool m_visible;
+ bool m_hasUnsupportedTracks;
+ bool m_videoFrameHasDrawn;
#if DRAW_FRAME_RATE
int m_frameCountWhilePlaying;
double m_timeStartedPlaying;
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index dfb5958..dd87bb5 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * 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
@@ -204,17 +204,18 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
, m_networkState(MediaPlayer::Empty)
, m_readyState(MediaPlayer::HaveNothing)
- , m_startedPlaying(false)
- , m_isStreaming(false)
- , m_visible(false)
, m_rect()
, m_scaleFactor(1, 1)
, m_enabledTrackCount(0)
, m_totalTrackCount(0)
+ , m_reportedDuration(-1)
+ , m_cachedDuration(-1)
+ , m_timeToRestore(-1)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+ , m_visible(false)
, m_hasUnsupportedTracks(false)
- , m_reportedDuration(-1.0f)
- , m_cachedDuration(-1.0f)
- , m_timeToRestore(-1.0f)
+ , m_videoFrameHasDrawn(false)
#if DRAW_FRAME_RATE
, m_frameCountWhilePlaying(0)
, m_timeStartedPlaying(0)
@@ -449,7 +450,7 @@ void MediaPlayerPrivate::createQTMovieLayer()
// later via acceleratedRenderingStateChanged().
GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
if (videoGraphicsLayer)
- videoGraphicsLayer->setContentsToVideo((PlatformLayer *)m_qtVideoLayer.get());
+ videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer.get());
}
#endif
}
@@ -498,6 +499,9 @@ MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::preferredRenderingMod
void MediaPlayerPrivate::setUpVideoRendering()
{
+ if (!isReadyForRendering())
+ return;
+
MediaRenderingMode currentMode = currentRenderingMode();
MediaRenderingMode preferredMode = preferredRenderingMode();
if (currentMode == preferredMode && currentMode != MediaRenderingNone)
@@ -556,6 +560,7 @@ void MediaPlayerPrivate::load(const String& url)
m_player->readyStateChanged();
}
cancelSeek();
+ m_videoFrameHasDrawn = false;
[m_objcObserver.get() setDelayCallbacks:YES];
@@ -651,7 +656,7 @@ void MediaPlayerPrivate::doSeek()
[m_qtMovie.get() setRate:0];
[m_qtMovie.get() setCurrentTime:qttime];
- // restore playback only if not at end, othewise QTMovie will loop
+ // restore playback only if not at end, otherwise QTMovie will loop
float timeAfterSeek = currentTime();
if (oldRate && timeAfterSeek < duration())
[m_qtMovie.get() setRate:oldRate];
@@ -687,10 +692,6 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
}
}
-void MediaPlayerPrivate::setEndTime(float)
-{
-}
-
bool MediaPlayerPrivate::paused() const
{
if (!metaDataAvailable())
@@ -765,7 +766,7 @@ void MediaPlayerPrivate::setClosedCaptionsVisible(bool closedCaptionsVisible)
#if USE(ACCELERATED_COMPOSITING) && (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
if (closedCaptionsVisible && m_qtVideoLayer) {
- // Captions will be rendered upsided down unless we flag the movie as flipped (again). See <rdar://7408440>.
+ // Captions will be rendered upside down unless we flag the movie as flipped (again). See <rdar://7408440>.
[m_qtVideoLayer.get() setGeometryFlipped:YES];
}
#endif
@@ -796,13 +797,6 @@ void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch)
createQTMovie([movieAttributes valueForKey:QTMovieURLAttribute], movieAttributes);
}
-int MediaPlayerPrivate::dataRate() const
-{
- if (!metaDataAvailable())
- return 0;
- return wkQTMovieDataRate(m_qtMovie.get());
-}
-
PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
{
RefPtr<TimeRanges> timeRanges = TimeRanges::create();
@@ -839,11 +833,6 @@ unsigned MediaPlayerPrivate::bytesLoaded() const
return totalBytes() * maxTimeLoaded() / dur;
}
-bool MediaPlayerPrivate::totalBytesKnown() const
-{
- return totalBytes() > 0;
-}
-
unsigned MediaPlayerPrivate::totalBytes() const
{
if (!metaDataAvailable())
@@ -981,7 +970,7 @@ void MediaPlayerPrivate::updateStates()
}
}
- if (isReadyForRendering() && !hasSetUpVideoRendering())
+ if (!hasSetUpVideoRendering())
setUpVideoRendering();
if (seeking())
@@ -1056,8 +1045,11 @@ void MediaPlayerPrivate::didEnd()
// Hang onto the current time and use it as duration from now on since QuickTime is telling us we
// are at the end. Do this because QuickTime sometimes reports one time for duration and stops
- // playback at another time, which causes problems in HTMLMediaElement.
- m_cachedDuration = currentTime();
+ // playback at another time, which causes problems in HTMLMediaElement. QTKit's 'ended' event
+ // fires when playing in reverse so don't update duration when at time zero!
+ float now = currentTime();
+ if (now > 0)
+ m_cachedDuration = now;
updateStates();
m_player->timeChanged();
@@ -1078,14 +1070,27 @@ void MediaPlayerPrivate::setVisible(bool b)
{
if (m_visible != b) {
m_visible = b;
- if (b) {
- if (m_readyState >= MediaPlayer::HaveMetadata)
- setUpVideoRendering();
- } else
+ if (b)
+ setUpVideoRendering();
+ else
tearDownVideoRendering();
}
}
+bool MediaPlayerPrivate::hasAvailableVideoFrame() const
+{
+ // When using a QTMovieLayer return true as soon as the movie reaches QTMovieLoadStatePlayable
+ // because although we don't *know* when the first frame has decoded, by the time we get and
+ // process the notification a frame should have propagated the VisualContext and been set on
+ // the layer.
+ if (currentRenderingMode() == MediaRenderingMovieLayer)
+ return m_readyState >= MediaPlayer::HaveCurrentData;
+
+ // When using the software renderer QuickTime signals that a frame is available so we might as well
+ // wait until we know that a frame has been drawn.
+ return m_videoFrameHasDrawn;
+}
+
void MediaPlayerPrivate::repaint()
{
if (m_hasUnsupportedTracks)
@@ -1100,6 +1105,7 @@ void MediaPlayerPrivate::repaint()
m_timeStartedPlaying = [NSDate timeIntervalSinceReferenceDate];
}
#endif
+ m_videoFrameHasDrawn = true;
m_player->repaint();
}
@@ -1404,7 +1410,7 @@ void MediaPlayerPrivate::acceleratedRenderingStateChanged()
if (currentRenderingMode() == MediaRenderingMovieLayer) {
GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
if (videoGraphicsLayer)
- videoGraphicsLayer->setContentsToVideo((PlatformLayer *)m_qtVideoLayer.get());
+ videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer.get());
}
}
#endif
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
index 97a7251..ef7c58f 100644
--- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -55,8 +55,7 @@ using namespace std;
namespace WebCore {
const float smallCapsFontSizeMultiplier = 0.7f;
-const float contextDPI = 72.0f;
-static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (contextDPI / (contextDPI * unitsPerEm)); }
+static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x / unitsPerEm; }
static bool initFontData(SimpleFontData* fontData)
{
@@ -149,7 +148,6 @@ void SimpleFontData::platformInit()
m_styleGroup = 0;
#endif
#if USE(ATSUI)
- m_ATSUStyleInitialized = false;
m_ATSUMirrors = false;
m_checkedShapesArabic = false;
m_shapesArabic = false;
@@ -318,8 +316,9 @@ void SimpleFontData::platformDestroy()
wkReleaseStyleGroup(m_styleGroup);
#endif
#if USE(ATSUI)
- if (m_ATSUStyleInitialized)
- ATSUDisposeStyle(m_ATSUStyle);
+ HashMap<unsigned, ATSUStyle>::iterator end = m_ATSUStyleMap.end();
+ for (HashMap<unsigned, ATSUStyle>::iterator it = m_ATSUStyleMap.begin(); it != end; ++it)
+ ATSUDisposeStyle(it->second);
#endif
}
@@ -445,13 +444,15 @@ CTFontRef SimpleFontData::getCTFont() const
return m_CTFont.get();
}
-CFDictionaryRef SimpleFontData::getCFStringAttributes(TextRenderingMode textMode) const
+CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typesettingFeatures) const
{
- if (m_CFStringAttributes)
- return m_CFStringAttributes.get();
+ unsigned key = typesettingFeatures + 1;
+ pair<HashMap<unsigned, RetainPtr<CFDictionaryRef> >::iterator, bool> addResult = m_CFStringAttributes.add(key, RetainPtr<CFDictionaryRef>());
+ RetainPtr<CFDictionaryRef>& attributesDictionary = addResult.first->second;
+ if (!addResult.second)
+ return attributesDictionary.get();
- bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision;
- bool allowLigatures = platformData().allowsLigatures() || allowKerning;
+ bool allowLigatures = platformData().allowsLigatures() || (typesettingFeatures & Ligatures);
static const int ligaturesNotAllowedValue = 0;
static CFNumberRef ligaturesNotAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesNotAllowedValue);
@@ -459,25 +460,25 @@ CFDictionaryRef SimpleFontData::getCFStringAttributes(TextRenderingMode textMode
static const int ligaturesAllowedValue = 1;
static CFNumberRef ligaturesAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesAllowedValue);
- if (!allowKerning) {
+ if (!(typesettingFeatures & Kerning)) {
static const float kerningAdjustmentValue = 0;
static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue);
static const void* keysWithKerningDisabled[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName };
const void* valuesWithKerningDisabled[] = { getCTFont(), kerningAdjustment, allowLigatures
? ligaturesAllowed : ligaturesNotAllowed };
- m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, keysWithKerningDisabled, valuesWithKerningDisabled,
+ attributesDictionary.adoptCF(CFDictionaryCreate(NULL, keysWithKerningDisabled, valuesWithKerningDisabled,
sizeof(keysWithKerningDisabled) / sizeof(*keysWithKerningDisabled),
&kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
} else {
// By omitting the kCTKernAttributeName attribute, we get Core Text's standard kerning.
static const void* keysWithKerningEnabled[] = { kCTFontAttributeName, kCTLigatureAttributeName };
const void* valuesWithKerningEnabled[] = { getCTFont(), allowLigatures ? ligaturesAllowed : ligaturesNotAllowed };
- m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, keysWithKerningEnabled, valuesWithKerningEnabled,
+ attributesDictionary.adoptCF(CFDictionaryCreate(NULL, keysWithKerningEnabled, valuesWithKerningEnabled,
sizeof(keysWithKerningEnabled) / sizeof(*keysWithKerningEnabled),
&kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
}
- return m_CFStringAttributes.get();
+ return attributesDictionary.get();
}
#endif
diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm
index 56b28e6..641d421 100644
--- a/WebCore/platform/graphics/mac/WebLayer.mm
+++ b/WebCore/platform/graphics/mac/WebLayer.mm
@@ -153,6 +153,13 @@ using namespace WebCore;
}
}
+- (void)display
+{
+ [super display];
+ if (m_layerOwner)
+ m_layerOwner->didDisplay(self);
+}
+
- (void)drawInContext:(CGContextRef)context
{
[WebLayer drawContents:m_layerOwner ofLayer:self intoContext:context];
diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.mm b/WebCore/platform/graphics/mac/WebTiledLayer.mm
index a1f5693..97ba233 100644
--- a/WebCore/platform/graphics/mac/WebTiledLayer.mm
+++ b/WebCore/platform/graphics/mac/WebTiledLayer.mm
@@ -92,6 +92,13 @@ using namespace WebCore;
}
}
+- (void)display
+{
+ [super display];
+ if (m_layerOwner)
+ m_layerOwner->didDisplay(self);
+}
+
- (void)drawInContext:(CGContextRef)ctx
{
[WebLayer drawContents:m_layerOwner ofLayer:self intoContext:ctx];
diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
index 3a60160..12ae09d 100644
--- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
+++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
@@ -401,7 +401,7 @@ static size_t renameFontInternal(SharedBuffer* fontData, const String& fontName,
return nameTableSize;
}
-#if PLATFORM(WINCE)
+#if OS(WINCE)
// AddFontMemResourceEx does not exist on WinCE, so we must handle the font data manually
// This function just renames the font and overwrites the old font data with the new
bool renameFont(SharedBuffer* fontData, const String& fontName)
diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
index 4c75314..0ef1b2b 100644
--- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
+++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
@@ -36,7 +36,7 @@ struct BigEndianUShort;
struct EOTPrefix;
class SharedBuffer;
-#if PLATFORM(WINCE)
+#if OS(WINCE)
typedef unsigned __int8 UInt8;
#endif
diff --git a/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp b/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp
new file mode 100644
index 0000000..3c7eaf2
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp
@@ -0,0 +1,431 @@
+/*
+ * 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 "EGLDisplayOpenVG.h"
+
+#include "EGLUtils.h"
+#include "IntSize.h"
+#include "SurfaceOpenVG.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+// Need to typedef this, otherwise DEFINE_STATIC_LOCAL() doesn't swallow it.
+typedef HashMap<EGLDisplay, EGLDisplayOpenVG*> EGLDisplayManagerMap;
+
+// File-static variables.
+static EGLDisplayManagerMap& displayManagers()
+{
+ DEFINE_STATIC_LOCAL(EGLDisplayManagerMap, managers, ());
+ return managers;
+}
+
+static EGLDisplayOpenVG* s_current = 0;
+
+// Static class members.
+
+SurfaceOpenVG* EGLDisplayOpenVG::currentSurface()
+{
+ EGLDisplayManagerMap& managers = displayManagers();
+ EGLDisplay currentDisplay = eglGetCurrentDisplay();
+
+ if (currentDisplay == EGL_NO_DISPLAY || !managers.contains(currentDisplay))
+ return 0;
+
+ EGLDisplayOpenVG* displayManager = managers.get(currentDisplay);
+ EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
+
+ if (currentSurface == EGL_NO_SURFACE || !displayManager->m_platformSurfaces.contains(currentSurface))
+ return 0;
+
+ return displayManager->m_platformSurfaces.get(currentSurface);
+}
+
+void EGLDisplayOpenVG::registerPlatformSurface(SurfaceOpenVG* platformSurface)
+{
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
+ displayManager->m_platformSurfaces.set(platformSurface->eglSurface(), platformSurface);
+}
+
+void EGLDisplayOpenVG::unregisterPlatformSurface(SurfaceOpenVG* platformSurface)
+{
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
+ displayManager->m_platformSurfaces.remove(platformSurface->eglSurface());
+}
+
+void EGLDisplayOpenVG::setCurrentDisplay(const EGLDisplay& display)
+{
+ s_current = EGLDisplayOpenVG::forDisplay(display);
+}
+
+EGLDisplayOpenVG* EGLDisplayOpenVG::current()
+{
+ if (!s_current) {
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(display, 0, 0);
+ ASSERT_EGL_NO_ERROR();
+
+ s_current = EGLDisplayOpenVG::forDisplay(display);
+ }
+ return s_current;
+}
+
+EGLDisplayOpenVG* EGLDisplayOpenVG::forDisplay(const EGLDisplay& display)
+{
+ EGLDisplayManagerMap& managers = displayManagers();
+
+ if (!managers.contains(display))
+ managers.set(display, new EGLDisplayOpenVG(display));
+
+ return managers.get(display);
+}
+
+
+// Object/instance members.
+
+EGLDisplayOpenVG::EGLDisplayOpenVG(const EGLDisplay& display)
+ : m_display(display)
+ , m_sharedPlatformSurface(0)
+ , m_pbufferConfigId(0)
+ , m_windowConfigId(0)
+{
+ eglBindAPI(EGL_OPENVG_API);
+ ASSERT_EGL_NO_ERROR();
+}
+
+EGLDisplayOpenVG::~EGLDisplayOpenVG()
+{
+ eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ ASSERT_EGL_NO_ERROR();
+
+ delete m_sharedPlatformSurface;
+
+ HashMap<EGLSurface, EGLint>::const_iterator end = m_surfaceConfigIds.end();
+ for (HashMap<EGLSurface, EGLint>::const_iterator it = m_surfaceConfigIds.begin(); it != end; ++it)
+ destroySurface((*it).first);
+
+ eglTerminate(m_display);
+ ASSERT_EGL_NO_ERROR();
+}
+
+void EGLDisplayOpenVG::setDefaultPbufferConfig(const EGLConfig& config)
+{
+ EGLint configId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(configId != EGL_BAD_ATTRIBUTE);
+
+ m_pbufferConfigId = configId;
+}
+
+EGLConfig EGLDisplayOpenVG::defaultPbufferConfig()
+{
+ EGLConfig config;
+ EGLint numConfigs;
+
+ // Hopefully the client will have set the pbuffer config of its choice
+ // by now - if not, use a 32-bit generic one as default.
+ if (!m_pbufferConfigId) {
+ static const EGLint configAttribs[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_ALPHA_MASK_SIZE, 1,
+ EGL_LUMINANCE_SIZE, EGL_DONT_CARE,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_NONE
+ };
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ } else {
+ const EGLint configAttribs[] = {
+ EGL_CONFIG_ID, m_pbufferConfigId,
+ EGL_NONE
+ };
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ }
+
+ ASSERT_EGL_NO_ERROR();
+ ASSERT(numConfigs == 1);
+ return config;
+}
+
+void EGLDisplayOpenVG::setDefaultWindowConfig(const EGLConfig& config)
+{
+ EGLint configId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(configId != EGL_BAD_ATTRIBUTE);
+
+ m_windowConfigId = configId;
+}
+
+EGLConfig EGLDisplayOpenVG::defaultWindowConfig()
+{
+ EGLConfig config;
+ EGLint numConfigs;
+
+ // Hopefully the client will have set the window config of its choice
+ // by now - if not, use a 32-bit generic one as default.
+ if (!m_windowConfigId) {
+ static const EGLint configAttribs[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_ALPHA_MASK_SIZE, 1,
+ EGL_LUMINANCE_SIZE, EGL_DONT_CARE,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_NONE
+ };
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ } else {
+ const EGLint configAttribs[] = {
+ EGL_CONFIG_ID, m_windowConfigId,
+ EGL_NONE
+ };
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ }
+
+ ASSERT_EGL_NO_ERROR();
+ ASSERT(numConfigs == 1);
+ return config;
+}
+
+SurfaceOpenVG* EGLDisplayOpenVG::sharedPlatformSurface()
+{
+ if (!m_sharedPlatformSurface) {
+ // The shared surface doesn't need to be drawn on, it just exists so
+ // that we can always make the shared context current (which in turn is
+ // the owner of long-living resources such as images, paths and fonts).
+ // We'll just make the shared surface as small as possible: 1x1 pixel.
+ EGLConfig config = defaultPbufferConfig();
+ EGLSurface surface = createPbufferSurface(IntSize(1, 1), config);
+
+ EGLContext context = eglCreateContext(m_display, config, EGL_NO_CONTEXT, 0);
+ ASSERT_EGL_NO_ERROR();
+ m_contexts.set(m_surfaceConfigIds.get(surface), context);
+
+ m_sharedPlatformSurface = new SurfaceOpenVG;
+ m_sharedPlatformSurface->m_eglDisplay = m_display;
+ m_sharedPlatformSurface->m_eglSurface = surface;
+ m_sharedPlatformSurface->m_eglContext = context;
+ m_platformSurfaces.set(surface, m_sharedPlatformSurface); // a.k.a. registerPlatformSurface()
+ }
+ return m_sharedPlatformSurface;
+}
+
+EGLSurface EGLDisplayOpenVG::createPbufferSurface(const IntSize& size, const EGLConfig& config, EGLint* errorCode)
+{
+ const EGLint attribList[] = {
+ EGL_WIDTH, size.width(),
+ EGL_HEIGHT, size.height(),
+ EGL_NONE
+ };
+ EGLSurface surface = eglCreatePbufferSurface(m_display, config, attribList);
+
+ if (errorCode)
+ *errorCode = eglGetError();
+ else
+ ASSERT_EGL_NO_ERROR();
+
+ if (surface == EGL_NO_SURFACE)
+ return EGL_NO_SURFACE;
+
+ EGLint surfaceConfigId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
+
+ ASSERT(!m_surfaceConfigIds.contains(surface));
+ m_surfaceConfigIds.set(surface, surfaceConfigId);
+ return surface;
+}
+
+EGLSurface EGLDisplayOpenVG::surfaceForWindow(EGLNativeWindowType wId, const EGLConfig& config)
+{
+ if (m_windowSurfaces.contains(wId))
+ return m_windowSurfaces.get(wId);
+
+ EGLSurface surface = eglCreateWindowSurface(m_display, config, wId, 0);
+ ASSERT_EGL_NO_ERROR();
+
+ EGLint surfaceConfigId;
+ EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
+
+ ASSERT(!m_surfaceConfigIds.contains(surface));
+ m_surfaceConfigIds.set(surface, surfaceConfigId);
+ return surface;
+}
+
+bool EGLDisplayOpenVG::surfacesCompatible(const EGLSurface& surface, const EGLSurface& otherSurface)
+{
+ if (surface == EGL_NO_SURFACE || otherSurface == EGL_NO_SURFACE)
+ return false;
+
+ // Currently, we assume that all surfaces known to this object are
+ // context-compatible to each other (which is reasonable to assume,
+ // otherwise eglCreateContext() would fail with EGL_BAD_MATCH for shared
+ // context compatibility anyways.
+ return m_surfaceConfigIds.contains(surface) && m_surfaceConfigIds.contains(otherSurface);
+}
+
+void EGLDisplayOpenVG::destroySurface(const EGLSurface& surface)
+{
+ ASSERT(surface != EGL_NO_SURFACE);
+
+ if (eglGetCurrentSurface(EGL_DRAW) == surface) {
+ eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ ASSERT_EGL_NO_ERROR();
+ }
+
+ // Destroy the context associated to the surface, if we already created one.
+ if (m_surfaceConfigIds.contains(surface)) {
+ EGLint surfaceConfigId = m_surfaceConfigIds.take(surface); // take = get and remove
+ bool isContextReferenced = false;
+
+ if (m_compatibleConfigIds.contains(surfaceConfigId))
+ surfaceConfigId = m_compatibleConfigIds.get(surfaceConfigId);
+
+ HashMap<EGLSurface, EGLint>::iterator end = m_surfaceConfigIds.end();
+
+ // ...but only if there's no other surfaces associated to that context.
+ for (HashMap<EGLSurface, EGLint>::iterator it = m_surfaceConfigIds.begin(); it != end; ++it) {
+ if ((*it).second == surfaceConfigId) {
+ isContextReferenced = true;
+ break;
+ }
+ }
+ if (!isContextReferenced && m_contexts.contains(surfaceConfigId)) {
+ EGLContext context = m_contexts.take(surfaceConfigId);
+ eglDestroyContext(m_display, context);
+ ASSERT_EGL_NO_ERROR();
+ }
+ }
+
+ m_platformSurfaces.remove(surface);
+
+ HashMap<EGLNativeWindowType, EGLSurface>::iterator end = m_windowSurfaces.end();
+ for (HashMap<EGLNativeWindowType, EGLSurface>::iterator it = m_windowSurfaces.begin(); it != end; ++it) {
+ if ((*it).second == surface) {
+ m_windowSurfaces.remove(it);
+ break;
+ }
+ }
+
+ eglDestroySurface(m_display, surface);
+ ASSERT_EGL_NO_ERROR();
+}
+
+EGLContext EGLDisplayOpenVG::contextForSurface(const EGLSurface& surface)
+{
+ ASSERT(surface != EGL_NO_SURFACE);
+
+ if (m_platformSurfaces.contains(surface))
+ return m_platformSurfaces.get(surface)->eglContext();
+
+ eglBindAPI(EGL_OPENVG_API);
+ ASSERT_EGL_NO_ERROR();
+
+ EGLint surfaceConfigId;
+
+ if (m_surfaceConfigIds.contains(surface))
+ surfaceConfigId = m_surfaceConfigIds.get(surface);
+ else {
+ // Retrieve the same EGL config for context creation that was used to
+ // create the the EGL surface.
+ EGLBoolean success = eglQuerySurface(m_display, surface, EGL_CONFIG_ID, &surfaceConfigId);
+ ASSERT(success == EGL_TRUE);
+ ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
+
+ m_surfaceConfigIds.set(surface, surfaceConfigId);
+ }
+
+ if (m_compatibleConfigIds.contains(surfaceConfigId))
+ surfaceConfigId = m_compatibleConfigIds.get(surfaceConfigId);
+
+ if (m_contexts.contains(surfaceConfigId))
+ return m_contexts.get(surfaceConfigId);
+
+ if (!m_sharedPlatformSurface) // shared context has not been created yet
+ sharedPlatformSurface(); // creates the shared surface & context
+
+ EGLDisplay currentDisplay = eglGetCurrentDisplay();
+ EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ);
+ EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
+ EGLContext currentContext = eglGetCurrentContext();
+
+ // Before creating a new context, let's try whether an existing one
+ // is compatible with the surface. EGL doesn't give us a different way
+ // to check context/surface compatibility than trying it out, so let's
+ // do just that.
+ HashMap<EGLint, EGLContext>::iterator end = m_contexts.end();
+
+ for (HashMap<EGLint, EGLContext>::iterator it = m_contexts.begin(); it != end; ++it) {
+ eglMakeCurrent(m_display, surface, surface, (*it).second);
+ if (eglGetError() == EGL_SUCCESS) {
+ // Restore previous surface/context.
+ if (currentContext != EGL_NO_CONTEXT) {
+ eglMakeCurrent(currentDisplay, currentReadSurface, currentDrawSurface, currentContext);
+ ASSERT_EGL_NO_ERROR();
+ }
+ // Cool, surface is compatible to one of our existing contexts.
+ m_compatibleConfigIds.set(surfaceConfigId, (*it).first);
+ return (*it).second;
+ }
+ }
+ // Restore previous surface/context.
+ if (currentContext != EGL_NO_CONTEXT) {
+ eglMakeCurrent(currentDisplay, currentReadSurface, currentDrawSurface, currentContext);
+ ASSERT_EGL_NO_ERROR();
+ }
+
+ EGLConfig config;
+ EGLint numConfigs;
+
+ const EGLint configAttribs[] = {
+ EGL_CONFIG_ID, surfaceConfigId,
+ EGL_NONE
+ };
+
+ eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
+ ASSERT_EGL_NO_ERROR();
+ ASSERT(numConfigs == 1);
+
+ // We share all of the images and paths amongst the different contexts,
+ // so that they can be used in all of them. Resources that are created
+ // while m_sharedPlatformSurface->context() is current will be
+ // accessible from all other contexts, but are not restricted to the
+ // lifetime of those contexts.
+ EGLContext context = eglCreateContext(m_display, config, m_sharedPlatformSurface->eglContext(), 0);
+ ASSERT_EGL_NO_ERROR();
+
+ ASSERT(!m_contexts.contains(surfaceConfigId));
+ m_contexts.set(surfaceConfigId, context);
+ return context;
+}
+
+}
diff --git a/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h b/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h
new file mode 100644
index 0000000..fd8353d
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h
@@ -0,0 +1,89 @@
+/*
+ * 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 EGLDisplayOpenVG_h
+#define EGLDisplayOpenVG_h
+
+#include <egl.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class IntSize;
+class SurfaceOpenVG;
+
+class EGLDisplayOpenVG {
+public:
+ friend class SurfaceOpenVG;
+
+ static SurfaceOpenVG* currentSurface();
+ static void setCurrentDisplay(const EGLDisplay&);
+ static EGLDisplayOpenVG* current();
+ static EGLDisplayOpenVG* forDisplay(const EGLDisplay&);
+
+ void setDefaultPbufferConfig(const EGLConfig&);
+ EGLConfig defaultPbufferConfig();
+ void setDefaultWindowConfig(const EGLConfig&);
+ EGLConfig defaultWindowConfig();
+
+ EGLDisplay display() const { return m_display; }
+ SurfaceOpenVG* sharedPlatformSurface();
+
+ /** Creates a pbuffer surface using the given config. If no surface
+ * could be created, EGL_NO_SURFACE is returned and errors can be
+ * checked with the value that is written to the errorCode parameter
+ * If no surface could be created and errorCode is zero, this method
+ * will trigger an assertion by itself. */
+ EGLSurface createPbufferSurface(const IntSize&, const EGLConfig&, EGLint* errorCode = 0);
+
+ EGLSurface surfaceForWindow(EGLNativeWindowType, const EGLConfig&);
+
+ bool surfacesCompatible(const EGLSurface&, const EGLSurface&);
+
+ /** Destroy the surface and its corresponding context (unless another
+ * surface is still using the same context, in which case the context
+ * is not destroyed). */
+ void destroySurface(const EGLSurface&);
+
+ /** Return the context corresponding to the surface.
+ * If no corresponding context exists, one is created automatically. */
+ EGLContext contextForSurface(const EGLSurface&);
+
+private:
+ static void registerPlatformSurface(SurfaceOpenVG*);
+ static void unregisterPlatformSurface(SurfaceOpenVG*);
+
+ EGLDisplayOpenVG(const EGLDisplay& display);
+ ~EGLDisplayOpenVG();
+
+ EGLDisplay m_display;
+ SurfaceOpenVG* m_sharedPlatformSurface;
+ EGLint m_pbufferConfigId;
+ EGLint m_windowConfigId;
+
+ HashMap<EGLSurface, SurfaceOpenVG*> m_platformSurfaces;
+ HashMap<EGLNativeWindowType, EGLSurface> m_windowSurfaces;
+ HashMap<EGLSurface, EGLint> m_surfaceConfigIds;
+ HashMap<EGLint, EGLint> m_compatibleConfigIds;
+ HashMap<EGLint, EGLContext> m_contexts;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/openvg/EGLUtils.h b/WebCore/platform/graphics/openvg/EGLUtils.h
new file mode 100644
index 0000000..6f5d793
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/EGLUtils.h
@@ -0,0 +1,71 @@
+/*
+ * 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 EGLUtils_h
+#define EGLUtils_h
+
+#include <egl.h>
+#include <wtf/Assertions.h>
+
+static inline const char* toEGLErrorConstant(EGLint error)
+{
+ switch (error) {
+ case EGL_NOT_INITIALIZED:
+ return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS:
+ return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC:
+ return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE:
+ return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONTEXT:
+ return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CONFIG:
+ return "EGL_BAD_CONFIG";
+ case EGL_BAD_CURRENT_SURFACE:
+ return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY:
+ return "EGL_BAD_DISPLAY";
+ case EGL_BAD_SURFACE:
+ return "EGL_BAD_SURFACE";
+ case EGL_BAD_MATCH:
+ return "EGL_BAD_MATCH";
+ case EGL_BAD_PARAMETER:
+ return "EGL_BAD_PARAMETER";
+ case EGL_BAD_NATIVE_PIXMAP:
+ return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW:
+ return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_CONTEXT_LOST:
+ return "EGL_CONTEXT_LOST";
+ default:
+ return "UNKNOWN_ERROR";
+ }
+}
+
+#if ASSERT_DISABLED
+#define ASSERT_EGL_NO_ERROR() ((void)0)
+#else
+#define ASSERT_EGL_NO_ERROR() do { \
+ EGLint eglErrorCode = eglGetError(); \
+ ASSERT_WITH_MESSAGE(eglErrorCode == EGL_SUCCESS, "Found %s", toEGLErrorConstant(eglErrorCode)); \
+} while (0)
+#endif
+
+#endif
diff --git a/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp b/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp
new file mode 100644
index 0000000..5ed892c
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp
@@ -0,0 +1,566 @@
+/*
+ * 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 "GraphicsContext.h"
+
+#include "GraphicsContextPrivate.h"
+#include "NotImplemented.h"
+#include "PainterOpenVG.h"
+#include "SurfaceOpenVG.h"
+#include "TransformationMatrix.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(EGL)
+#include "EGLDisplayOpenVG.h"
+#include "EGLUtils.h"
+#include <egl.h>
+#endif
+
+namespace WebCore {
+
+// typedef'ing doesn't work, let's inherit from PainterOpenVG instead
+class GraphicsContextPlatformPrivate : public PainterOpenVG {
+public:
+ GraphicsContextPlatformPrivate(SurfaceOpenVG* surface)
+ : PainterOpenVG(surface)
+ {
+ }
+};
+
+GraphicsContext::GraphicsContext(SurfaceOpenVG* surface)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(surface ? new GraphicsContextPlatformPrivate(surface) : 0)
+{
+ setPaintingDisabled(!surface);
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ destroyGraphicsContextPrivate(m_common);
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ if (paintingDisabled())
+ return 0;
+
+ return m_data->baseSurface();
+}
+
+TransformationMatrix GraphicsContext::getCTM() const
+{
+ if (paintingDisabled())
+ return TransformationMatrix();
+
+ return m_data->transformationMatrix();
+}
+
+void GraphicsContext::savePlatformState()
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->restore();
+}
+
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawRect(rect);
+}
+
+void GraphicsContext::drawLine(const IntPoint& from, const IntPoint& to)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawLine(from, to);
+}
+
+/**
+ * Draw the largest ellipse that fits into the given rectangle.
+ */
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawEllipse(rect);
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawArc(rect, startAngle, angleSpan, VG_STROKE_PATH);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawPolygon(numPoints, points);
+
+ UNUSED_PARAM(shouldAntialias); // FIXME
+}
+
+void GraphicsContext::fillPath()
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::strokePath()
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawRect(rect, VG_FILL_PATH);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ Color oldColor = m_data->fillColor();
+ m_data->setFillColor(color);
+ m_data->drawRect(rect, VG_FILL_PATH);
+ m_data->setFillColor(oldColor);
+
+ UNUSED_PARAM(colorSpace); // FIXME
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ Color oldColor = m_data->fillColor();
+ m_data->setFillColor(color);
+ m_data->drawRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight, VG_FILL_PATH);
+ m_data->setFillColor(oldColor);
+
+ UNUSED_PARAM(colorSpace); // FIXME
+}
+
+void GraphicsContext::beginPath()
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::addPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->intersectClipRect(rect);
+}
+
+void GraphicsContext::clipPath(WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(clipRule);
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (rects.isEmpty())
+ return;
+
+ // FIXME: We just unite all focus ring rects into one for now.
+ // We should outline the edge of the full region.
+ offset += (width - 1) / 2;
+ IntRect finalFocusRect;
+
+ for (unsigned i = 0; i < rects.size(); i++) {
+ IntRect focusRect = rects[i];
+ focusRect.inflate(offset);
+ finalFocusRect.unite(focusRect);
+ }
+
+ StrokeStyle oldStyle = m_data->strokeStyle();
+ Color oldStrokeColor = m_data->strokeColor();
+ m_data->setStrokeStyle(DashedStroke);
+ m_data->setStrokeColor(color);
+ strokeRect(FloatRect(finalFocusRect), 1.f);
+ m_data->setStrokeStyle(oldStyle);
+ m_data->setStrokeColor(oldStrokeColor);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ if (width <= 0)
+ return;
+
+ StrokeStyle oldStyle = m_data->strokeStyle();
+ m_data->setStrokeStyle(SolidStroke);
+ drawLine(origin, origin + IntSize(width, 0));
+ m_data->setStrokeStyle(oldStyle);
+
+ UNUSED_PARAM(printing);
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(origin);
+ UNUSED_PARAM(width);
+ UNUSED_PARAM(grammar);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return FloatRect();
+
+ return FloatRect(enclosingIntRect(m_data->transformationMatrix().mapRect(rect)));
+}
+
+void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(size);
+ UNUSED_PARAM(blur);
+ UNUSED_PARAM(color);
+ UNUSED_PARAM(colorSpace);
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(opacity);
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ CompositeOperator op = m_data->compositeOperation();
+ m_data->setCompositeOperation(CompositeClear);
+ m_data->drawRect(rect, VG_FILL_PATH);
+ m_data->setCompositeOperation(op);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->drawRect(rect, VG_STROKE_PATH);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ float oldThickness = m_data->strokeThickness();
+ m_data->setStrokeThickness(lineWidth);
+ m_data->drawRect(rect, VG_STROKE_PATH);
+ m_data->setStrokeThickness(oldThickness);
+}
+
+void GraphicsContext::setLineCap(LineCap lc)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setLineCap(lc);
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setLineDash(dashes, dashOffset);
+}
+
+void GraphicsContext::setLineJoin(LineJoin lj)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setLineJoin(lj);
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setMiterLimit(limit);
+}
+
+void GraphicsContext::setAlpha(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setOpacity(opacity);
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setCompositeOperation(op);
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(path);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(path);
+}
+
+void GraphicsContext::scale(const FloatSize& scaleFactors)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->scale(scaleFactors);
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->rotate(radians);
+}
+
+void GraphicsContext::translate(float dx, float dy)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->translate(dx, dy);
+}
+
+IntPoint GraphicsContext::origin()
+{
+ if (paintingDisabled())
+ return IntPoint();
+
+ TransformationMatrix matrix = m_data->transformationMatrix();
+ return IntPoint(roundf(matrix.m41()), roundf(matrix.m42()));
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(rect);
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(rect);
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(rect);
+ UNUSED_PARAM(imageBuffer);
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ UNUSED_PARAM(rect);
+ UNUSED_PARAM(thickness);
+}
+
+void GraphicsContext::concatCTM(const TransformationMatrix& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->concatTransformationMatrix(transform);
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ notImplemented();
+ UNUSED_PARAM(link);
+ UNUSED_PARAM(destRect);
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setStrokeColor(color);
+
+ UNUSED_PARAM(colorSpace); // FIXME
+}
+
+void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setStrokeStyle(strokeStyle);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setStrokeThickness(thickness);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setFillColor(color);
+
+ UNUSED_PARAM(colorSpace); // FIXME
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->setAntialiasingEnabled(enable);
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+ notImplemented();
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ notImplemented();
+ return InterpolationDefault;
+}
+
+}
diff --git a/WebCore/platform/graphics/openvg/PainterOpenVG.cpp b/WebCore/platform/graphics/openvg/PainterOpenVG.cpp
new file mode 100644
index 0000000..3b7cf85
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/PainterOpenVG.cpp
@@ -0,0 +1,957 @@
+/*
+ * 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 "PainterOpenVG.h"
+
+#include "Color.h"
+#include "DashArray.h"
+#include "FloatPoint.h"
+#include "FloatQuad.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "IntSize.h"
+#include "NotImplemented.h"
+#include "SurfaceOpenVG.h"
+#include "TransformationMatrix.h"
+#include "VGUtils.h"
+
+#if PLATFORM(EGL)
+#include "EGLUtils.h"
+#endif
+
+#include <vgu.h>
+
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+static bool isNonRotatedAffineTransformation(const TransformationMatrix& matrix)
+{
+ return matrix.m12() <= FLT_EPSILON && matrix.m13() <= FLT_EPSILON && matrix.m14() <= FLT_EPSILON
+ && matrix.m21() <= FLT_EPSILON && matrix.m23() <= FLT_EPSILON && matrix.m24() <= FLT_EPSILON
+ && matrix.m31() <= FLT_EPSILON && matrix.m32() <= FLT_EPSILON && matrix.m34() <= FLT_EPSILON
+ && matrix.m44() >= 1 - FLT_EPSILON;
+}
+
+static VGCapStyle toVGCapStyle(LineCap lineCap)
+{
+ switch (lineCap) {
+ case RoundCap:
+ return VG_CAP_ROUND;
+ case SquareCap:
+ return VG_CAP_SQUARE;
+ case ButtCap:
+ default:
+ return VG_CAP_BUTT;
+ }
+}
+
+static VGJoinStyle toVGJoinStyle(LineJoin lineJoin)
+{
+ switch (lineJoin) {
+ case RoundJoin:
+ return VG_JOIN_ROUND;
+ case BevelJoin:
+ return VG_JOIN_BEVEL;
+ case MiterJoin:
+ default:
+ return VG_JOIN_MITER;
+ }
+}
+
+static VGFillRule toVGFillRule(WindRule fillRule)
+{
+ return fillRule == RULE_EVENODD ? VG_EVEN_ODD : VG_NON_ZERO;
+}
+
+static VGuint colorToVGColor(const Color& color)
+{
+ VGuint vgColor = color.red();
+ vgColor = (vgColor << 8) | color.green();
+ vgColor = (vgColor << 8) | color.blue();
+ vgColor = (vgColor << 8) | color.alpha();
+ return vgColor;
+}
+
+static void setVGSolidColor(VGPaintMode paintMode, const Color& color)
+{
+ VGPaint paint = vgCreatePaint();
+ vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+ vgSetColor(paint, colorToVGColor(color));
+ vgSetPaint(paint, paintMode);
+ vgDestroyPaint(paint);
+ ASSERT_VG_NO_ERROR();
+}
+
+
+struct PlatformPainterState {
+ TransformationMatrix surfaceTransformationMatrix;
+ CompositeOperator compositeOperation;
+ float opacity;
+
+ bool scissoringEnabled;
+ FloatRect scissorRect;
+
+ Color fillColor;
+ StrokeStyle strokeStyle;
+ Color strokeColor;
+ float strokeThickness;
+ LineCap strokeLineCap;
+ LineJoin strokeLineJoin;
+ float strokeMiterLimit;
+ DashArray strokeDashArray;
+ float strokeDashOffset;
+
+ bool antialiasingEnabled;
+
+ PlatformPainterState()
+ : compositeOperation(CompositeSourceOver)
+ , opacity(1.0)
+ , scissoringEnabled(false)
+ , fillColor(Color::black)
+ , strokeStyle(NoStroke)
+ , strokeThickness(0.0)
+ , strokeLineCap(ButtCap)
+ , strokeLineJoin(MiterJoin)
+ , strokeMiterLimit(4.0)
+ , strokeDashOffset(0.0)
+ , antialiasingEnabled(true)
+ {
+ }
+
+ PlatformPainterState(const PlatformPainterState& state)
+ {
+ surfaceTransformationMatrix = state.surfaceTransformationMatrix;
+
+ scissoringEnabled = state.scissoringEnabled;
+ scissorRect = state.scissorRect;
+ copyPaintState(&state);
+ }
+
+ void copyPaintState(const PlatformPainterState* other)
+ {
+ compositeOperation = other->compositeOperation;
+ opacity = other->opacity;
+
+ fillColor = other->fillColor;
+ strokeStyle = other->strokeStyle;
+ strokeColor = other->strokeColor;
+ strokeThickness = other->strokeThickness;
+ strokeLineCap = other->strokeLineCap;
+ strokeLineJoin = other->strokeLineJoin;
+ strokeMiterLimit = other->strokeMiterLimit;
+ strokeDashArray = other->strokeDashArray;
+ strokeDashOffset = other->strokeDashOffset;
+
+ antialiasingEnabled = other->antialiasingEnabled;
+ }
+
+ void applyState(PainterOpenVG* painter)
+ {
+ ASSERT(painter);
+
+ setVGSolidColor(VG_FILL_PATH, fillColor);
+ setVGSolidColor(VG_STROKE_PATH, strokeColor);
+
+ vgSetf(VG_STROKE_LINE_WIDTH, strokeThickness);
+ vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(strokeLineCap));
+ vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(strokeLineJoin));
+ vgSetf(VG_STROKE_MITER_LIMIT, strokeMiterLimit);
+
+ if (antialiasingEnabled)
+ vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER);
+ else
+ vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+
+ applyBlending(painter);
+ applyStrokeStyle();
+
+ applyTransformationMatrix(painter);
+ applyScissorRect();
+ }
+
+ void applyBlending(PainterOpenVG* painter)
+ {
+ VGBlendMode blendMode = VG_BLEND_SRC_OVER;
+
+ switch (compositeOperation) {
+ case CompositeClear: {
+ // Clear means "set to fully transparent regardless of SRC".
+ // We implement that by multiplying DST with white color
+ // (= no changes) and an alpha of 1.0 - opacity, so the destination
+ // pixels will be fully transparent when opacity == 1.0 and
+ // unchanged when opacity == 0.0.
+ blendMode = VG_BLEND_DST_IN;
+ const VGfloat values[] = { 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 - opacity };
+ vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values);
+ vgSeti(VG_COLOR_TRANSFORM, VG_TRUE);
+ ASSERT_VG_NO_ERROR();
+ break;
+ }
+ case CompositeCopy:
+ blendMode = VG_BLEND_SRC;
+ break;
+ case CompositeSourceOver:
+ blendMode = VG_BLEND_SRC_OVER;
+ break;
+ case CompositeSourceIn:
+ blendMode = VG_BLEND_SRC_IN;
+ break;
+ case CompositeSourceOut:
+ notImplemented();
+ break;
+ case CompositeSourceAtop:
+ notImplemented();
+ break;
+ case CompositeDestinationOver:
+ blendMode = VG_BLEND_DST_OVER;
+ break;
+ case CompositeDestinationIn:
+ blendMode = VG_BLEND_DST_IN;
+ break;
+ case CompositeDestinationOut:
+ notImplemented();
+ break;
+ case CompositeDestinationAtop:
+ notImplemented();
+ break;
+ case CompositeXOR:
+ notImplemented();
+ break;
+ case CompositePlusDarker:
+ blendMode = VG_BLEND_DARKEN;
+ break;
+ case CompositeHighlight:
+ notImplemented();
+ break;
+ case CompositePlusLighter:
+ blendMode = VG_BLEND_LIGHTEN;
+ break;
+ }
+
+ if (compositeOperation != CompositeClear) {
+ if (opacity >= (1.0 - FLT_EPSILON))
+ vgSeti(VG_COLOR_TRANSFORM, VG_FALSE);
+ else if (blendMode == VG_BLEND_SRC) {
+ blendMode = VG_BLEND_SRC_OVER;
+ VGfloat values[] = { 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, opacity };
+ vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values);
+ vgSeti(VG_COLOR_TRANSFORM, VG_TRUE);
+ } else {
+ VGfloat values[] = { 1.0, 1.0, 1.0, opacity, 0.0, 0.0, 0.0, 0.0 };
+ vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values);
+ vgSeti(VG_COLOR_TRANSFORM, VG_TRUE);
+ }
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgSeti(VG_BLEND_MODE, blendMode);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ void applyTransformationMatrix(PainterOpenVG* painter)
+ {
+ // There are *five* separate transforms that can be applied to OpenVG as of 1.1
+ // but it is not clear that we need to set them separately. Instead we set them
+ // all right here and let this be a call to essentially set the world transformation!
+ VGMatrix vgMatrix(surfaceTransformationMatrix);
+ const VGfloat* vgFloatArray = vgMatrix.toVGfloat();
+
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgLoadMatrix(vgFloatArray);
+ ASSERT_VG_NO_ERROR();
+
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(vgFloatArray);
+ ASSERT_VG_NO_ERROR();
+
+#ifdef OPENVG_VERSION_1_1
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
+ vgLoadMatrix(vgFloatArray);
+ ASSERT_VG_NO_ERROR();
+#endif
+ }
+
+ void applyScissorRect()
+ {
+ if (scissoringEnabled) {
+ vgSeti(VG_SCISSORING, VG_TRUE);
+ vgSetfv(VG_SCISSOR_RECTS, 4, VGRect(scissorRect).toVGfloat());
+ } else
+ vgSeti(VG_SCISSORING, VG_FALSE);
+
+ ASSERT_VG_NO_ERROR();
+ }
+
+ void applyStrokeStyle()
+ {
+ if (strokeStyle == DottedStroke) {
+ VGfloat vgFloatArray[2] = { 1.0, 1.0 };
+ vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray);
+ vgSetf(VG_STROKE_DASH_PHASE, 0.0);
+ } else if (strokeStyle == DashedStroke) {
+ if (!strokeDashArray.size()) {
+ VGfloat vgFloatArray[2] = { 4.0, 3.0 };
+ vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray);
+ } else {
+ Vector<VGfloat> vgFloatArray(strokeDashArray.size());
+ for (int i = 0; i < strokeDashArray.size(); ++i)
+ vgFloatArray[i] = strokeDashArray[i];
+
+ vgSetfv(VG_STROKE_DASH_PATTERN, vgFloatArray.size(), vgFloatArray.data());
+ }
+ vgSetf(VG_STROKE_DASH_PHASE, strokeDashOffset);
+ } else {
+ vgSetfv(VG_STROKE_DASH_PATTERN, 0, 0);
+ vgSetf(VG_STROKE_DASH_PHASE, 0.0);
+ }
+
+ ASSERT_VG_NO_ERROR();
+ }
+
+ inline bool strokeDisabled() const
+ {
+ return (compositeOperation == CompositeSourceOver
+ && (strokeStyle == NoStroke || !strokeColor.alpha()));
+ }
+
+ inline bool fillDisabled() const
+ {
+ return (compositeOperation == CompositeSourceOver && !fillColor.alpha());
+ }
+};
+
+
+PainterOpenVG::PainterOpenVG()
+ : m_state(0)
+ , m_surface(0)
+{
+}
+
+PainterOpenVG::PainterOpenVG(SurfaceOpenVG* surface)
+ : m_state(0)
+ , m_surface(0)
+{
+ ASSERT(surface);
+ begin(surface);
+}
+
+PainterOpenVG::~PainterOpenVG()
+{
+ end();
+}
+
+void PainterOpenVG::begin(SurfaceOpenVG* surface)
+{
+ if (surface == m_surface)
+ return;
+
+ ASSERT(surface);
+ ASSERT(!m_state);
+
+ m_surface = surface;
+
+ m_stateStack.append(new PlatformPainterState());
+ m_state = m_stateStack.last();
+
+ m_surface->setActivePainter(this);
+ m_surface->makeCurrent();
+}
+
+void PainterOpenVG::end()
+{
+ if (!m_surface)
+ return;
+
+ m_surface->setActivePainter(0);
+ m_surface = 0;
+
+ destroyPainterStates();
+}
+
+void PainterOpenVG::destroyPainterStates()
+{
+ PlatformPainterState* state = 0;
+ while (!m_stateStack.isEmpty()) {
+ state = m_stateStack.last();
+ m_stateStack.removeLast();
+ delete state;
+ }
+ m_state = 0;
+}
+
+// Called by friend SurfaceOpenVG, private otherwise.
+void PainterOpenVG::applyState()
+{
+ ASSERT(m_state);
+ m_state->applyState(this);
+}
+
+/**
+ * Copy the current back buffer image onto the surface.
+ *
+ * Call this method when all painting operations have been completed,
+ * otherwise the surface won't visibly change.
+ */
+void PainterOpenVG::blitToSurface()
+{
+ ASSERT(m_state); // implies m_surface
+ m_surface->flush();
+}
+
+TransformationMatrix PainterOpenVG::transformationMatrix() const
+{
+ ASSERT(m_state);
+ return m_state->surfaceTransformationMatrix;
+}
+
+void PainterOpenVG::concatTransformationMatrix(const TransformationMatrix& matrix)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ // We do the multiplication ourself using WebCore's TransformationMatrix rather than
+ // offloading this to VG via vgMultMatrix to keep things simple and so we can maintain
+ // state ourselves.
+ m_state->surfaceTransformationMatrix.multLeft(matrix);
+ m_state->applyTransformationMatrix(this);
+}
+
+void PainterOpenVG::setTransformationMatrix(const TransformationMatrix& matrix)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->surfaceTransformationMatrix = matrix;
+ m_state->applyTransformationMatrix(this);
+}
+
+CompositeOperator PainterOpenVG::compositeOperation() const
+{
+ ASSERT(m_state);
+ return m_state->compositeOperation;
+}
+
+void PainterOpenVG::setCompositeOperation(CompositeOperator op)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->compositeOperation = op;
+ m_state->applyBlending(this);
+}
+
+float PainterOpenVG::opacity() const
+{
+ ASSERT(m_state);
+ return m_state->opacity;
+}
+
+void PainterOpenVG::setOpacity(float opacity)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->opacity = opacity;
+ m_state->applyBlending(this);
+}
+
+float PainterOpenVG::strokeThickness() const
+{
+ ASSERT(m_state);
+ return m_state->strokeThickness;
+}
+
+void PainterOpenVG::setStrokeThickness(float thickness)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeThickness = thickness;
+ vgSetf(VG_STROKE_LINE_WIDTH, thickness);
+ ASSERT_VG_NO_ERROR();
+}
+
+StrokeStyle PainterOpenVG::strokeStyle() const
+{
+ ASSERT(m_state);
+ return m_state->strokeStyle;
+}
+
+void PainterOpenVG::setStrokeStyle(const StrokeStyle& style)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeStyle = style;
+ m_state->applyStrokeStyle();
+}
+
+void PainterOpenVG::setLineDash(const DashArray& dashArray, float dashOffset)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeDashArray = dashArray;
+ m_state->strokeDashOffset = dashOffset;
+ m_state->applyStrokeStyle();
+}
+
+void PainterOpenVG::setLineCap(LineCap lineCap)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeLineCap = lineCap;
+ vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(lineCap));
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::setLineJoin(LineJoin lineJoin)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeLineJoin = lineJoin;
+ vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(lineJoin));
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::setMiterLimit(float miterLimit)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeMiterLimit = miterLimit;
+ vgSetf(VG_STROKE_MITER_LIMIT, miterLimit);
+ ASSERT_VG_NO_ERROR();
+}
+
+Color PainterOpenVG::strokeColor() const
+{
+ ASSERT(m_state);
+ return m_state->strokeColor;
+}
+
+void PainterOpenVG::setStrokeColor(const Color& color)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->strokeColor = color;
+ setVGSolidColor(VG_STROKE_PATH, color);
+}
+
+Color PainterOpenVG::fillColor() const
+{
+ ASSERT(m_state);
+ return m_state->fillColor;
+}
+
+void PainterOpenVG::setFillColor(const Color& color)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->fillColor = color;
+ setVGSolidColor(VG_FILL_PATH, color);
+}
+
+bool PainterOpenVG::antialiasingEnabled() const
+{
+ ASSERT(m_state);
+ return m_state->antialiasingEnabled;
+}
+
+void PainterOpenVG::setAntialiasingEnabled(bool enabled)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ m_state->antialiasingEnabled = enabled;
+
+ if (enabled)
+ vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER);
+ else
+ vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
+}
+
+void PainterOpenVG::scale(const FloatSize& scaleFactors)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ TransformationMatrix matrix = m_state->surfaceTransformationMatrix;
+ matrix.scaleNonUniform(scaleFactors.width(), scaleFactors.height());
+ setTransformationMatrix(matrix);
+}
+
+void PainterOpenVG::rotate(float radians)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ TransformationMatrix matrix = m_state->surfaceTransformationMatrix;
+ matrix.rotate(rad2deg(radians));
+ setTransformationMatrix(matrix);
+}
+
+void PainterOpenVG::translate(float dx, float dy)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ TransformationMatrix matrix = m_state->surfaceTransformationMatrix;
+ matrix.translate(dx, dy);
+ setTransformationMatrix(matrix);
+}
+
+void PainterOpenVG::intersectScissorRect(const FloatRect& rect)
+{
+ // Scissor rectangles are defined by float values, but e.g. painting
+ // something red to a float-clipped rectangle and then painting something
+ // white to the same rectangle will leave some red remnants as it is
+ // rendered to full pixels in between. Also, some OpenVG implementations
+ // are likely to clip to integer coordinates anyways because of the above
+ // effect. So considering the above (and confirming through tests) the
+ // visual result is better if we clip to the enclosing integer rectangle
+ // rather than the exact float rectangle for scissoring.
+ if (m_state->scissoringEnabled)
+ m_state->scissorRect.intersect(FloatRect(enclosingIntRect(rect)));
+ else {
+ m_state->scissoringEnabled = true;
+ m_state->scissorRect = FloatRect(enclosingIntRect(rect));
+ }
+
+ m_state->applyScissorRect();
+}
+
+void PainterOpenVG::intersectClipRect(const FloatRect& rect)
+{
+ ASSERT(m_state);
+ m_surface->makeCurrent();
+
+ if (m_state->surfaceTransformationMatrix.isIdentity()) {
+ // No transformation required, skip all the complex stuff.
+ intersectScissorRect(rect);
+ return;
+ }
+
+ // Check if the actual destination rectangle is still rectilinear (can be
+ // represented as FloatRect) so we could apply scissoring instead of
+ // (potentially more expensive) path clipping. Note that scissoring is not
+ // subject to transformations, so we need to do the transformation to
+ // surface coordinates by ourselves.
+ FloatQuad effectiveScissorQuad =
+ m_state->surfaceTransformationMatrix.mapQuad(FloatQuad(rect));
+
+ if (effectiveScissorQuad.isRectilinear())
+ intersectScissorRect(effectiveScissorQuad.boundingBox());
+ else {
+ // The transformed scissorRect cannot be represented as FloatRect
+ // anymore, so we need to perform masking instead. Not yet implemented.
+ notImplemented();
+ }
+}
+
+void PainterOpenVG::drawRect(const FloatRect& rect, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 5 /* expected number of segments */,
+ 5 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ if (vguRect(path, rect.x(), rect.y(), rect.width(), rect.height()) == VGU_NO_ERROR) {
+ vgDrawPath(path, paintModes);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawRoundedRect(const FloatRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 10 /* expected number of segments */,
+ 25 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ // clamp corner arc sizes
+ FloatSize clampedTopLeft = FloatSize(topLeft).shrunkTo(rect.size()).expandedTo(FloatSize());
+ FloatSize clampedTopRight = FloatSize(topRight).shrunkTo(rect.size()).expandedTo(FloatSize());
+ FloatSize clampedBottomLeft = FloatSize(bottomLeft).shrunkTo(rect.size()).expandedTo(FloatSize());
+ FloatSize clampedBottomRight = FloatSize(bottomRight).shrunkTo(rect.size()).expandedTo(FloatSize());
+
+ // As OpenVG's coordinate system is flipped in comparison to WebKit's,
+ // we have to specify the opposite value for the "clockwise" value.
+ static const VGubyte pathSegments[] = {
+ VG_MOVE_TO_ABS,
+ VG_HLINE_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_VLINE_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_HLINE_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_VLINE_TO_REL,
+ VG_SCCWARC_TO_REL,
+ VG_CLOSE_PATH
+ };
+ // Also, the rounded rectangle path proceeds from the top to the bottom,
+ // requiring height distances and clamped radius sizes to be flipped.
+ const VGfloat pathData[] = {
+ rect.x() + clampedTopLeft.width(), rect.y(),
+ rect.width() - clampedTopLeft.width() - clampedTopRight.width(),
+ clampedTopRight.width(), clampedTopRight.height(), 0, clampedTopRight.width(), clampedTopRight.height(),
+ rect.height() - clampedTopRight.height() - clampedBottomRight.height(),
+ clampedBottomRight.width(), clampedBottomRight.height(), 0, -clampedBottomRight.width(), clampedBottomRight.height(),
+ -(rect.width() - clampedBottomLeft.width() - clampedBottomRight.width()),
+ clampedBottomLeft.width(), clampedBottomLeft.height(), 0, -clampedBottomLeft.width(), -clampedBottomLeft.height(),
+ -(rect.height() - clampedTopLeft.height() - clampedBottomLeft.height()),
+ clampedTopLeft.width(), clampedTopLeft.height(), 0, clampedTopLeft.width(), -clampedTopLeft.height(),
+ };
+
+ vgAppendPathData(path, 10, pathSegments, pathData);
+ vgDrawPath(path, paintModes);
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawLine(const IntPoint& from, const IntPoint& to)
+{
+ ASSERT(m_state);
+
+ if (m_state->strokeDisabled())
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 2 /* expected number of segments */,
+ 4 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ VGUErrorCode errorCode;
+
+ // Try to align lines to pixels, centering them between pixels for odd thickness values.
+ if (fmod(m_state->strokeThickness + 0.5, 2.0) < 1.0)
+ errorCode = vguLine(path, from.x(), from.y(), to.x(), to.y());
+ else if ((to.y() - from.y()) > (to.x() - from.x())) // more vertical than horizontal
+ errorCode = vguLine(path, from.x() + 0.5, from.y(), to.x() + 0.5, to.y());
+ else
+ errorCode = vguLine(path, from.x(), from.y() + 0.5, to.x(), to.y() + 0.5);
+
+ if (errorCode == VGU_NO_ERROR) {
+ vgDrawPath(path, VG_STROKE_PATH);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawArc(const IntRect& rect, int startAngle, int angleSpan, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 2 /* expected number of segments */,
+ 4 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ if (vguArc(path, rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0, rect.width(), rect.height(), -startAngle, -angleSpan, VGU_ARC_OPEN) == VGU_NO_ERROR) {
+ vgDrawPath(path, VG_STROKE_PATH);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawEllipse(const IntRect& rect, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ 4 /* expected number of segments */,
+ 12 /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ if (vguEllipse(path, rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0, rect.width(), rect.height()) == VGU_NO_ERROR) {
+ vgDrawPath(path, paintModes);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::drawPolygon(size_t numPoints, const FloatPoint* points, VGbitfield specifiedPaintModes)
+{
+ ASSERT(m_state);
+
+ VGbitfield paintModes = 0;
+ if (!m_state->strokeDisabled())
+ paintModes |= VG_STROKE_PATH;
+ if (!m_state->fillDisabled())
+ paintModes |= VG_FILL_PATH;
+
+ paintModes &= specifiedPaintModes;
+
+ if (!paintModes)
+ return;
+
+ m_surface->makeCurrent();
+
+ // Path segments: all points + "close path".
+ const VGint numSegments = numPoints + 1;
+ const VGint numCoordinates = numPoints * 2;
+
+ VGPath path = vgCreatePath(
+ VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
+ 1.0 /* scale */, 0.0 /* bias */,
+ numSegments /* expected number of segments */,
+ numCoordinates /* expected number of total coordinates */,
+ VG_PATH_CAPABILITY_APPEND_TO);
+ ASSERT_VG_NO_ERROR();
+
+ Vector<VGfloat> vgPoints(numCoordinates);
+ for (int i = 0; i < numPoints; ++i) {
+ vgPoints[i*2] = points[i].x();
+ vgPoints[i*2 + 1] = points[i].y();
+ }
+
+ if (vguPolygon(path, vgPoints.data(), numPoints, VG_TRUE /* closed */) == VGU_NO_ERROR) {
+ vgDrawPath(path, paintModes);
+ ASSERT_VG_NO_ERROR();
+ }
+
+ vgDestroyPath(path);
+ ASSERT_VG_NO_ERROR();
+}
+
+void PainterOpenVG::save(PainterOpenVG::SaveMode saveMode)
+{
+ ASSERT(m_state);
+
+ // If the underlying context/surface was switched away by someone without
+ // telling us, it might not correspond to the one assigned to this painter.
+ // Switch back so we can save the state properly. (Should happen rarely.)
+ // Use DontSaveOrApplyPainterState mode in order to avoid recursion.
+ m_surface->makeCurrent(SurfaceOpenVG::DontSaveOrApplyPainterState);
+
+ if (saveMode == PainterOpenVG::CreateNewState) {
+ PlatformPainterState* state = new PlatformPainterState(*m_state);
+ m_stateStack.append(state);
+ m_state = m_stateStack.last();
+ } else { // if (saveMode == PainterOpenVG::CreateNewStateWithPaintStateOnly) {
+ PlatformPainterState* state = new PlatformPainterState();
+ state->copyPaintState(m_state);
+ m_stateStack.append(state);
+ m_state = m_stateStack.last();
+ }
+}
+
+void PainterOpenVG::restore()
+{
+ ASSERT(m_stateStack.size() >= 2);
+ m_surface->makeCurrent(SurfaceOpenVG::DontApplyPainterState);
+
+ PlatformPainterState* state = m_stateStack.last();
+ m_stateStack.removeLast();
+ delete state;
+
+ m_state = m_stateStack.last();
+ m_state->applyState(this);
+}
+
+}
diff --git a/WebCore/platform/graphics/openvg/PainterOpenVG.h b/WebCore/platform/graphics/openvg/PainterOpenVG.h
new file mode 100644
index 0000000..6936eee
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/PainterOpenVG.h
@@ -0,0 +1,121 @@
+/*
+ * 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 PainterOpenVG_h
+#define PainterOpenVG_h
+
+#include "Color.h"
+#include "GraphicsContext.h"
+
+#include <openvg.h>
+
+#include <wtf/Noncopyable.h>
+#include <wtf/Platform.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatRect;
+class IntRect;
+class IntSize;
+class SurfaceOpenVG;
+class TransformationMatrix;
+
+struct PlatformPainterState;
+
+class PainterOpenVG : public Noncopyable {
+public:
+ friend class SurfaceOpenVG;
+ friend struct PlatformPainterState;
+
+ enum SaveMode {
+ CreateNewState,
+ CreateNewStateWithPaintStateOnly // internal usage only, do not use outside PainterOpenVG
+ };
+
+ PainterOpenVG();
+ PainterOpenVG(SurfaceOpenVG*);
+ ~PainterOpenVG();
+
+ void begin(SurfaceOpenVG*);
+ void end();
+
+ TransformationMatrix transformationMatrix() const;
+ void setTransformationMatrix(const TransformationMatrix&);
+ void concatTransformationMatrix(const TransformationMatrix&);
+
+ CompositeOperator compositeOperation() const;
+ void setCompositeOperation(CompositeOperator);
+ float opacity() const;
+ void setOpacity(float);
+
+ float strokeThickness() const;
+ void setStrokeThickness(float);
+ StrokeStyle strokeStyle() const;
+ void setStrokeStyle(const StrokeStyle&);
+
+ void setLineDash(const DashArray&, float dashOffset);
+ void setLineCap(LineCap);
+ void setLineJoin(LineJoin);
+ void setMiterLimit(float);
+
+ Color strokeColor() const;
+ void setStrokeColor(const Color&);
+
+ Color fillColor() const;
+ void setFillColor(const Color&);
+
+ bool antialiasingEnabled() const;
+ void setAntialiasingEnabled(bool);
+
+ void drawRect(const FloatRect&, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH));
+ void drawRoundedRect(const FloatRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH));
+ void drawLine(const IntPoint& from, const IntPoint& to);
+ 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 scale(const FloatSize& scaleFactors);
+ void rotate(float radians);
+ void translate(float dx, float dy);
+
+ void intersectClipRect(const FloatRect&);
+
+ void save(PainterOpenVG::SaveMode saveMode = CreateNewState);
+ void restore();
+
+ SurfaceOpenVG* surface() { return m_surface; }
+ void blitToSurface();
+
+private:
+ void destroyPainterStates();
+ void applyState();
+
+ void intersectScissorRect(const FloatRect&);
+
+private:
+ Vector<PlatformPainterState*> m_stateStack;
+ PlatformPainterState* m_state;
+ SurfaceOpenVG* m_surface;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp b/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp
new file mode 100644
index 0000000..9539f2c
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp
@@ -0,0 +1,243 @@
+/*
+ * 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 "SurfaceOpenVG.h"
+
+#include "IntSize.h"
+#include "PainterOpenVG.h"
+
+#if PLATFORM(EGL)
+#include "EGLDisplayOpenVG.h"
+#include "EGLUtils.h"
+#endif
+
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+PainterOpenVG* SurfaceOpenVG::s_currentPainter = 0;
+
+SurfaceOpenVG* SurfaceOpenVG::currentSurface()
+{
+#if PLATFORM(EGL)
+ return EGLDisplayOpenVG::currentSurface();
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+#if PLATFORM(EGL)
+SurfaceOpenVG::SurfaceOpenVG(const IntSize& size, const EGLDisplay& display, EGLConfig* confPtr, EGLint* errorCode)
+ : m_activePainter(0)
+ , m_eglDisplay(display)
+ , m_eglSurface(EGL_NO_SURFACE)
+ , m_eglContext(EGL_NO_CONTEXT)
+{
+ ASSERT(m_eglDisplay != EGL_NO_DISPLAY);
+
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay);
+ EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultPbufferConfig();
+ m_eglSurface = displayManager->createPbufferSurface(size, config, errorCode);
+
+ if (m_eglSurface == EGL_NO_SURFACE)
+ return;
+
+ m_eglContext = displayManager->contextForSurface(m_eglSurface);
+ EGLDisplayOpenVG::registerPlatformSurface(this);
+}
+
+SurfaceOpenVG::SurfaceOpenVG(EGLNativeWindowType window, const EGLDisplay& display, EGLConfig* confPtr)
+ : m_activePainter(0)
+ , m_eglDisplay(display)
+ , m_eglSurface(EGL_NO_SURFACE)
+ , m_eglContext(EGL_NO_CONTEXT)
+{
+ ASSERT(m_eglDisplay != EGL_NO_DISPLAY);
+
+ EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay);
+ EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultWindowConfig();
+ m_eglSurface = displayManager->surfaceForWindow(window, config);
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ m_eglContext = displayManager->contextForSurface(m_eglSurface);
+ EGLDisplayOpenVG::registerPlatformSurface(this);
+}
+
+// Constructor only accessible to EGLDisplayOpenVG for shared context
+// initialization. The parameter types might define to void* like in the
+// window surface constructor, so it can't be overloaded with all the required
+// arguments and EGLDisplayOpenVG basically implements the constructor
+// by itself.
+SurfaceOpenVG::SurfaceOpenVG()
+ : m_activePainter(0)
+ , m_eglDisplay(EGL_NO_DISPLAY)
+ , m_eglSurface(EGL_NO_SURFACE)
+ , m_eglContext(EGL_NO_CONTEXT)
+{
+}
+#endif
+
+SurfaceOpenVG::~SurfaceOpenVG()
+{
+ if (!isValid())
+ return;
+
+ if (m_activePainter && this == m_activePainter->baseSurface())
+ m_activePainter->end();
+
+#if PLATFORM(EGL)
+ EGLDisplayOpenVG::forDisplay(m_eglDisplay)->destroySurface(m_eglSurface);
+ EGLDisplayOpenVG::unregisterPlatformSurface(this);
+#else
+ ASSERT_NOT_REACHED();
+#endif
+}
+
+bool SurfaceOpenVG::isValid() const
+{
+#if PLATFORM(EGL)
+ return (m_eglSurface != EGL_NO_SURFACE);
+#else
+ ASSERT_NOT_REACHED();
+ return false;
+#endif
+}
+
+int SurfaceOpenVG::width() const
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ EGLint width;
+ eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &width);
+ ASSERT_EGL_NO_ERROR();
+ return width;
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+int SurfaceOpenVG::height() const
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ EGLint height;
+ eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &height);
+ ASSERT_EGL_NO_ERROR();
+ return height;
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+SurfaceOpenVG* SurfaceOpenVG::sharedSurface() const
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+ return EGLDisplayOpenVG::forDisplay(m_eglDisplay)->sharedPlatformSurface();
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+}
+
+void SurfaceOpenVG::makeCurrent(MakeCurrentMode mode)
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ eglBindAPI(EGL_OPENVG_API);
+ ASSERT_EGL_NO_ERROR();
+ EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
+ ASSERT_EGL_NO_ERROR();
+
+ if (currentSurface != m_eglSurface) {
+ eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
+ ASSERT_EGL_NO_ERROR();
+ s_currentPainter = 0;
+ }
+#endif
+
+ if (m_activePainter && mode == ApplyPainterStateOnSurfaceSwitch
+ && s_currentPainter != m_activePainter) {
+ m_activePainter->applyState();
+ s_currentPainter = m_activePainter;
+ }
+}
+
+void SurfaceOpenVG::makeCompatibleCurrent()
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ eglBindAPI(EGL_OPENVG_API);
+ ASSERT_EGL_NO_ERROR();
+ EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
+ ASSERT_EGL_NO_ERROR();
+
+ if (currentSurface == m_eglSurface) {
+ if (m_activePainter && s_currentPainter != m_activePainter) {
+ m_activePainter->applyState();
+ s_currentPainter = m_activePainter;
+ }
+ } else if (!EGLDisplayOpenVG::forDisplay(m_eglDisplay)->surfacesCompatible(currentSurface, m_eglSurface)) {
+ eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
+ ASSERT_EGL_NO_ERROR();
+ s_currentPainter = 0;
+ }
+ // else: surfaces compatible, no need to switch contexts
+#endif
+}
+
+void SurfaceOpenVG::flush()
+{
+#if PLATFORM(EGL)
+ ASSERT(m_eglSurface != EGL_NO_SURFACE);
+
+ eglSwapBuffers(m_eglDisplay, m_eglSurface);
+ ASSERT_EGL_NO_ERROR();
+#endif
+}
+
+void SurfaceOpenVG::setActivePainter(PainterOpenVG* painter)
+{
+ ASSERT(isValid());
+
+ // If painter is non-zero, we want to make sure there was no previous painter set.
+ ASSERT(!painter || !m_activePainter);
+
+ // Make sure a disabled painter isn't marked as global current painter anymore.
+ if (!painter && s_currentPainter == m_activePainter)
+ s_currentPainter = 0;
+
+ m_activePainter = painter;
+}
+
+PainterOpenVG* SurfaceOpenVG::activePainter()
+{
+ ASSERT(isValid());
+ return m_activePainter;
+}
+
+}
diff --git a/WebCore/platform/graphics/openvg/SurfaceOpenVG.h b/WebCore/platform/graphics/openvg/SurfaceOpenVG.h
new file mode 100644
index 0000000..dc288dd
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/SurfaceOpenVG.h
@@ -0,0 +1,137 @@
+/*
+ * 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 SurfaceOpenVG_h
+#define SurfaceOpenVG_h
+
+#if PLATFORM(EGL)
+#include <egl.h>
+#endif
+
+#include <wtf/Noncopyable.h>
+#include <wtf/Platform.h>
+
+namespace WebCore {
+
+#if PLATFORM(EGL)
+class EGLDisplayOpenVG;
+#endif
+class PainterOpenVG;
+class IntSize;
+
+/**
+ * SurfaceOpenVG provides the functionality of surfaces and contexts that are
+ * underlying the OpenVG implementation. In the vast majority of cases, that
+ * underlying technology is EGL, but OpenVG doesn't depend on EGL per se.
+ * Wrapping surface/context functionality into a separate class avoids lots
+ * of #ifdefs and should make it easy to add different surface/context
+ * implementations than EGL.
+ */
+class SurfaceOpenVG : public Noncopyable {
+public:
+ enum MakeCurrentMode {
+ ApplyPainterStateOnSurfaceSwitch,
+ DontApplyPainterState,
+ };
+
+ static SurfaceOpenVG* currentSurface();
+
+#if PLATFORM(EGL)
+ friend class EGLDisplayOpenVG;
+
+ /**
+ * Create a new EGL pbuffer surface with the specified size and config on
+ * the given display. If config is not specified, the display's default
+ * pbuffer config is used.
+ *
+ * This constructor will trigger an assertion if creation of the surface
+ * fails, unless you pledge to manually process the error code by passing
+ * a non-zero pointer as errorCode parameter. The error code returned by
+ * eglGetError() will be written to that variable.
+ */
+ SurfaceOpenVG(const IntSize& size, const EGLDisplay& display, EGLConfig* config = 0, EGLint* errorCode = 0);
+
+ /**
+ * Create a new EGL window surface with the specified native window handle
+ * and config on the given display. If config is not specified, the
+ * display's default window config is used.
+ */
+ SurfaceOpenVG(EGLNativeWindowType window, const EGLDisplay& display, EGLConfig* config = 0);
+
+ EGLDisplay eglDisplay() const { return m_eglDisplay; }
+ EGLSurface eglSurface() const { return m_eglSurface; }
+ EGLContext eglContext() const { return m_eglContext; }
+#endif
+
+ ~SurfaceOpenVG();
+
+ /**
+ * If a surface is invalid (could not be created), all method calls will
+ * crash horribly.
+ */
+ bool isValid() const;
+
+ int width() const;
+ int height() const;
+
+ SurfaceOpenVG* sharedSurface() const;
+
+ /**
+ * Make the associated GL/EGL context the current one, so that subsequent
+ * OpenVG commands apply to it.
+ */
+ void makeCurrent(MakeCurrentMode mode = ApplyPainterStateOnSurfaceSwitch);
+
+ /**
+ * Make a surface/context combination current that is "compatible"
+ * (i.e. can access its shared resources) to the given one. If no
+ * surface/context is current, the given one is made current.
+ *
+ * This method is meant to avoid context changes if they're not
+ * necessary, particularly tailored for the case where something
+ * compatible to the shared surface is requested while actual painting
+ * happens on another surface.
+ */
+ void makeCompatibleCurrent();
+
+ /**
+ * Empty the OpenVG pipeline and make sure all the performed paint
+ * operations show up on the surface as actual drawn pixels.
+ */
+ void flush();
+
+ void setActivePainter(PainterOpenVG*);
+ PainterOpenVG* activePainter();
+
+private:
+ PainterOpenVG* m_activePainter;
+ static PainterOpenVG* s_currentPainter; // global currently active painter
+
+#if PLATFORM(EGL)
+ SurfaceOpenVG(); // for EGLDisplayOpenVG
+
+ EGLDisplay m_eglDisplay;
+ EGLSurface m_eglSurface;
+ EGLContext m_eglContext;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/openvg/VGUtils.cpp b/WebCore/platform/graphics/openvg/VGUtils.cpp
new file mode 100644
index 0000000..72ba5b2
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/VGUtils.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) Research In Motion Limited 2009. 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 "VGUtils.h"
+
+#include "FloatRect.h"
+#include "TransformationMatrix.h"
+
+namespace WebCore {
+
+VGMatrix::VGMatrix(const VGfloat data[9])
+{
+ m_data[0] = data[0];
+ m_data[1] = data[1];
+ m_data[2] = data[2];
+ m_data[3] = data[3];
+ m_data[4] = data[4];
+ m_data[5] = data[5];
+ m_data[6] = data[6];
+ m_data[7] = data[7];
+ m_data[8] = data[8];
+}
+
+VGMatrix::VGMatrix(const TransformationMatrix& matrix)
+{
+ m_data[0] = matrix.m11();
+ m_data[1] = matrix.m12();
+ m_data[2] = matrix.m14();
+ m_data[3] = matrix.m21();
+ m_data[4] = matrix.m22();
+ m_data[5] = matrix.m24();
+ m_data[6] = matrix.m41();
+ m_data[7] = matrix.m42();
+ m_data[8] = matrix.m44();
+}
+
+VGMatrix::operator TransformationMatrix() const
+{
+ TransformationMatrix matrix;
+ matrix.setM11(m_data[0]);
+ matrix.setM12(m_data[1]);
+ matrix.setM14(m_data[2]);
+ matrix.setM21(m_data[3]);
+ matrix.setM22(m_data[4]);
+ matrix.setM24(m_data[5]);
+ matrix.setM41(m_data[6]);
+ matrix.setM42(m_data[7]);
+ matrix.setM44(m_data[8]);
+ return matrix;
+}
+
+TransformationMatrix::operator VGMatrix() const
+{
+ return VGMatrix(*this);
+}
+
+VGRect::VGRect(const VGfloat data[4])
+{
+ m_data[0] = data[0];
+ m_data[1] = data[1];
+ m_data[2] = data[2];
+ m_data[3] = data[3];
+}
+
+VGRect::VGRect(const FloatRect& rect)
+{
+ m_data[0] = rect.x();
+ m_data[1] = rect.y();
+ m_data[2] = rect.width();
+ m_data[3] = rect.height();
+}
+
+VGRect::operator FloatRect() const
+{
+ return FloatRect(m_data[0], m_data[1], m_data[2], m_data[3]);
+}
+
+FloatRect::operator VGRect() const
+{
+ return VGRect(*this);
+}
+
+}
diff --git a/WebCore/platform/graphics/openvg/VGUtils.h b/WebCore/platform/graphics/openvg/VGUtils.h
new file mode 100644
index 0000000..083c15a
--- /dev/null
+++ b/WebCore/platform/graphics/openvg/VGUtils.h
@@ -0,0 +1,87 @@
+/*
+ * 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 VGUtils_h
+#define VGUtils_h
+
+#include <openvg.h>
+#include <wtf/Assertions.h>
+
+static inline const char* toVGErrorConstant(VGErrorCode error)
+{
+ switch (error) {
+ case VG_BAD_HANDLE_ERROR:
+ return "VG_BAD_HANDLE_ERROR";
+ case VG_ILLEGAL_ARGUMENT_ERROR:
+ return "VG_ILLEGAL_ARGUMENT_ERROR";
+ case VG_OUT_OF_MEMORY_ERROR:
+ return "VG_OUT_OF_MEMORY_ERROR";
+ case VG_PATH_CAPABILITY_ERROR:
+ return "VG_PATH_CAPABILITY_ERROR";
+ case VG_UNSUPPORTED_IMAGE_FORMAT_ERROR:
+ return "VG_UNSUPPORTED_IMAGE_FORMAT_ERROR";
+ case VG_UNSUPPORTED_PATH_FORMAT_ERROR:
+ return "VG_UNSUPPORTED_PATH_FORMAT_ERROR";
+ case VG_IMAGE_IN_USE_ERROR:
+ return "VG_IMAGE_IN_USE_ERROR";
+ case VG_NO_CONTEXT_ERROR:
+ return "VG_NO_CONTEXT_ERROR";
+ default:
+ return "UNKNOWN_ERROR";
+ }
+}
+
+#if ASSERT_DISABLED
+#define ASSERT_VG_NO_ERROR() ((void)0)
+#else
+#define ASSERT_VG_NO_ERROR() do { \
+ VGErrorCode vgErrorCode = vgGetError(); \
+ ASSERT_WITH_MESSAGE(vgErrorCode == VG_NO_ERROR, "Found %s", toVGErrorConstant(vgErrorCode)); \
+} while (0)
+#endif
+
+
+namespace WebCore {
+
+class FloatRect;
+class TransformationMatrix;
+
+class VGMatrix {
+public:
+ VGMatrix(const VGfloat data[9]);
+ VGMatrix(const TransformationMatrix&);
+ const VGfloat* toVGfloat() const { return m_data; }
+ operator TransformationMatrix() const;
+private:
+ VGfloat m_data[9];
+};
+
+class VGRect {
+public:
+ VGRect(const VGfloat data[4]);
+ VGRect(const FloatRect&);
+ const VGfloat* toVGfloat() const { return m_data; }
+ operator FloatRect() const;
+private:
+ VGfloat m_data[4];
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp
index 82fb709..83df0f3 100644
--- a/WebCore/platform/graphics/qt/FontCacheQt.cpp
+++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp
@@ -56,7 +56,7 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
{
- const AtomicString fallbackFamily = QFont(fontDescription.family().family()).lastResortFont();
+ const AtomicString fallbackFamily = QFont(fontDescription.family().family()).lastResortFamily();
return new FontPlatformData(fontDescription, fallbackFamily);
}
diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h
index 4a3f8bc..9355142 100644
--- a/WebCore/platform/graphics/qt/FontPlatformData.h
+++ b/WebCore/platform/graphics/qt/FontPlatformData.h
@@ -31,7 +31,7 @@
namespace WebCore {
class String;
-class FontPlatformDataPrivate {
+class FontPlatformDataPrivate : public Noncopyable {
public:
FontPlatformDataPrivate()
: refCount(1)
diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
index 2cc2fc6..0a1075f 100644
--- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
+++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
@@ -49,17 +49,6 @@ FontPlatformData::FontPlatformData(const FontPlatformData &other) : m_data(other
FontPlatformData::FontPlatformData(const FontDescription& description, const AtomicString& familyName, int wordSpacing, int letterSpacing)
: m_data(new FontPlatformDataPrivate())
{
- QString familyNames(familyName);
- if (!familyName.isEmpty())
- familyNames += QLatin1Char(',');
-
- const FontFamily* family = &description.family();
- while (family) {
- familyNames += family->family();
- family = family->next();
- if (family)
- familyNames += QLatin1Char(',');
- }
QFont& font = m_data->font;
font.setFamily(familyName);
font.setPixelSize(qRound(description.computedSize()));
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index 1e44626..0196ab2 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -44,24 +44,11 @@
namespace WebCore {
-static const QString qstring(const TextRun& run)
+static const QString fromRawDataWithoutRef(const String& string)
{
- // We don't detach
- return QString::fromRawData(reinterpret_cast<const QChar*>(run.characters()), run.length());
-}
-
-static const QString fixSpacing(const QString &string)
-{
- //Only detach if we're actually changing something
- QString possiblyDetached = string;
- for (int i = 0; i < string.length(); ++i) {
- const QChar c = string.at(i);
- if (c.unicode() != 0x20 && Font::treatAsSpace(c.unicode()))
- possiblyDetached[i] = 0x20; // detach
- else if (c.unicode() != 0x200c && Font::treatAsZeroWidthSpace(c.unicode()))
- possiblyDetached[i] = 0x200c; // detach
- }
- return possiblyDetached;
+ // We don't detach. This assumes the WebCore string data will stay valid for the
+ // lifetime of the QString we pass back, since we don't ref the WebCore string.
+ return QString::fromRawData(reinterpret_cast<const QChar*>(string.characters()), string.length());
}
static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
@@ -110,7 +97,8 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float
p->setPen(QPen(QColor(ctx->strokeColor()), ctx->strokeThickness()));
}
- const QString string = fixSpacing(qstring(run));
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
// text shadow
IntSize shadowSize;
@@ -185,7 +173,10 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon
{
if (!run.length())
return 0;
- const QString string = fixSpacing(qstring(run));
+
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
int w = int(line.naturalTextWidth());
@@ -198,7 +189,9 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon
int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool) const
{
- const QString string = fixSpacing(qstring(run));
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
return line.xToCursor(position);
@@ -206,7 +199,9 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const
{
- const QString string = fixSpacing(qstring(run));
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index a095476..b78a6e8 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -166,7 +166,7 @@ static inline Qt::FillRule toQtFillRule(WindRule rule)
return Qt::OddEvenFill;
}
-struct TransparencyLayer {
+struct TransparencyLayer : FastAllocBase {
TransparencyLayer(const QPainter* p, const QRect &rect)
: pixmap(rect.width(), rect.height())
{
@@ -198,7 +198,7 @@ private:
TransparencyLayer & operator=(const TransparencyLayer &) { return *this; }
};
-class GraphicsContextPlatformPrivate {
+class GraphicsContextPlatformPrivate : public Noncopyable {
public:
GraphicsContextPlatformPrivate(QPainter* painter);
~GraphicsContextPlatformPrivate();
@@ -618,14 +618,14 @@ QPen GraphicsContext::pen()
return p->pen();
}
-static void inline drawFilledShadowPath(GraphicsContext* context, QPainter* p, const QPainterPath *path)
+static void inline drawFilledShadowPath(GraphicsContext* context, QPainter* p, const QPainterPath& path)
{
IntSize shadowSize;
int shadowBlur;
Color shadowColor;
if (context->getShadow(shadowSize, shadowBlur, shadowColor)) {
p->translate(shadowSize.width(), shadowSize.height());
- p->fillPath(*path, QBrush(shadowColor));
+ p->fillPath(path, QBrush(shadowColor));
p->translate(-shadowSize.width(), -shadowSize.height());
}
}
@@ -640,7 +640,7 @@ void GraphicsContext::fillPath()
path.setFillRule(toQtFillRule(fillRule()));
if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) {
- drawFilledShadowPath(this, p, &path);
+ drawFilledShadowPath(this, p, path);
if (m_common->state.fillPattern) {
TransformationMatrix affine;
p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine)));
@@ -751,7 +751,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight);
QPainter* p = m_data->p();
drawFilledShadowPath(this, p, path.platformPath());
- p->fillPath(*path.platformPath(), QColor(color));
+ p->fillPath(path.platformPath(), QColor(color));
}
void GraphicsContext::beginPath()
@@ -762,7 +762,7 @@ void GraphicsContext::beginPath()
void GraphicsContext::addPath(const Path& path)
{
QPainterPath newPath = m_data->currentPath;
- newPath.addPath(*(path.platformPath()));
+ newPath.addPath(path.platformPath());
m_data->currentPath = newPath;
}
@@ -795,17 +795,21 @@ void GraphicsContext::clipPath(WindRule clipRule)
p->setClipPath(newPath);
}
+void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
/**
* Focus ring handling is not handled here. Qt style in
* RenderTheme handles drawing focus on widgets which
* need it.
*/
-void GraphicsContext::drawFocusRing(const Color& color)
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
{
if (paintingDisabled())
return;
- const Vector<IntRect>& rects = focusRingRects();
unsigned rectCount = rects.size();
if (!rects.size())
@@ -1031,7 +1035,7 @@ void GraphicsContext::clip(const Path& path)
if (paintingDisabled())
return;
- m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip);
+ m_data->p()->setClipPath(path.platformPath(), Qt::IntersectClip);
}
void GraphicsContext::canvasClip(const Path& path)
@@ -1045,7 +1049,7 @@ void GraphicsContext::clipOut(const Path& path)
return;
QPainter* p = m_data->p();
- QPainterPath clippedOut = *path.platformPath();
+ QPainterPath clippedOut = path.platformPath();
QPainterPath newClip;
newClip.setFillRule(Qt::OddEvenFill);
if (p->hasClipping()) {
@@ -1054,7 +1058,7 @@ void GraphicsContext::clipOut(const Path& path)
p->setClipPath(newClip, Qt::IntersectClip);
} else {
newClip.addRect(p->window());
- newClip.addPath(clippedOut & newClip);
+ newClip.addPath(clippedOut.intersected(newClip));
p->setClipPath(newClip);
}
}
@@ -1293,7 +1297,7 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
memset(bmpInfo.bmBits, 0, bufferSize);
}
-#if !PLATFORM(WINCE)
+#if !OS(WINCE)
// Make sure we can do world transforms.
SetGraphicsMode(bitmapDC, GM_ADVANCED);
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
new file mode 100644
index 0000000..5712eee
--- /dev/null
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
@@ -0,0 +1,1118 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 "GraphicsLayerQt.h"
+
+#include "CurrentTime.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "RefCounted.h"
+#include "TranslateTransformOperation.h"
+#include "UnitBezier.h"
+#include <QtCore/qabstractanimation.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qset.h>
+#include <QtCore/qtimer.h>
+#include <QtGui/qbitmap.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qgraphicseffect.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qstyleoption.h>
+
+namespace WebCore {
+
+class GraphicsLayerQtImpl : public QGraphicsObject {
+ Q_OBJECT
+
+public:
+ // this set of flags help us defer which properties of the layer have been
+ // modified by the compositor, so we can know what to look for in the next flush
+ enum ChangeMask {
+ NoChanges = 0,
+ ChildrenChange = (1L << 1),
+ MaskLayerChange = (1L << 2),
+ PositionChange = (1L << 3),
+ AnchorPointChange = (1L << 4),
+ SizeChange = (1L << 5),
+ TransformChange = (1L << 6),
+ ContentChange = (1L << 7),
+ GeometryOrientationChange = (1L << 8),
+ ContentsOrientationChange = (1L << 9),
+ OpacityChange = (1L << 10),
+ ContentsRectChange = (1L << 11),
+ Preserves3DChange = (1L << 12),
+ MasksToBoundsChange = (1L << 13),
+ DrawsContentChange = (1L << 14),
+ ContentsOpaqueChange = (1L << 15),
+ BackfaceVisibilityChange = (1L << 16),
+ ChildrenTransformChange = (1L << 17),
+ DisplayChange = (1L << 18),
+ BackgroundColorChange = (1L << 19),
+ ParentChange = (1L << 20),
+ DistributesOpacityChange = (1L << 21)
+ };
+
+ // the compositor lets us special-case images and colors, so we try to do so
+ enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType};
+
+ GraphicsLayerQtImpl(GraphicsLayerQt* newLayer);
+ virtual ~GraphicsLayerQtImpl();
+
+ // reimps from QGraphicsItem
+ virtual QPainterPath opaqueArea() const;
+ virtual QRectF boundingRect() const;
+ virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
+
+ // we manage transforms ourselves because transform-origin acts differently in webkit and in Qt
+ void setBaseTransform(const QTransform&);
+ void drawContents(QPainter*, const QRectF&, bool mask = false);
+
+ // let the compositor-API tell us which properties were changed
+ void notifyChange(ChangeMask);
+
+ // called when the compositor is ready for us to show the changes on screen
+ // this is called indirectly from ChromeClientQt::setNeedsOneShotDrawingSynchronization
+ // (meaning the sync would happen together with the next draw)
+ // or ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP)
+ void flushChanges(bool recursive = true);
+
+public slots:
+ // we need to notify the client (aka the layer compositor) when the animation actually starts
+ void notifyAnimationStarted();
+
+public:
+ GraphicsLayerQt* m_layer;
+
+ QTransform m_baseTransfom;
+ bool m_transformAnimationRunning;
+ bool m_opacityAnimationRunning;
+
+ struct ContentData {
+ QPixmap pixmap;
+ QRegion regionToUpdate;
+ bool updateAll;
+ QColor contentsBackgroundColor;
+ QColor backgroundColor;
+ StaticContentType contentType;
+ float opacity;
+ ContentData()
+ : updateAll(false)
+ , contentType(HTMLContentType)
+ , opacity(1.f)
+ {
+ }
+
+ };
+
+ ContentData m_pendingContent;
+ ContentData m_currentContent;
+
+ int m_changeMask;
+
+ QSizeF m_size;
+ QList<QWeakPointer<QAbstractAnimation> > m_animations;
+ QTimer m_suspendTimer;
+
+ struct State {
+ GraphicsLayer* maskLayer;
+ FloatPoint pos;
+ FloatPoint3D anchorPoint;
+ FloatSize size;
+ TransformationMatrix transform;
+ TransformationMatrix childrenTransform;
+ Color backgroundColor;
+ Color currentColor;
+ GraphicsLayer::CompositingCoordinatesOrientation geoOrientation;
+ GraphicsLayer::CompositingCoordinatesOrientation contentsOrientation;
+ float opacity;
+ QRect contentsRect;
+
+ bool preserves3D: 1;
+ bool masksToBounds: 1;
+ bool drawsContent: 1;
+ bool contentsOpaque: 1;
+ bool backfaceVisibility: 1;
+ bool distributeOpacity: 1;
+ bool align: 2;
+ State(): maskLayer(0), opacity(1), preserves3D(false), masksToBounds(false),
+ drawsContent(false), contentsOpaque(false), backfaceVisibility(false),
+ distributeOpacity(false)
+ {
+ }
+ } m_state;
+};
+
+GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
+ : QGraphicsObject(0)
+ , m_layer(newLayer)
+ , m_transformAnimationRunning(false)
+ , m_changeMask(NoChanges)
+{
+ // better to calculate the exposed rect in QGraphicsView than over-render in WebCore
+ // FIXME: test different approaches
+ setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
+
+ // we use graphics-view for compositing, not for interactivity
+ setAcceptedMouseButtons(Qt::NoButton);
+ setEnabled(false);
+
+ // we'll set the cache when we know what's going on
+ setCacheMode(NoCache);
+}
+
+GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
+{
+ // the compositor manages item lifecycle - we don't want the graphics-view
+ // system to automatically delete our items
+
+ const QList<QGraphicsItem*> children = childItems();
+ for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it) {
+ if (QGraphicsItem* item = *it) {
+ if (scene())
+ scene()->removeItem(item);
+ item->setParentItem(0);
+ }
+ }
+
+ // we do, however, own the animations...
+ for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_animations.begin(); it != m_animations.end(); ++it)
+ if (QAbstractAnimation* anim = it->data())
+ delete anim;
+}
+
+void GraphicsLayerQtImpl::setBaseTransform(const QTransform& transform)
+{
+ if (!m_layer)
+ return;
+ // webkit has relative-to-size originPoint, graphics-view has a pixel originPoint
+ // here we convert
+ QPointF originTranslate(
+ m_layer->anchorPoint().x() * m_layer->size().width(), m_layer->anchorPoint().y() * m_layer->size().height());
+
+ resetTransform();
+
+ // we have to manage this ourselves because QGraphicsView's transformOrigin is incomplete
+ translate(originTranslate.x(), originTranslate.y());
+ setTransform(transform, true);
+ translate(-originTranslate.x(), -originTranslate.y());
+ m_baseTransfom = transform;
+}
+
+QPainterPath GraphicsLayerQtImpl::opaqueArea() const
+{
+ QPainterPath painterPath;
+ // we try out best to return the opaque area, maybe it will help graphics-view render less items
+ if (m_currentContent.backgroundColor.isValid() && m_currentContent.backgroundColor.alpha() == 0xff)
+ painterPath.addRect(boundingRect());
+ else {
+ if (m_state.contentsOpaque
+ || (m_currentContent.contentType == ColorContentType && m_currentContent.contentsBackgroundColor.alpha() == 0xff)
+ || (m_currentContent.contentType == PixmapContentType && !m_currentContent.pixmap.hasAlpha())) {
+
+ painterPath.addRect(m_state.contentsRect);
+ }
+ }
+ return painterPath;
+}
+
+QRectF GraphicsLayerQtImpl::boundingRect() const
+{
+ return QRectF(QPointF(0, 0), QSizeF(m_size));
+}
+
+void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+{
+ if (m_state.maskLayer && m_state.maskLayer->platformLayer()) {
+ // FIXME: see if this is better done somewhere else
+ GraphicsLayerQtImpl* otherMask = static_cast<GraphicsLayerQtImpl*>(m_state.maskLayer->platformLayer());
+ otherMask->flushChanges(true);
+
+ // CSS3 mask and QGraphicsOpacityEffect are the same thing! we just need to convert...
+ // The conversion is as fast as we can make it - we render the layer once and send it to the QGraphicsOpacityEffect
+ if (!graphicsEffect()) {
+ QPixmap mask(QSize(m_state.maskLayer->size().width(), m_state.maskLayer->size().height()));
+ mask.fill(Qt::transparent);
+ {
+ QPainter p(&mask);
+ p.setRenderHints(painter->renderHints(), true);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ static_cast<GraphicsLayerQtImpl*>(m_state.maskLayer->platformLayer())->drawContents(&p, option->exposedRect, true);
+ }
+ QGraphicsOpacityEffect* opacityEffect = new QGraphicsOpacityEffect(this);
+ opacityEffect->setOpacity(1);
+ opacityEffect->setOpacityMask(QBrush(mask));
+ setGraphicsEffect(opacityEffect);
+ }
+ }
+ drawContents(painter, option->exposedRect);
+}
+
+void GraphicsLayerQtImpl::drawContents(QPainter* painter, const QRectF& r, bool mask)
+{
+ QRect rect = r.toAlignedRect();
+
+ if (m_currentContent.contentType != HTMLContentType && !m_state.contentsRect.isEmpty())
+ rect = rect.intersected(m_state.contentsRect);
+
+ if (m_currentContent.backgroundColor.isValid())
+ painter->fillRect(r, QColor(m_currentContent.backgroundColor));
+
+ if (!rect.isEmpty()) {
+ switch (m_currentContent.contentType) {
+ case PixmapContentType:
+ // we have to scale the image to the contentsRect
+ // FIXME: a better way would probably be drawPixmap with a src/target rect
+ painter->drawPixmap(rect.topLeft(), m_currentContent.pixmap.scaled(m_state.contentsRect.size()), r);
+ break;
+ case ColorContentType:
+ painter->fillRect(rect, m_currentContent.contentsBackgroundColor);
+ break;
+ default:
+ if (m_state.drawsContent) {
+ // this is the "expensive" bit. we try to minimize calls to this
+ // neck of the woods by proper caching
+ GraphicsContext gc(painter);
+ m_layer->paintGraphicsLayerContents(gc, rect);
+ }
+ break;
+ }
+ }
+}
+
+void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
+{
+ if (!this)
+ return;
+
+ m_changeMask |= changeMask;
+
+ if (m_layer->client())
+ m_layer->client()->notifySyncRequired(m_layer);
+}
+
+void GraphicsLayerQtImpl::flushChanges(bool recursive)
+{
+ // this is the bulk of the work. understanding what the compositor is trying to achieve,
+ // what graphics-view can do, and trying to find a sane common-grounds
+ if (!m_layer || m_changeMask == NoChanges)
+ goto afterLayerChanges;
+
+ if (m_currentContent.contentType == HTMLContentType && (m_changeMask & ParentChange)) {
+ // the WebCore compositor manages item ownership. We have to make sure
+ // graphics-view doesn't try to snatch that ownership...
+ if (!m_layer->parent() && !parentItem())
+ setParentItem(0);
+ else if (m_layer && m_layer->parent() && m_layer->parent()->nativeLayer() != parentItem())
+ setParentItem(m_layer->parent()->nativeLayer());
+ }
+
+ if (m_changeMask & ChildrenChange) {
+ // we basically do an XOR operation on the list of current children
+ // and the list of wanted children, and remove/add
+ QSet<QGraphicsItem*> newChildren;
+ const Vector<GraphicsLayer*> newChildrenVector = (m_layer->children());
+ newChildren.reserve(newChildrenVector.size());
+
+ for (size_t i = 0; i < newChildrenVector.size(); ++i)
+ newChildren.insert(newChildrenVector[i]->platformLayer());
+
+ const QSet<QGraphicsItem*> currentChildren = childItems().toSet();
+ const QSet<QGraphicsItem*> childrenToAdd = newChildren - currentChildren;
+ const QSet<QGraphicsItem*> childrenToRemove = currentChildren - newChildren;
+ for (QSet<QGraphicsItem*>::const_iterator it = childrenToAdd.begin(); it != childrenToAdd.end(); ++it) {
+ if (QGraphicsItem* w = *it)
+ w->setParentItem(this);
+ }
+ for (QSet<QGraphicsItem*>::const_iterator it = childrenToRemove.begin(); it != childrenToRemove.end(); ++it) {
+ if (QGraphicsItem* w = *it)
+ w->setParentItem(0);
+ }
+
+ // children are ordered by z-value, let graphics-view know.
+ for (size_t i = 0; i < newChildrenVector.size(); ++i)
+ if (newChildrenVector[i]->platformLayer())
+ newChildrenVector[i]->platformLayer()->setZValue(i);
+ }
+
+ if (m_changeMask & MaskLayerChange) {
+ // we can't paint here, because we don't know if the mask layer
+ // itself is ready... we'll have to wait till this layer tries to paint
+ setGraphicsEffect(0);
+ if (m_layer->maskLayer())
+ setFlag(ItemClipsChildrenToShape, true);
+ else
+ setFlag(ItemClipsChildrenToShape, m_layer->masksToBounds());
+ update();
+ }
+
+ if ((m_changeMask & PositionChange) && (m_layer->position() != m_state.pos))
+ setPos(m_layer->position().x(), m_layer->position().y());
+
+ if (m_changeMask & SizeChange) {
+ if (m_layer->size() != m_state.size) {
+ prepareGeometryChange();
+ m_size = QSizeF(m_layer->size().width(), m_layer->size().height());
+ }
+ }
+
+ if (m_changeMask & (TransformChange | AnchorPointChange | SizeChange)) {
+ // since we convert a percentage-based origin-point to a pixel-based one,
+ // the anchor-point, transform and size from WebCore all affect the one
+ // that we give Qt
+ if (m_state.transform != m_layer->transform() || m_state.anchorPoint != m_layer->anchorPoint() || m_state.size != m_layer->size())
+ setBaseTransform(QTransform(m_layer->transform()));
+ }
+
+ if (m_changeMask & (ContentChange | DrawsContentChange)) {
+ switch (m_pendingContent.contentType) {
+ case PixmapContentType:
+ // we need cache even for images, because they need to be resized
+ // to the contents rect. maybe this can be optimized though
+ setCacheMode(m_transformAnimationRunning ? ItemCoordinateCache : DeviceCoordinateCache);
+ update();
+ setFlag(ItemHasNoContents, false);
+ break;
+
+ case ColorContentType:
+ // no point in caching a solid-color rectangle
+ setCacheMode(QGraphicsItem::NoCache);
+ if (m_pendingContent.contentType != m_currentContent.contentType || m_pendingContent.contentsBackgroundColor != m_currentContent.contentsBackgroundColor)
+ update();
+ m_state.drawsContent = false;
+ setFlag(ItemHasNoContents, false);
+ break;
+
+ case HTMLContentType:
+ if (m_pendingContent.contentType != m_currentContent.contentType)
+ update();
+ if (!m_state.drawsContent && m_layer->drawsContent())
+ update();
+ if (m_layer->drawsContent())
+ setCacheMode(m_transformAnimationRunning ? ItemCoordinateCache : DeviceCoordinateCache);
+ else
+ setCacheMode(NoCache);
+
+ setFlag(ItemHasNoContents, !m_layer->drawsContent());
+ break;
+ }
+ }
+
+ if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity())
+ setOpacity(m_layer->opacity());
+
+ if (m_changeMask & ContentsRectChange) {
+ const QRect rect(m_layer->contentsRect());
+ if (m_state.contentsRect != rect) {
+ m_state.contentsRect = rect;
+ update();
+ }
+ }
+
+ if ((m_changeMask & MasksToBoundsChange)
+ && m_state.masksToBounds != m_layer->masksToBounds()) {
+
+ setFlag(QGraphicsItem::ItemClipsToShape, m_layer->masksToBounds());
+ setFlag(QGraphicsItem::ItemClipsChildrenToShape, m_layer->masksToBounds());
+ }
+
+ if ((m_changeMask & ContentsOpaqueChange) && m_state.contentsOpaque != m_layer->contentsOpaque())
+ prepareGeometryChange();
+
+ if (m_changeMask & DisplayChange)
+ update(m_pendingContent.regionToUpdate.boundingRect());
+
+ if ((m_changeMask & BackgroundColorChange) && (m_pendingContent.backgroundColor != m_currentContent.backgroundColor))
+ update();
+
+ // FIXME: the following flags are currently not handled, as they don't have a clear test or are in low priority
+ // GeometryOrientationChange, ContentsOrientationChange, BackfaceVisibilityChange, ChildrenTransformChange
+
+ m_state.maskLayer = m_layer->maskLayer();
+ m_state.pos = m_layer->position();
+ m_state.anchorPoint = m_layer->anchorPoint();
+ m_state.size = m_layer->size();
+ m_state.transform = m_layer->transform();
+ m_state.geoOrientation = m_layer->geometryOrientation();
+ m_state.contentsOrientation =m_layer->contentsOrientation();
+ m_state.opacity = m_layer->opacity();
+ m_state.contentsRect = m_layer->contentsRect();
+ m_state.preserves3D = m_layer->preserves3D();
+ m_state.masksToBounds = m_layer->masksToBounds();
+ m_state.drawsContent = m_layer->drawsContent();
+ m_state.contentsOpaque = m_layer->contentsOpaque();
+ m_state.backfaceVisibility = m_layer->backfaceVisibility();
+ m_currentContent.pixmap = m_pendingContent.pixmap;
+ m_currentContent.contentType = m_pendingContent.contentType;
+ m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
+ m_currentContent.regionToUpdate |= m_pendingContent.regionToUpdate;
+ m_currentContent.contentsBackgroundColor = m_pendingContent.contentsBackgroundColor;
+ m_pendingContent.regionToUpdate = QRegion();
+ m_changeMask = NoChanges;
+
+
+afterLayerChanges:
+ if (!recursive)
+ return;
+
+ const QList<QGraphicsItem*> children = childItems();
+
+ for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it) {
+ if (QGraphicsItem* item = *it)
+ if (GraphicsLayerQtImpl* layer = qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject()))
+ layer->flushChanges(true);
+ }
+}
+
+void GraphicsLayerQtImpl::notifyAnimationStarted()
+{
+ // WebCore notifies javascript when the animation starts
+ // here we're letting it know
+ m_layer->client()->notifyAnimationStarted(m_layer, WTF::currentTime());
+}
+
+GraphicsLayerQt::GraphicsLayerQt(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_impl(PassOwnPtr<GraphicsLayerQtImpl>(new GraphicsLayerQtImpl(this)))
+{
+}
+
+GraphicsLayerQt::~GraphicsLayerQt()
+{
+}
+
+// this is the hook for WebCore compositor to know that Qt implements compositing with GraphicsLayerQt
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerQt(client);
+}
+
+// reimp from GraphicsLayer.h: Qt is top-down
+GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation()
+{
+ return CompositingCoordinatesTopDown;
+}
+
+// reimp from GraphicsLayer.h: we'll need to update the whole display, and we can't count on the current size because it might change
+void GraphicsLayerQt::setNeedsDisplay()
+{
+ m_impl->m_pendingContent.regionToUpdate = QRegion(QRect(QPoint(0, 0), QSize(size().width(), size().height())));
+ m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& r)
+{
+ m_impl->m_pendingContent.regionToUpdate|= QRectF(r).toAlignedRect();
+ m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setName(const String& name)
+{
+ m_impl->setObjectName(name);
+ GraphicsLayer::setName(name);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setParent(GraphicsLayer* layer)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
+ GraphicsLayer::setParent(layer);
+}
+
+// reimp from GraphicsLayer.h
+bool GraphicsLayerQt::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ return GraphicsLayer::setChildren(children);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::addChild(GraphicsLayer* layer)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ GraphicsLayer::addChild(layer);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::addChildAtIndex(GraphicsLayer* layer, int index)
+{
+ GraphicsLayer::addChildAtIndex(layer, index);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildAbove(layer, sibling);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+
+ GraphicsLayer::addChildBelow(layer, sibling);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+// reimp from GraphicsLayer.h
+bool GraphicsLayerQt::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ return true;
+ }
+
+ return false;
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::removeFromParent()
+{
+ if (parent())
+ m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
+ GraphicsLayer::removeFromParent();
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setMaskLayer(GraphicsLayer* layer)
+{
+ GraphicsLayer::setMaskLayer(layer);
+ m_impl->notifyChange(GraphicsLayerQtImpl::MaskLayerChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setPosition(const FloatPoint& p)
+{
+ if (position() != p)
+ m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange);
+ GraphicsLayer::setPosition(p);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& p)
+{
+ if (anchorPoint() != p)
+ m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange);
+ GraphicsLayer::setAnchorPoint(p);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setSize(const FloatSize& size)
+{
+ if (this->size() != size)
+ m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange);
+ GraphicsLayer::setSize(size);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setTransform(const TransformationMatrix& t)
+{
+ if (!m_impl->m_transformAnimationRunning && transform() != t)
+ m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange);
+ GraphicsLayer::setTransform(t);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& t)
+{
+ GraphicsLayer::setChildrenTransform(t);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenTransformChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setPreserves3D(bool b)
+{
+ if (b != preserves3D());
+ m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange);
+ GraphicsLayer::setPreserves3D(b);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setMasksToBounds(bool b)
+{
+ GraphicsLayer::setMasksToBounds(b);
+ m_impl->notifyChange(GraphicsLayerQtImpl::MasksToBoundsChange);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setDrawsContent(bool b)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::DrawsContentChange);
+ GraphicsLayer::setDrawsContent(b);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setBackgroundColor(const Color& c)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
+ m_impl->m_pendingContent.backgroundColor = c;
+ GraphicsLayer::setBackgroundColor(c);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::clearBackgroundColor()
+{
+ m_impl->m_pendingContent.backgroundColor = QColor();
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
+ GraphicsLayer::clearBackgroundColor();
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setContentsOpaque(bool b)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOpaqueChange);
+ GraphicsLayer::setContentsOpaque(b);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setBackfaceVisibility(bool b)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackfaceVisibilityChange);
+ GraphicsLayer::setBackfaceVisibility(b);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setOpacity(float o)
+{
+ if (!m_impl->m_opacityAnimationRunning && opacity() != o)
+ m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
+ GraphicsLayer::setOpacity(o);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setContentsRect(const IntRect& r)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsRectChange);
+ GraphicsLayer::setContentsRect(r);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setContentsToImage(Image* image)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::HTMLContentType;
+ GraphicsLayer::setContentsToImage(image);
+ if (image) {
+ QPixmap* pxm = image->nativeImageForCurrentFrame();
+ if (pxm) {
+ m_impl->m_pendingContent.pixmap = *pxm;
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::PixmapContentType;
+ return;
+ }
+ }
+ m_impl->m_pendingContent.pixmap = QPixmap();
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setContentsBackgroundColor(const Color& color)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::ColorContentType;
+ m_impl->m_pendingContent.contentsBackgroundColor = QColor(color);
+ GraphicsLayer::setContentsBackgroundColor(color);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setGeometryOrientation(CompositingCoordinatesOrientation orientation)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::GeometryOrientationChange);
+ GraphicsLayer::setGeometryOrientation(orientation);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::setContentsOrientation(CompositingCoordinatesOrientation orientation)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOrientationChange);
+ GraphicsLayer::setContentsOrientation(orientation);
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::distributeOpacity(float o)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
+ m_impl->m_state.distributeOpacity = true;
+}
+
+// reimp from GraphicsLayer.h
+float GraphicsLayerQt::accumulatedOpacity() const
+{
+ return m_impl->effectiveOpacity();
+}
+
+// reimp from GraphicsLayer.h
+void GraphicsLayerQt::syncCompositingState()
+{
+ m_impl->flushChanges();
+ GraphicsLayer::syncCompositingState();
+}
+
+// reimp from GraphicsLayer.h
+NativeLayer GraphicsLayerQt::nativeLayer() const
+{
+ return m_impl.get();
+}
+
+// reimp from GraphicsLayer.h
+PlatformLayer* GraphicsLayerQt::platformLayer() const
+{
+ return m_impl.get();
+}
+
+// now we start dealing with WebCore animations translated to Qt animations
+
+template <typename T>
+struct KeyframeValueQt {
+ TimingFunction timingFunction;
+ T value;
+};
+
+// we copy this from the AnimationBase.cpp
+static inline double solveEpsilon(double duration)
+{
+ return 1.0 / (200.0 * duration);
+}
+
+static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, qreal p2y, double t, double duration)
+{
+ UnitBezier bezier(p1x, p1y, p2x, p2y);
+ return bezier.solve(t, solveEpsilon(duration));
+}
+
+// we want the timing function to be as close as possible to what the web-developer intended, so we're using the same function used by WebCore when compositing is disabled
+// Using easing-curves would probably work for some of the cases, but wouldn't really buy us anything as we'd have to convert the bezier function back to an easing curve
+static inline qreal applyTimingFunction(const TimingFunction& timingFunction, qreal progress, int duration)
+{
+ if (timingFunction.type() == LinearTimingFunction)
+ return progress;
+ if (timingFunction.type() == CubicBezierTimingFunction) {
+ return solveCubicBezierFunction(timingFunction.x1(),
+ timingFunction.y1(),
+ timingFunction.x2(),
+ timingFunction.y2(),
+ double(progress), double(duration) / 1000);
+ }
+ return progress;
+}
+
+// helper functions to safely get a value out of WebCore's AnimationValue*
+static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, TransformOperations& transformOperations)
+{
+ transformOperations = TransformOperations();
+ if (!animationValue)
+ return;
+
+ const TransformOperations* ops = static_cast<const TransformAnimationValue*>(animationValue)->value();
+
+ if (ops)
+ transformOperations = *ops;
+}
+
+static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, qreal& realValue)
+{
+ realValue = animationValue ? static_cast<const FloatAnimationValue*>(animationValue)->value() : 0;
+}
+
+// we put a bit of the functionality in a base class to allow casting and to save some code size
+class AnimationQtBase : public QAbstractAnimation {
+public:
+ AnimationQtBase(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : QAbstractAnimation(0)
+ , m_layer(layer)
+ , m_boxSize(boxSize)
+ , m_duration(anim->duration() * 1000)
+ , m_isAlternate(anim->direction() == Animation::AnimationDirectionAlternate)
+ , m_webkitPropertyID(values.property())
+ , m_keyframesName(name)
+ {
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ QAbstractAnimation::updateState(newState, oldState);
+
+ // for some reason I have do this asynchronously - or the animation won't work
+ if (newState == Running && oldState == Stopped)
+ QTimer::singleShot(0, m_layer.data(), SLOT(notifyAnimationStarted()));
+ }
+
+ virtual int duration() const { return m_duration; }
+
+ QWeakPointer<GraphicsLayerQtImpl> m_layer;
+ IntSize m_boxSize;
+ int m_duration;
+ bool m_isAlternate;
+ AnimatedPropertyID m_webkitPropertyID;
+ QString m_keyframesName;
+};
+
+// we'd rather have a templatized QAbstractAnimation than QPropertyAnimation / QVariantAnimation;
+// Since we know the types that we're dealing with, the QObject/QProperty/QVariant abstraction
+// buys us very little in this case, for too much overhead
+template <typename T>
+class AnimationQt : public AnimationQtBase {
+
+public:
+ AnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ :AnimationQtBase(layer, values, boxSize, anim, name)
+ {
+ // copying those WebCore structures is not trivial, we have to do it like this
+ for (size_t i = 0; i < values.size(); ++i) {
+ const AnimationValue* animationValue = values.at(i);
+ KeyframeValueQt<T> keyframeValue;
+ if (animationValue->timingFunction())
+ keyframeValue.timingFunction = *animationValue->timingFunction();
+ webkitAnimationToQtAnimationValue(animationValue, keyframeValue.value);
+ m_keyframeValues[animationValue->keyTime()] = keyframeValue;
+ }
+ }
+
+protected:
+
+ // this is the part that differs between animated properties
+ virtual void applyFrame(const T& fromValue, const T& toValue, qreal progress) = 0;
+
+ virtual void updateCurrentTime(int currentTime)
+ {
+ if (!m_layer)
+ return;
+
+ qreal progress = qreal(currentLoopTime()) / duration();
+
+ if (m_isAlternate && currentLoop()%2)
+ progress = 1-progress;
+
+ if (m_keyframeValues.isEmpty())
+ return;
+
+ // we find the current from-to keyframes in our little map
+ typename QMap<qreal, KeyframeValueQt<T> >::iterator it = m_keyframeValues.find(progress);
+
+ // we didn't find an exact match, we try the closest match (lower bound)
+ if (it == m_keyframeValues.end())
+ it = m_keyframeValues.lowerBound(progress)-1;
+
+ // we didn't find any match - we use the first keyframe
+ if (it == m_keyframeValues.end())
+ it = m_keyframeValues.begin();
+
+ typename QMap<qreal, KeyframeValueQt<T> >::iterator it2 = it+1;
+ if (it2 == m_keyframeValues.end())
+ it2 = m_keyframeValues.begin();
+ const KeyframeValueQt<T>& fromKeyframe = it.value();
+ const KeyframeValueQt<T>& toKeyframe = it2.value();
+
+ const TimingFunction& timingFunc = fromKeyframe.timingFunction;
+ const T& fromValue = fromKeyframe.value;
+ const T& toValue = toKeyframe.value;
+
+ // now we have a source keyframe, origin keyframe and a timing function
+ // we can now process the progress and apply the frame
+ qreal normalizedProgress = (it.key() == it2.key()) ? 0 : (progress - it.key()) / (it2.key() - it.key());
+ normalizedProgress = applyTimingFunction(timingFunc, normalizedProgress, duration() / 1000);
+ applyFrame(fromValue, toValue, normalizedProgress);
+ }
+
+ QMap<qreal, KeyframeValueQt<T> > m_keyframeValues;
+};
+
+class TransformAnimationQt : public AnimationQt<TransformOperations> {
+public:
+ TransformAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : AnimationQt<TransformOperations>(layer, values, boxSize, anim, name)
+ {
+ }
+
+ ~TransformAnimationQt()
+ {
+ // this came up during the compositing/animation LayoutTests
+ // when the animation dies, the transform has to go back to default
+ if (m_layer)
+ m_layer.data()->setBaseTransform(QTransform(m_layer.data()->m_layer->transform()));
+ }
+
+ // the idea is that we let WebCore manage the transform-operations
+ // and Qt just manages the animation heartbeat and the bottom-line QTransform
+ // we get the performance not by using QTransform instead of TransformationMatrix, but by proper caching of
+ // items that are expensive for WebCore to render. We want the rest to be as close to WebCore's idea as possible.
+ virtual void applyFrame(const TransformOperations& sourceOperations, const TransformOperations& targetOperations, qreal progress)
+ {
+ TransformationMatrix transformMatrix;
+
+ // this looks simple but is really tricky to get right. Use caution.
+ for (size_t i = 0; i < targetOperations.size(); ++i)
+ targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize);
+
+ m_layer.data()->setBaseTransform(QTransform(transformMatrix));
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ AnimationQtBase::updateState(newState, oldState);
+ if (!m_layer)
+ return;
+ m_layer.data()->flushChanges(true);
+
+ // to increase FPS, we use a less accurate caching mechanism while animation is going on
+ // this is a UX choice that should probably be customizable
+ if (newState == QAbstractAnimation::Running) {
+ m_layer.data()->m_transformAnimationRunning = true;
+ if (m_layer.data()->cacheMode() == QGraphicsItem::DeviceCoordinateCache)
+ m_layer.data()->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ } else {
+ m_layer.data()->m_transformAnimationRunning = false;
+ if (m_layer.data()->cacheMode() == QGraphicsItem::ItemCoordinateCache)
+ m_layer.data()->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
+ }
+ }
+};
+
+class OpacityAnimationQt : public AnimationQt<qreal> {
+public:
+ OpacityAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : AnimationQt<qreal>(layer, values, boxSize, anim, name)
+ {
+ }
+
+ virtual void applyFrame(const qreal& fromValue, const qreal& toValue, qreal progress)
+ {
+ m_layer.data()->setOpacity(qMin<qreal>(qMax<qreal>(fromValue + (toValue-fromValue)*progress, 0), 1));
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ QAbstractAnimation::updateState(newState, oldState);
+ if (m_layer)
+ m_layer.data()->m_opacityAnimationRunning = (newState == QAbstractAnimation::Running);
+ }
+};
+
+bool GraphicsLayerQt::addAnimation(const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset)
+{
+ if (!anim->duration() || !anim->iterationCount())
+ return false;
+
+ QAbstractAnimation* newAnim;
+
+ switch (values.property()) {
+ case AnimatedPropertyOpacity:
+ newAnim = new OpacityAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
+ break;
+ case AnimatedPropertyWebkitTransform:
+ newAnim = new TransformAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
+ break;
+ default:
+ return false;
+ }
+
+ // we make sure WebCore::Animation and QAnimation are on the same terms
+ newAnim->setLoopCount(anim->iterationCount());
+ m_impl->m_animations.append(QWeakPointer<QAbstractAnimation>(newAnim));
+ QObject::connect(&m_impl->m_suspendTimer, SIGNAL(timeout()), newAnim, SLOT(resume()));
+ timeOffset += anim->delay();
+
+ // flush now or flicker...
+ m_impl->flushChanges(false);
+
+ if (timeOffset)
+ QTimer::singleShot(timeOffset * 1000, newAnim, SLOT(start()));
+ else
+ newAnim->start();
+
+ QObject::connect(newAnim, SIGNAL(finished()), newAnim, SLOT(deleteLater()));
+
+ return true;
+}
+
+void GraphicsLayerQt::removeAnimationsForProperty(AnimatedPropertyID id)
+{
+ for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (*it) {
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
+ if (anim && anim->m_webkitPropertyID == id) {
+ delete anim;
+ it = m_impl->m_animations.erase(it);
+ --it;
+ }
+ }
+ }
+}
+
+void GraphicsLayerQt::removeAnimationsForKeyframes(const String& name)
+{
+ for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (*it) {
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data());
+ if (anim && anim->m_keyframesName == QString(name)) {
+ (*it).data()->deleteLater();
+ it = m_impl->m_animations.erase(it);
+ --it;
+ }
+ }
+ }
+}
+
+void GraphicsLayerQt::pauseAnimation(const String& name, double timeOffset)
+{
+ for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (*it) {
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data());
+ if (anim && anim->m_keyframesName == QString(name))
+ QTimer::singleShot(timeOffset * 1000, anim, SLOT(pause()));
+ }
+ }
+}
+
+void GraphicsLayerQt::suspendAnimations(double time)
+{
+ if (m_impl->m_suspendTimer.isActive()) {
+ m_impl->m_suspendTimer.stop();
+ m_impl->m_suspendTimer.start(time * 1000);
+ } else {
+ for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ QAbstractAnimation* anim = it->data();
+ if (anim)
+ anim->pause();
+ }
+ }
+}
+
+void GraphicsLayerQt::resumeAnimations()
+{
+ if (m_impl->m_suspendTimer.isActive()) {
+ m_impl->m_suspendTimer.stop();
+ for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ QAbstractAnimation* anim = (*it).data();
+ if (anim)
+ anim->resume();
+ }
+ }
+}
+
+}
+
+#include <GraphicsLayerQt.moc>
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
new file mode 100644
index 0000000..3a53bd9
--- /dev/null
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 GraphicsLayerQt_h
+#define GraphicsLayerQt_h
+
+#include "GraphicsLayer.h"
+#include "GraphicsLayerClient.h"
+
+namespace WebCore {
+
+class GraphicsLayerQtImpl;
+
+class GraphicsLayerQt : public GraphicsLayer {
+ friend class GraphicsLayerQtImpl;
+
+public:
+ GraphicsLayerQt(GraphicsLayerClient*);
+ virtual ~GraphicsLayerQt();
+
+ // reimps from GraphicsLayer.h
+ virtual NativeLayer nativeLayer() const;
+ virtual PlatformLayer* platformLayer() const;
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+ virtual void setParent(GraphicsLayer* layer);
+ virtual void setName(const String& name);
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+ virtual void addChild(GraphicsLayer*);
+ virtual void addChildAtIndex(GraphicsLayer*, int index);
+ virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+ virtual void removeFromParent();
+ virtual void setMaskLayer(GraphicsLayer* layer);
+ virtual void setPosition(const FloatPoint& p);
+ virtual void setAnchorPoint(const FloatPoint3D& p);
+ virtual void setSize(const FloatSize& size);
+ virtual void setTransform(const TransformationMatrix& t);
+ virtual void setChildrenTransform(const TransformationMatrix& t);
+ virtual void setPreserves3D(bool b);
+ virtual void setMasksToBounds(bool b);
+ virtual void setDrawsContent(bool b);
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+ virtual void setContentsOpaque(bool b);
+ virtual void setBackfaceVisibility(bool b);
+ virtual void setOpacity(float opacity);
+ virtual void setContentsRect(const IntRect& r);
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double timeOffset);
+ virtual void removeAnimationsForProperty(AnimatedPropertyID);
+ virtual void removeAnimationsForKeyframes(const String& keyframesName);
+ virtual void pauseAnimation(const String& keyframesName, double timeOffset);
+ virtual void suspendAnimations(double time);
+ virtual void resumeAnimations();
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsBackgroundColor(const Color&);
+ virtual void setGeometryOrientation(CompositingCoordinatesOrientation orientation);
+ virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation);
+ virtual void distributeOpacity(float);
+ virtual float accumulatedOpacity() const;
+ virtual void syncCompositingState();
+
+private:
+ OwnPtr<GraphicsLayerQtImpl> m_impl;
+};
+
+}
+#endif // GraphicsLayerQt_h
diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
index 5255428..d831566 100644
--- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -114,7 +114,7 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
value = qRgba(lookUpTable[qRed(value)],
lookUpTable[qGreen(value)],
lookUpTable[qBlue(value)],
- lookUpTable[qAlpha(value)]);
+ qAlpha(value));
image.setPixel(x, y, value);
}
}
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
index b6823dd..234f78b 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -47,16 +47,12 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data)
}
ImageDecoderQt::ImageDecoderQt()
- : m_buffer(0)
- , m_reader(0)
- , m_repetitionCount(cAnimationNone)
+ : m_repetitionCount(cAnimationNone)
{
}
ImageDecoderQt::~ImageDecoderQt()
{
- delete m_reader;
- delete m_buffer;
}
void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
@@ -77,10 +73,16 @@ void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
// Attempt to load the data
QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size());
- m_buffer = new QBuffer;
+ m_buffer.set(new QBuffer);
m_buffer->setData(imageData);
m_buffer->open(QBuffer::ReadOnly);
- m_reader = new QImageReader(m_buffer, m_format);
+ m_reader.set(new QImageReader(m_buffer.get(), m_format));
+
+ // This will force the JPEG decoder to use JDCT_IFAST
+ m_reader->setQuality(49);
+
+ // QImageReader only allows retrieving the format before reading the image
+ m_format = m_reader->format();
}
bool ImageDecoderQt::isSizeAvailable()
@@ -158,7 +160,6 @@ void ImageDecoderQt::internalDecodeSize()
if (size.isEmpty())
return failRead();
- m_format = m_reader->format();
setSize(size.width(), size.height());
}
@@ -178,10 +179,8 @@ void ImageDecoderQt::internalReadImage(size_t frameIndex)
if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete)
return;
- delete m_reader;
- delete m_buffer;
- m_buffer = 0;
- m_reader = 0;
+ m_reader.clear();
+ m_buffer.clear();
}
void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
@@ -229,10 +228,8 @@ void ImageDecoderQt::forceLoadEverything()
void ImageDecoderQt::failRead()
{
setFailed();
- delete m_reader;
- delete m_buffer;
- m_reader = 0;
- m_buffer = 0;
+ m_reader.clear();
+ m_buffer.clear();
}
}
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h
index d11b938..be9a9b0 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.h
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -33,6 +33,7 @@
#include <QtCore/QList>
#include <QtCore/QHash>
#include <QtCore/QBuffer>
+#include <wtf/OwnPtr.h>
namespace WebCore {
@@ -66,8 +67,8 @@ private:
private:
QByteArray m_format;
- QBuffer* m_buffer;
- QImageReader* m_reader;
+ OwnPtr<QBuffer> m_buffer;
+ OwnPtr<QImageReader> m_reader;
mutable int m_repetitionCount;
};
diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp
index 9a82911..fea1448 100644
--- a/WebCore/platform/graphics/qt/ImageQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -213,7 +213,7 @@ void BitmapImage::checkForSolidColor()
m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0));
}
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
{
return BitmapImage::create(new QPixmap(QPixmap::fromWinHBITMAP(hBitmap)));
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
index f446755..3274db5 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -38,14 +38,16 @@
#include <QUrl>
#include <QEvent>
-#include <audiooutput.h>
-#include <mediaobject.h>
-#include <videowidget.h>
+#include <phonon/path.h>
+#include <phonon/audiooutput.h>
+#include <phonon/mediaobject.h>
+#include <phonon/videowidget.h>
using namespace Phonon;
#define LOG_MEDIAOBJECT() (LOG(Media, "%s", debugMediaObject(this, *m_mediaObject).constData()))
+#if !LOG_DISABLED
static QByteArray debugMediaObject(WebCore::MediaPlayerPrivate* mediaPlayer, const MediaObject& mediaObject)
{
QByteArray byteArray;
@@ -73,6 +75,7 @@ static QByteArray debugMediaObject(WebCore::MediaPlayerPrivate* mediaPlayer, con
return byteArray;
}
+#endif
using namespace WTF;
@@ -89,9 +92,7 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
{
// Hint to Phonon to disable overlay painting
m_videoWidget->setAttribute(Qt::WA_DontShowOnScreen);
-#if QT_VERSION < 0x040500
m_videoWidget->setAttribute(Qt::WA_QuitOnClose, false);
-#endif
createPath(m_mediaObject, m_videoWidget);
createPath(m_mediaObject, m_audioOutput);
@@ -256,11 +257,6 @@ float MediaPlayerPrivate::currentTime() const
return currentTime;
}
-void MediaPlayerPrivate::setEndTime(float)
-{
- notImplemented();
-}
-
PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
{
notImplemented();
@@ -279,12 +275,6 @@ unsigned MediaPlayerPrivate::bytesLoaded() const
return 0;
}
-bool MediaPlayerPrivate::totalBytesKnown() const
-{
- //notImplemented();
- return false;
-}
-
unsigned MediaPlayerPrivate::totalBytes() const
{
//notImplemented();
@@ -308,14 +298,6 @@ void MediaPlayerPrivate::setMuted(bool muted)
m_audioOutput->setMuted(muted);
}
-
-int MediaPlayerPrivate::dataRate() const
-{
- // This is not used at the moment
- return 0;
-}
-
-
MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
{
const QMetaObject* metaObj = this->metaObject();
@@ -502,7 +484,7 @@ void MediaPlayerPrivate::aboutToFinish()
void MediaPlayerPrivate::totalTimeChanged(qint64 totalTime)
{
- LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%d)", totalTime);
+ LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%lld)", totalTime);
LOG_MEDIAOBJECT();
}
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
index e1193b6..e7630a1 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
@@ -94,21 +94,17 @@ namespace WebCore {
float duration() const;
float currentTime() const;
void seek(float);
- void setEndTime(float);
void setRate(float);
void setVolume(float);
void setMuted(bool);
- int dataRate() const;
-
MediaPlayer::NetworkState networkState() const;
MediaPlayer::ReadyState readyState() const;
PassRefPtr<TimeRanges> buffered() const;
float maxTimeSeekable() const;
unsigned bytesLoaded() const;
- bool totalBytesKnown() const;
unsigned totalBytes() const;
void setVisible(bool);
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
index e5cecc8..4716d32 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -51,38 +51,32 @@
namespace WebCore {
Path::Path()
- : m_path(new QPainterPath())
{
}
Path::~Path()
{
- delete m_path;
}
Path::Path(const Path& other)
- : m_path(new QPainterPath(*other.platformPath()))
+ : m_path(other.m_path)
{
}
Path& Path::operator=(const Path& other)
{
- if (&other != this) {
- delete m_path;
- m_path = new QPainterPath(*other.platformPath());
- }
-
+ m_path = other.m_path;
return *this;
}
bool Path::contains(const FloatPoint& point, WindRule rule) const
{
- Qt::FillRule savedRule = m_path->fillRule();
- m_path->setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
+ Qt::FillRule savedRule = m_path.fillRule();
+ const_cast<QPainterPath*>(&m_path)->setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
- bool contains = m_path->contains(point);
+ bool contains = m_path.contains(point);
- m_path->setFillRule(savedRule);
+ const_cast<QPainterPath*>(&m_path)->setFillRule(savedRule);
return contains;
}
@@ -105,19 +99,19 @@ bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point)
stroke.setDashPattern(pen.dashPattern());
stroke.setDashOffset(pen.dashOffset());
- return (stroke.createStroke(*platformPath())).contains(point);
+ return stroke.createStroke(m_path).contains(point);
}
void Path::translate(const FloatSize& size)
{
QTransform matrix;
matrix.translate(size.width(), size.height());
- *m_path = (*m_path) * matrix;
+ m_path = m_path * matrix;
}
FloatRect Path::boundingRect() const
{
- return m_path->boundingRect();
+ return m_path.boundingRect();
}
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
@@ -138,35 +132,35 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
stroke.setDashPattern(pen.dashPattern());
stroke.setDashOffset(pen.dashOffset());
}
- return (stroke.createStroke(*platformPath())).boundingRect();
+ return stroke.createStroke(m_path).boundingRect();
}
void Path::moveTo(const FloatPoint& point)
{
- m_path->moveTo(point);
+ m_path.moveTo(point);
}
void Path::addLineTo(const FloatPoint& p)
{
- m_path->lineTo(p);
+ m_path.lineTo(p);
}
void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
{
- m_path->quadTo(cp, p);
+ m_path.quadTo(cp, p);
}
void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
{
- m_path->cubicTo(cp1, cp2, p);
+ m_path.cubicTo(cp1, cp2, p);
}
void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
{
- FloatPoint p0(m_path->currentPosition());
+ FloatPoint p0(m_path.currentPosition());
if ((p1.x() == p0.x() && p1.y() == p0.y()) || (p1.x() == p2.x() && p1.y() == p2.y()) || radius == 0.f) {
- m_path->lineTo(p1);
+ m_path.lineTo(p1);
return;
}
@@ -178,7 +172,7 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
// all points on a line logic
if (cos_phi == -1) {
- m_path->lineTo(p1);
+ m_path.lineTo(p1);
return;
}
if (cos_phi == 1) {
@@ -186,7 +180,7 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
unsigned int max_length = 65535;
double factor_max = max_length / p1p0_length;
FloatPoint ep((p0.x() + factor_max * p1p0.x()), (p0.y() + factor_max * p1p0.y()));
- m_path->lineTo(ep);
+ m_path.lineTo(ep);
return;
}
@@ -226,14 +220,14 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
if ((sa < ea) && ((ea - sa) > piDouble))
anticlockwise = true;
- m_path->lineTo(t_p1p0);
+ m_path.lineTo(t_p1p0);
addArc(p, radius, sa, ea, anticlockwise);
}
void Path::closeSubpath()
{
- m_path->closeSubpath();
+ m_path.closeSubpath();
}
#define DEGREES(t) ((t) * 180.0 / M_PI)
@@ -275,32 +269,32 @@ void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool antic
span += ea - sa;
}
- m_path->moveTo(QPointF(xc + radius * cos(sar),
+ m_path.moveTo(QPointF(xc + radius * cos(sar),
yc - radius * sin(sar)));
- m_path->arcTo(xs, ys, width, height, sa, span);
+ m_path.arcTo(xs, ys, width, height, sa, span);
}
void Path::addRect(const FloatRect& r)
{
- m_path->addRect(r.x(), r.y(), r.width(), r.height());
+ m_path.addRect(r.x(), r.y(), r.width(), r.height());
}
void Path::addEllipse(const FloatRect& r)
{
- m_path->addEllipse(r.x(), r.y(), r.width(), r.height());
+ m_path.addEllipse(r.x(), r.y(), r.width(), r.height());
}
void Path::clear()
{
- *m_path = QPainterPath();
+ m_path = QPainterPath();
}
bool Path::isEmpty() const
{
// Don't use QPainterPath::isEmpty(), as that also returns true if there's only
// one initial MoveTo element in the path.
- return !m_path->elementCount();
+ return !m_path.elementCount();
}
bool Path::hasCurrentPoint() const
@@ -311,8 +305,8 @@ bool Path::hasCurrentPoint() const
String Path::debugString() const
{
QString ret;
- for (int i = 0; i < m_path->elementCount(); ++i) {
- const QPainterPath::Element &cur = m_path->elementAt(i);
+ for (int i = 0; i < m_path.elementCount(); ++i) {
+ const QPainterPath::Element &cur = m_path.elementAt(i);
switch (cur.type) {
case QPainterPath::MoveToElement:
@@ -323,8 +317,8 @@ String Path::debugString() const
break;
case QPainterPath::CurveToElement:
{
- const QPainterPath::Element &c1 = m_path->elementAt(i + 1);
- const QPainterPath::Element &c2 = m_path->elementAt(i + 2);
+ const QPainterPath::Element &c1 = m_path.elementAt(i + 1);
+ const QPainterPath::Element &c2 = m_path.elementAt(i + 2);
Q_ASSERT(c1.type == QPainterPath::CurveToDataElement);
Q_ASSERT(c2.type == QPainterPath::CurveToDataElement);
@@ -348,8 +342,8 @@ void Path::apply(void* info, PathApplierFunction function) const
PathElement pelement;
FloatPoint points[3];
pelement.points = points;
- for (int i = 0; i < m_path->elementCount(); ++i) {
- const QPainterPath::Element& cur = m_path->elementAt(i);
+ for (int i = 0; i < m_path.elementCount(); ++i) {
+ const QPainterPath::Element& cur = m_path.elementAt(i);
switch (cur.type) {
case QPainterPath::MoveToElement:
@@ -364,8 +358,8 @@ void Path::apply(void* info, PathApplierFunction function) const
break;
case QPainterPath::CurveToElement:
{
- const QPainterPath::Element& c1 = m_path->elementAt(i + 1);
- const QPainterPath::Element& c2 = m_path->elementAt(i + 2);
+ const QPainterPath::Element& c1 = m_path.elementAt(i + 1);
+ const QPainterPath::Element& c2 = m_path.elementAt(i + 2);
Q_ASSERT(c1.type == QPainterPath::CurveToDataElement);
Q_ASSERT(c2.type == QPainterPath::CurveToDataElement);
@@ -387,12 +381,7 @@ void Path::apply(void* info, PathApplierFunction function) const
void Path::transform(const TransformationMatrix& transform)
{
- if (m_path) {
- QTransform mat = transform;
- QPainterPath temp = mat.map(*m_path);
- delete m_path;
- m_path = new QPainterPath(temp);
- }
+ m_path = QTransform(transform).map(m_path);
}
}
diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
index f1536a6..985442c 100644
--- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
@@ -86,7 +86,10 @@ inline float square(float n)
// Ideally, all of these would be fixed in the graphics layer and we would not
// have to do any checking. You can uncomment the ENSURE_VALUE_SAFETY_FOR_SKIA
// flag to check the graphics layer.
-#define ENSURE_VALUE_SAFETY_FOR_SKIA
+
+// Disabling these checks (20/01/2010), since we think we've fixed all the Skia
+// bugs. Leaving the code in for now, so we can revert easily if necessary.
+// #define ENSURE_VALUE_SAFETY_FOR_SKIA
static bool isCoordinateSkiaSafe(float coord)
{
@@ -431,7 +434,7 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect,
if (paintingDisabled())
return;
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
platformContext()->beginLayerClippedToImage(rect, imageBuffer);
#endif
}
@@ -498,12 +501,16 @@ void GraphicsContext::drawEllipse(const IntRect& elipseRect)
}
}
-void GraphicsContext::drawFocusRing(const Color& color)
+void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
{
if (paintingDisabled())
return;
- const Vector<IntRect>& rects = focusRingRects();
unsigned rectCount = rects.size();
if (!rectCount)
return;
diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
index c36f1ce..4ea3d7a 100644
--- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
@@ -66,7 +66,7 @@ ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, b
m_data.m_platformContext.setCanvas(&m_data.m_canvas);
m_context.set(new GraphicsContext(&m_data.m_platformContext));
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
m_context->platformContext()->setDrawingToImageBuffer(true);
#endif
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
index dfffa0d..92a1870 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -89,7 +89,7 @@ struct PlatformContextSkia::State {
// color to produce a new output color.
SkColor applyAlpha(SkColor) const;
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
// If non-empty, the current State is clipped to this image.
SkBitmap m_imageBufferClip;
// If m_imageBufferClip is non-empty, this is the region the image is clipped to.
@@ -143,7 +143,7 @@ PlatformContextSkia::State::State(const State& other)
, m_lineJoin(other.m_lineJoin)
, m_dash(other.m_dash)
, m_textDrawingMode(other.m_textDrawingMode)
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
, m_imageBufferClip(other.m_imageBufferClip)
, m_clip(other.m_clip)
#endif
@@ -180,7 +180,7 @@ SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
// Danger: canvas can be NULL.
PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
: m_canvas(canvas)
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
, m_drawingToImageBuffer(false)
#endif
{
@@ -197,7 +197,7 @@ void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
m_canvas = canvas;
}
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
void PlatformContextSkia::setDrawingToImageBuffer(bool value)
{
m_drawingToImageBuffer = value;
@@ -214,7 +214,7 @@ void PlatformContextSkia::save()
m_stateStack.append(*m_state);
m_state = &m_stateStack.last();
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
// The clip image only needs to be applied once. Reset the image so that we
// don't attempt to clip multiple times.
m_state->m_imageBufferClip.reset();
@@ -224,7 +224,7 @@ void PlatformContextSkia::save()
canvas()->save();
}
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rect,
const WebCore::ImageBuffer* imageBuffer)
{
@@ -234,7 +234,8 @@ void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rec
m_state->m_clip = rect;
SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
SkFloatToScalar(rect.right()), SkFloatToScalar(rect.bottom()) };
-
+
+ canvas()->clipRect(bounds);
canvas()->saveLayerAlpha(&bounds, 255,
static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
// Copy off the image as |imageBuffer| may be deleted before restore is invoked.
@@ -271,7 +272,7 @@ void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath)
void PlatformContextSkia::restore()
{
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
if (!m_state->m_imageBufferClip.empty()) {
applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
canvas()->restore();
@@ -574,7 +575,7 @@ bool PlatformContextSkia::isPrinting()
return m_canvas->getTopPlatformDevice().IsVectorial();
}
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
void PlatformContextSkia::applyClipFromImage(const WebCore::FloatRect& rect, const SkBitmap& imageBuffer)
{
// NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h
index 53590bf..e445262 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.h
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h
@@ -71,7 +71,7 @@ public:
// to the constructor.
void setCanvas(skia::PlatformCanvas*);
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
// If false we're rendering to a GraphicsContext for a web page, if false
// we're not (as is the case when rendering to a canvas object).
// If this is true the contents have not been marked up with the magic
@@ -88,7 +88,7 @@ public:
// |rect|. This layer is implicitly restored when the next restore is
// invoked.
// NOTE: |imageBuffer| may be deleted before the |restore| is invoked.
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
void beginLayerClippedToImage(const WebCore::FloatRect&,
const WebCore::ImageBuffer*);
#endif
@@ -168,7 +168,7 @@ public:
bool isPrinting();
private:
-#if defined(__linux__) || PLATFORM(WIN_OS)
+#if OS(LINUX) || OS(WINDOWS)
// Used when restoring and the state has an image clip. Only shows the pixels in
// m_canvas that are also in imageBuffer.
void applyClipFromImage(const WebCore::FloatRect&, const SkBitmap&);
@@ -191,7 +191,7 @@ private:
// Current path in global coordinates.
SkPath m_path;
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
bool m_drawingToImageBuffer;
#endif
};
diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h
index 802ad3c..9e724d5 100644
--- a/WebCore/platform/graphics/transforms/TransformationMatrix.h
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h
@@ -35,6 +35,8 @@
#include <CoreGraphics/CGAffineTransform.h>
#elif PLATFORM(CAIRO)
#include <cairo.h>
+#elif PLATFORM(OPENVG)
+#include "VGUtils.h"
#elif PLATFORM(QT)
#include <QTransform>
#elif PLATFORM(SKIA)
@@ -43,6 +45,14 @@
#include <wx/graphics.h>
#endif
+#if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)) || (PLATFORM(WX) && OS(WINDOWS))
+#if COMPILER(MINGW)
+typedef struct _XFORM XFORM;
+#else
+typedef struct tagXFORM XFORM;
+#endif
+#endif
+
namespace WebCore {
class IntRect;
@@ -299,6 +309,8 @@ public:
operator CGAffineTransform() const;
#elif PLATFORM(CAIRO)
operator cairo_matrix_t() const;
+#elif PLATFORM(OPENVG)
+ operator VGMatrix() const;
#elif PLATFORM(QT)
operator QTransform() const;
#elif PLATFORM(SKIA)
@@ -307,31 +319,31 @@ public:
operator wxGraphicsMatrix() const;
#endif
-#if PLATFORM(WIN)
+#if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)) || (PLATFORM(WX) && OS(WINDOWS))
operator XFORM() const;
#endif
+ bool isIdentityOrTranslation() const
+ {
+ return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0
+ && m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0
+ && m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0
+ && m_matrix[3][3] == 1;
+ }
+
private:
// multiply passed 2D point by matrix (assume z=0)
void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
-
+
// multiply passed 3D point by matrix
void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const;
-
+
void setMatrix(const Matrix4 m)
{
if (m && m != m_matrix)
memcpy(m_matrix, m, sizeof(Matrix4));
}
-
- bool isIdentityOrTranslation() const
- {
- return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 &&
- m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 &&
- m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 &&
- m_matrix[3][3] == 1;
- }
-
+
Matrix4 m_matrix;
};
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
index e901669..653b573 100644
--- a/WebCore/platform/graphics/win/FontCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -322,7 +322,8 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
}
if (font->platformData().useGDI()) {
- if (!shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) {
+ static bool canCreateCGFontWithLOGFONT = wkCanCreateCGFontWithLOGFONT();
+ if (!shouldUseFontSmoothing || !canCreateCGFontWithLOGFONT && (graphicsContext->textDrawingMode() & cTextStroke)) {
drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
return;
}
diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp
index 8663623..5e61ef3 100644
--- a/WebCore/platform/graphics/win/FontCacheWin.cpp
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -399,7 +399,7 @@ static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTM
return 1;
}
-static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size)
+static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size, bool synthesizeItalic)
{
HDC hdc = GetDC(0);
@@ -433,6 +433,9 @@ static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool
matchData.m_chosen.lfQuality = DEFAULT_QUALITY;
matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ if (desiredItalic && !matchData.m_chosen.lfItalic && synthesizeItalic)
+ matchData.m_chosen.lfItalic = 1;
+
HFONT result = CreateFontIndirect(&matchData.m_chosen);
if (!result)
return 0;
@@ -514,8 +517,14 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
// This masks rounding errors related to the HFONT metrics being different from the CGFont metrics.
// FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't
// look as nice. That may be solvable though.
+#if PLATFORM(CG)
+ bool canCreateCGFontWithLOGFONT = wkCanCreateCGFontWithLOGFONT();
+#else
+ bool canCreateCGFontWithLOGFONT = true;
+#endif
LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()), family);
- HFONT hfont = createGDIFont(family, weight, fontDescription.italic(), fontDescription.computedPixelSize() * (useGDI ? 1 : 32));
+ HFONT hfont = createGDIFont(family, weight, fontDescription.italic(),
+ fontDescription.computedPixelSize() * (useGDI ? 1 : 32), useGDI && canCreateCGFontWithLOGFONT);
if (!hfont)
return 0;
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
index 24db173..b2d1b32 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -61,7 +61,7 @@ FontCustomPlatformData::~FontCustomPlatformData()
FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode renderingMode)
{
- ASSERT(m_cgFont);
+ ASSERT(wkCanCreateCGFontWithLOGFONT() || m_cgFont);
ASSERT(m_fontReference);
ASSERT(T2embedLibrary());
@@ -87,6 +87,12 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
logFont.lfWeight = bold ? 700 : 400;
HFONT hfont = CreateFontIndirect(&logFont);
+
+ if (wkCanCreateCGFontWithLOGFONT()) {
+ RetainPtr<CGFontRef> cgFont(AdoptCF, CGFontCreateWithPlatformFont(&logFont));
+ return FontPlatformData(hfont, cgFont.get(), size, bold, italic, renderingMode == AlternateRenderingMode);
+ }
+
wkSetFontPlatformInfo(m_cgFont, &logFont, free);
return FontPlatformData(hfont, m_cgFont, size, bold, italic, renderingMode == AlternateRenderingMode);
}
@@ -190,12 +196,15 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
ASSERT_ARG(buffer, buffer);
ASSERT(T2embedLibrary());
- // Get CG to create the font.
- CGDataProviderDirectAccessCallbacks callbacks = { &getData, &releaseData, &getBytesWithOffset, NULL };
- RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirectAccess(buffer, buffer->size(), &callbacks));
- CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider.get());
- if (!cgFont)
- return 0;
+ RetainPtr<CGFontRef> cgFont;
+ if (!wkCanCreateCGFontWithLOGFONT()) {
+ // Get CG to create the font.
+ CGDataProviderDirectAccessCallbacks callbacks = { &getData, &releaseData, &getBytesWithOffset, NULL };
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirectAccess(buffer, buffer->size(), &callbacks));
+ cgFont.adoptCF(CGFontCreateWithDataProvider(dataProvider.get()));
+ if (!cgFont)
+ return 0;
+ }
// Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's
// font namespace (Windows has no API for creating an HFONT from data without exposing the font to the
@@ -210,10 +219,8 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
size_t overlayDst;
size_t overlaySrc;
size_t overlayLength;
- if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength)) {
- CGFontRelease(cgFont);
+ if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength))
return 0;
- }
HANDLE fontReference;
ULONG privStatus;
@@ -225,13 +232,11 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
fontName = String();
else {
fontReference = renameAndActivateFont(buffer, fontName);
- if (!fontReference) {
- CGFontRelease(cgFont);
+ if (!fontReference)
return 0;
- }
}
- return new FontCustomPlatformData(cgFont, fontReference, fontName);
+ return new FontCustomPlatformData(cgFont.releaseRef(), fontReference, fontName);
}
}
diff --git a/WebCore/platform/graphics/win/FontDatabase.cpp b/WebCore/platform/graphics/win/FontDatabase.cpp
index d0773ea..22ad4a6 100644
--- a/WebCore/platform/graphics/win/FontDatabase.cpp
+++ b/WebCore/platform/graphics/win/FontDatabase.cpp
@@ -188,6 +188,9 @@ void populateFontDatabase()
return;
initialized = true;
+ if (wkCanCreateCGFontWithLOGFONT())
+ return;
+
RetainPtr<CFPropertyListRef> propertyList = readFontPlist();
RetainPtr<CFArrayRef> lastFilenamesFromRegistry;
if (propertyList && CFGetTypeID(propertyList.get()) == CFDictionaryGetTypeID()) {
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
index a92e367..d605cf9 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -109,6 +109,13 @@ static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc)
void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
{
+ if (wkCanCreateCGFontWithLOGFONT()) {
+ LOGFONT logfont;
+ GetObject(font, sizeof(logfont), &logfont);
+ m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&logfont));
+ return;
+ }
+
// Try the face name first. Windows may end up localizing this name, and CG doesn't know about
// the localization. If the create fails, we'll try the PostScript name.
RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)));
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index 137b914..47a51de 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -124,17 +124,21 @@ void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& po
CGContextDrawImage(m_data->m_cgContext.get(), CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get());
}
-void GraphicsContext::drawFocusRing(const Color& color)
+void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
{
if (paintingDisabled())
return;
- float radius = (focusRingWidth() - 1) / 2.0f;
- int offset = radius + focusRingOffset();
+ float radius = (width - 1) / 2.0f;
+ offset += radius;
CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0;
CGMutablePathRef focusRingPath = CGPathCreateMutable();
- const Vector<IntRect>& rects = focusRingRects();
unsigned rectCount = rects.size();
for (unsigned i = 0; i < rectCount; i++)
CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset));
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
index 61ae76c..43d92fb 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -40,21 +40,26 @@ static cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha)
{
// Put the HDC In advanced mode so it will honor affine transforms.
SetGraphicsMode(hdc, GM_ADVANCED);
-
+
+ cairo_surface_t* surface = 0;
+
HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
BITMAP info;
- GetObject(bitmap, sizeof(info), &info);
- ASSERT(info.bmBitsPixel == 32);
+ if (!GetObject(bitmap, sizeof(info), &info))
+ surface = cairo_win32_surface_create(hdc);
+ else {
+ ASSERT(info.bmBitsPixel == 32);
- cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
+ surface = cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
CAIRO_FORMAT_ARGB32,
info.bmWidth,
info.bmHeight,
info.bmWidthBytes);
+ }
- cairo_t* context = cairo_create(image);
- cairo_surface_destroy(image);
+ cairo_t* context = cairo_create(surface);
+ cairo_surface_destroy(surface);
return context;
}
diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
index 22faeb8..5ec90b8 100644
--- a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
+++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp
@@ -36,6 +36,7 @@
#include "PlatformString.h"
#include "SystemTime.h"
#include "WKCACFLayer.h"
+#include <QuartzCoreInterface/QuartzCoreInterface.h>
#include <wtf/CurrentTime.h>
#include <wtf/StringExtras.h>
@@ -123,7 +124,7 @@ GraphicsLayerCACF::GraphicsLayerCACF(GraphicsLayerClient* client)
, m_contentsLayerPurpose(NoContentsLayer)
, m_contentsLayerHasBackgroundColor(false)
{
- m_layer = WKCACFLayer::create(kCACFLayer, this);
+ m_layer = WKCACFLayer::create(WKCACFLayer::Layer, this);
updateDebugIndicators();
}
@@ -536,7 +537,7 @@ void GraphicsLayerCACF::updateLayerPreserves3D()
{
if (m_preserves3D && !m_transformLayer) {
// Create the transform layer.
- m_transformLayer = WKCACFLayer::create(kCACFTransformLayer, this);
+ m_transformLayer = WKCACFLayer::create(WKCACFLayer::TransformLayer, this);
#ifndef NDEBUG
m_transformLayer->setName(String().format("Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this));
@@ -552,7 +553,7 @@ void GraphicsLayerCACF::updateLayerPreserves3D()
m_layer->setPosition(point);
m_layer->setAnchorPoint(CGPointMake(0.5f, 0.5f));
- m_layer->setTransform(CATransform3DIdentity);
+ m_layer->setTransform(wkqcCATransform3DIdentity());
// Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
m_layer->setOpacity(1);
@@ -609,7 +610,7 @@ void GraphicsLayerCACF::updateContentsImage()
{
if (m_pendingContentsImage) {
if (!m_contentsLayer.get()) {
- RefPtr<WKCACFLayer> imageLayer = WKCACFLayer::create(kCACFLayer, this);
+ RefPtr<WKCACFLayer> imageLayer = WKCACFLayer::create(WKCACFLayer::Layer, this);
#ifndef NDEBUG
imageLayer->setName("Image Layer");
#endif
@@ -620,7 +621,7 @@ void GraphicsLayerCACF::updateContentsImage()
// FIXME: maybe only do trilinear if the image is being scaled down,
// but then what if the layer size changes?
- m_contentsLayer->setMinificationFilter(kCACFFilterTrilinear);
+ m_contentsLayer->setMinificationFilter(WKCACFLayer::Trilinear);
m_contentsLayer->setContents(m_pendingContentsImage.get());
m_pendingContentsImage = 0;
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
index d71ca00..56b46de 100644
--- a/WebCore/platform/graphics/win/IconWin.cpp
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -27,7 +27,7 @@
#include <tchar.h>
#include <windows.h>
-#if PLATFORM(WINCE)
+#if OS(WINCE)
// SHGFI_SHELLICONSIZE is not available on WINCE
#define SHGFI_SHELLICONSIZE 0
#endif
@@ -63,7 +63,7 @@ PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
return adoptRef(new Icon(sfi.hIcon));
}
-#if PLATFORM(WINCE)
+#if OS(WINCE)
return 0;
#else
TCHAR buffer[MAX_PATH];
@@ -86,7 +86,7 @@ void Icon::paint(GraphicsContext* context, const IntRect& r)
if (context->paintingDisabled())
return;
-#if PLATFORM(WINCE)
+#if OS(WINCE)
context->drawIcon(m_hIcon, r, DI_NORMAL);
#else
HDC hdc = context->getWindowsContext(r);
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index a5beea1..b2fe069 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple, Inc. All rights reserved.
+ * 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
@@ -35,10 +35,16 @@
#include "StringHash.h"
#include "TimeRanges.h"
#include "Timer.h"
+#include <wtf/CurrentTime.h>
#include <wtf/HashSet.h>
#include <wtf/MathExtras.h>
#include <wtf/StdLibExtras.h>
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayerCACF.h"
+#include "WKCACFLayer.h"
+#endif
+
#if DRAW_FRAME_RATE
#include "Font.h"
#include "FrameView.h"
@@ -67,7 +73,6 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_seekTo(-1)
- , m_endTime(numeric_limits<float>::infinity())
, m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
, m_networkState(MediaPlayer::Empty)
, m_readyState(MediaPlayer::HaveNothing)
@@ -76,6 +81,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_hasUnsupportedTracks(false)
, m_startedPlaying(false)
, m_isStreaming(false)
+ , m_visible(false)
+ , m_newFrameAvailable(false)
#if DRAW_FRAME_RATE
, m_frameCountWhilePlaying(0)
, m_timeStartedPlaying(0)
@@ -86,6 +93,19 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
MediaPlayerPrivate::~MediaPlayerPrivate()
{
+ tearDownVideoRendering();
+}
+
+bool MediaPlayerPrivate::supportsFullscreen() const
+{
+ return true;
+}
+
+PlatformMedia MediaPlayerPrivate::platformMedia() const
+{
+ PlatformMedia p;
+ p.qtMovie = reinterpret_cast<QTMovie*>(m_qtMovie.get());
+ return p;
}
class TaskTimer : TimerBase {
@@ -178,7 +198,7 @@ void MediaPlayerPrivate::pause()
return;
m_startedPlaying = false;
#if DRAW_FRAME_RATE
- m_timeStoppedPlaying = GetTickCount();
+ m_timeStoppedPlaying = WTF::currentTime();
#endif
m_qtMovie->pause();
}
@@ -194,7 +214,7 @@ float MediaPlayerPrivate::currentTime() const
{
if (!m_qtMovie)
return 0;
- return min(m_qtMovie->currentTime(), m_endTime);
+ return m_qtMovie->currentTime();
}
void MediaPlayerPrivate::seek(float time)
@@ -222,7 +242,7 @@ void MediaPlayerPrivate::doSeek()
m_qtMovie->setCurrentTime(m_seekTo);
float timeAfterSeek = currentTime();
// restore playback only if not at end, othewise QTMovie will loop
- if (oldRate && timeAfterSeek < duration() && timeAfterSeek < m_endTime)
+ if (oldRate && timeAfterSeek < duration())
m_qtMovie->setRate(oldRate);
cancelSeek();
}
@@ -254,11 +274,6 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
}
}
-void MediaPlayerPrivate::setEndTime(float time)
-{
- m_endTime = time;
-}
-
bool MediaPlayerPrivate::paused() const
{
if (!m_qtMovie)
@@ -332,12 +347,6 @@ void MediaPlayerPrivate::setClosedCaptionsVisible(bool visible)
m_qtMovie->setClosedCaptionsVisible(visible);
}
-int MediaPlayerPrivate::dataRate() const
-{
- // This is not used at the moment
- return 0;
-}
-
PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
{
RefPtr<TimeRanges> timeRanges = TimeRanges::create();
@@ -372,11 +381,6 @@ unsigned MediaPlayerPrivate::bytesLoaded() const
return totalBytes() * maxTime / dur;
}
-bool MediaPlayerPrivate::totalBytesKnown() const
-{
- return totalBytes() > 0;
-}
-
unsigned MediaPlayerPrivate::totalBytes() const
{
if (!m_qtMovie)
@@ -389,9 +393,11 @@ void MediaPlayerPrivate::cancelLoad()
if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
return;
+ tearDownVideoRendering();
+
// Cancel the load by destroying the movie.
m_qtMovie.clear();
-
+
updateStates();
}
@@ -454,6 +460,9 @@ void MediaPlayerPrivate::updateStates()
}
}
+ if (isReadyForRendering() && !hasSetUpVideoRendering())
+ setUpVideoRendering();
+
if (seeking())
m_readyState = MediaPlayer::HaveNothing;
@@ -463,6 +472,11 @@ void MediaPlayerPrivate::updateStates()
m_player->readyStateChanged();
}
+bool MediaPlayerPrivate::isReadyForRendering() const
+{
+ return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
+}
+
void MediaPlayerPrivate::sawUnsupportedTracks()
{
m_qtMovie->setDisabled(true);
@@ -477,7 +491,7 @@ void MediaPlayerPrivate::didEnd()
m_startedPlaying = false;
#if DRAW_FRAME_RATE
- m_timeStoppedPlaying = GetTickCount();
+ m_timeStoppedPlaying = WTF::currentTime();
#endif
updateStates();
m_player->timeChanged();
@@ -485,20 +499,32 @@ void MediaPlayerPrivate::didEnd()
void MediaPlayerPrivate::setSize(const IntSize& size)
{
- if (m_hasUnsupportedTracks || !m_qtMovie)
+ if (m_hasUnsupportedTracks || !m_qtMovie || m_size == size)
return;
+ m_size = size;
m_qtMovie->setSize(size.width(), size.height());
}
-void MediaPlayerPrivate::setVisible(bool b)
+void MediaPlayerPrivate::setVisible(bool visible)
{
- if (m_hasUnsupportedTracks || !m_qtMovie)
+ if (m_hasUnsupportedTracks || !m_qtMovie || m_visible == visible)
return;
- m_qtMovie->setVisible(b);
+
+ m_qtMovie->setVisible(visible);
+ m_visible = visible;
+ if (m_visible) {
+ if (isReadyForRendering())
+ setUpVideoRendering();
+ } else
+ tearDownVideoRendering();
}
void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ return;
+#endif
if (p->paintingDisabled() || !m_qtMovie || m_hasUnsupportedTracks)
return;
@@ -529,28 +555,50 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
else
p->releaseWindowsContext(hdc, r);
+ paintCompleted(*p, r);
+}
+
+void MediaPlayerPrivate::paintCompleted(GraphicsContext& context, const IntRect& rect)
+{
+ m_newFrameAvailable = false;
+
#if DRAW_FRAME_RATE
if (m_frameCountWhilePlaying > 10) {
- Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : NULL;
- Document* document = frame ? frame->document() : NULL;
- RenderObject* renderer = document ? document->renderer() : NULL;
- RenderStyle* styleToUse = renderer ? renderer->style() : NULL;
- if (styleToUse) {
- double frameRate = (m_frameCountWhilePlaying - 1) / (0.001 * ( m_startedPlaying ? (GetTickCount() - m_timeStartedPlaying) :
- (m_timeStoppedPlaying - m_timeStartedPlaying) ));
- String text = String::format("%1.2f", frameRate);
- TextRun textRun(text.characters(), text.length());
- const Color color(255, 0, 0);
- p->save();
- p->translate(r.x(), r.y() + r.height());
- p->setFont(styleToUse->font());
- p->setStrokeColor(color);
- p->setStrokeStyle(SolidStroke);
- p->setStrokeThickness(1.0f);
- p->setFillColor(color);
- p->drawText(textRun, IntPoint(2, -3));
- p->restore();
- }
+ double interval = m_startedPlaying ? WTF::currentTime() - m_timeStartedPlaying : m_timeStoppedPlaying - m_timeStartedPlaying;
+ double frameRate = (m_frameCountWhilePlaying - 1) / interval;
+ CGContextRef cgContext = context.platformContext();
+ CGRect drawRect = rect;
+
+ char text[8];
+ _snprintf(text, sizeof(text), "%1.2f", frameRate);
+
+ static const int fontSize = 25;
+ static const int fontCharWidth = 12;
+ static const int boxHeight = 25;
+ static const int boxBorderWidth = 4;
+ drawRect.size.width = boxBorderWidth * 2 + fontCharWidth * strlen(text);
+ drawRect.size.height = boxHeight;
+
+ CGContextSaveGState(cgContext);
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ CGContextScaleCTM(cgContext, 1, -1);
+ CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, m_qtVideoLayer ? -rect.height() : 0);
+#else
+ CGContextTranslateCTM(cgContext, rect.width() - drawRect.size.width, 0);
+#endif
+ static const CGFloat backgroundColor[4] = { 0.98, 0.98, 0.82, 0.8 };
+ CGContextSetFillColor(cgContext, backgroundColor);
+ CGContextFillRect(cgContext, drawRect);
+
+ static const CGFloat textColor[4] = { 0, 0, 0, 1 };
+ CGContextSetFillColor(cgContext, textColor);
+ CGContextSetTextMatrix(cgContext, CGAffineTransformMakeScale(1, -1));
+ CGContextSelectFont(cgContext, "Helvetica", fontSize, kCGEncodingMacRoman);
+
+ CGContextShowTextAtPoint(cgContext, drawRect.origin.x + boxBorderWidth, drawRect.origin.y + boxHeight - boxBorderWidth, text, strlen(text));
+
+ CGContextRestoreGState(cgContext);
}
#endif
}
@@ -630,13 +678,21 @@ void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie)
#if DRAW_FRAME_RATE
if (m_startedPlaying) {
m_frameCountWhilePlaying++;
- // to eliminate preroll costs from our calculation,
- // our frame rate calculation excludes the first frame drawn after playback starts
- if (1==m_frameCountWhilePlaying)
- m_timeStartedPlaying = GetTickCount();
+ // To eliminate preroll costs from our calculation, our frame rate calculation excludes
+ // the first frame drawn after playback starts.
+ if (m_frameCountWhilePlaying == 1)
+ m_timeStartedPlaying = WTF::currentTime();
}
#endif
- m_player->repaint();
+
+ m_newFrameAvailable = true;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ m_qtVideoLayer->platformLayer()->setNeedsDisplay();
+ else
+#endif
+ m_player->repaint();
}
bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
@@ -646,6 +702,171 @@ bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
return true;
}
+MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::currentRenderingMode() const
+{
+ if (!m_qtMovie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::preferredRenderingMode() const
+{
+ if (!m_player->frameView() || !m_qtMovie)
+ return MediaRenderingNone;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+void MediaPlayerPrivate::setUpVideoRendering()
+{
+ MediaRenderingMode currentMode = currentRenderingMode();
+ MediaRenderingMode preferredMode = preferredRenderingMode();
+
+#if !USE(ACCELERATED_COMPOSITING)
+ ASSERT(preferredMode != MediaRenderingMovieLayer);
+#endif
+
+ if (currentMode == preferredMode && currentMode != MediaRenderingNone)
+ return;
+
+ if (currentMode != MediaRenderingNone)
+ tearDownVideoRendering();
+
+ if (preferredMode == MediaRenderingMovieLayer)
+ createLayerForMovie();
+}
+
+void MediaPlayerPrivate::tearDownVideoRendering()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_qtVideoLayer)
+ destroyLayerForMovie();
+#endif
+}
+
+bool MediaPlayerPrivate::hasSetUpVideoRendering() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ return m_qtVideoLayer || currentRenderingMode() != MediaRenderingMovieLayer;
+#else
+ return true;
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+
+// Up-call from compositing layer drawing callback.
+void MediaPlayerPrivate::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect&)
+{
+ if (m_hasUnsupportedTracks)
+ return;
+
+ ASSERT(supportsAcceleratedRendering());
+
+ // No reason to replace the current layer image unless we have something new to show.
+ if (!m_newFrameAvailable)
+ return;
+
+ static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ void* buffer;
+ unsigned bitsPerPixel;
+ unsigned rowBytes;
+ unsigned width;
+ unsigned height;
+
+ m_qtMovie->getCurrentFrameInfo(buffer, bitsPerPixel, rowBytes, width, height);
+ if (!buffer)
+ return ;
+
+ RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, static_cast<UInt8*>(buffer), rowBytes * height, kCFAllocatorNull));
+ RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithCFData(data.get()));
+ RetainPtr<CGImageRef> frameImage(AdoptCF, CGImageCreate(width, height, 8, bitsPerPixel, rowBytes, colorSpace,
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst, provider.get(), 0, false, kCGRenderingIntentDefault));
+ if (!frameImage)
+ return;
+
+ IntRect rect(0, 0, m_size.width(), m_size.height());
+ CGContextDrawImage(context.platformContext(), rect, frameImage.get());
+ paintCompleted(context, rect);
+}
+#endif
+
+void MediaPlayerPrivate::createLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(supportsAcceleratedRendering());
+
+ if (!m_qtMovie || m_qtVideoLayer)
+ return;
+
+ // Do nothing if the parent layer hasn't been set up yet.
+ GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
+ if (!videoGraphicsLayer)
+ 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(this));
+ if (!m_qtVideoLayer)
+ return;
+
+ // Mark the layer as drawing itself, anchored in the top left, and bottom-up.
+ m_qtVideoLayer->setDrawsContent(true);
+ m_qtVideoLayer->setAnchorPoint(FloatPoint3D());
+ m_qtVideoLayer->setContentsOrientation(GraphicsLayer::CompositingCoordinatesBottomUp);
+#ifndef NDEBUG
+ m_qtVideoLayer->setName("Video layer");
+#endif
+
+ // Hang the video layer from the render layer.
+ videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer->platformLayer());
+#endif
+}
+
+void MediaPlayerPrivate::destroyLayerForMovie()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!m_qtVideoLayer)
+ return;
+ m_qtVideoLayer = 0;
+#endif
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool MediaPlayerPrivate::supportsAcceleratedRendering() const
+{
+ return isReadyForRendering();
+}
+
+void MediaPlayerPrivate::acceleratedRenderingStateChanged()
+{
+ // Set up or change the rendering path if necessary.
+ setUpVideoRendering();
+}
+
+void MediaPlayerPrivate::notifySyncRequired(const GraphicsLayer*)
+{
+ GraphicsLayerCACF* videoGraphicsLayer = static_cast<GraphicsLayerCACF*>(m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player));
+ if (videoGraphicsLayer)
+ videoGraphicsLayer->notifySyncRequired();
+ }
+
+
+#endif
+
+
}
#endif
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
index 2bccbbf..d58f44f 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * 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
@@ -32,11 +32,18 @@
#include "Timer.h"
#include <QTMovieWin.h>
#include <wtf/OwnPtr.h>
+#include <wtf/RetainPtr.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayerClient.h"
+#endif
#ifndef DRAW_FRAME_RATE
#define DRAW_FRAME_RATE 0
#endif
+typedef struct CGImage *CGImageRef;
+
namespace WebCore {
class GraphicsContext;
@@ -44,15 +51,32 @@ class IntSize;
class IntRect;
class String;
-class MediaPlayerPrivate : public MediaPlayerPrivateInterface, public QTMovieWinClient {
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface, public QTMovieWinClient
+#if USE(ACCELERATED_COMPOSITING)
+ , public GraphicsLayerClient
+#endif
+{
public:
static void registerMediaEngine(MediaEngineRegistrar);
~MediaPlayerPrivate();
private:
+
+#if USE(ACCELERATED_COMPOSITING)
+ // GraphicsLayerClient methods
+ virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip);
+ virtual void notifyAnimationStarted(const GraphicsLayer*, double time) { }
+ virtual void notifySyncRequired(const GraphicsLayer*);
+ virtual bool showDebugBorders() const { return false; }
+ virtual bool showRepaintCounter() const { return false; }
+#endif
+
MediaPlayerPrivate(MediaPlayer*);
+ virtual bool supportsFullscreen() const;
+ virtual PlatformMedia platformMedia() const;
+
IntSize naturalSize() const;
bool hasVideo() const;
bool hasAudio() const;
@@ -69,21 +93,17 @@ private:
float duration() const;
float currentTime() const;
void seek(float time);
- void setEndTime(float);
void setRate(float);
void setVolume(float);
void setPreservesPitch(bool);
- int dataRate() const;
-
MediaPlayer::NetworkState networkState() const { return m_networkState; }
MediaPlayer::ReadyState readyState() const { return m_readyState; }
PassRefPtr<TimeRanges> buffered() const;
float maxTimeSeekable() const;
unsigned bytesLoaded() const;
- bool totalBytesKnown() const;
unsigned totalBytes() const;
void setVisible(bool);
@@ -93,7 +113,8 @@ private:
void didEnd();
void paint(GraphicsContext*, const IntRect&);
-
+ void paintCompleted(GraphicsContext&, const IntRect&);
+
bool hasSingleSecurityOrigin() const;
bool hasClosedCaptions() const;
@@ -117,11 +138,31 @@ private:
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();
+
MediaPlayer* m_player;
OwnPtr<QTMovieWin> m_qtMovie;
+#if USE(ACCELERATED_COMPOSITING)
+ OwnPtr<GraphicsLayer> m_qtVideoLayer;
+#endif
float m_seekTo;
- float m_endTime;
Timer<MediaPlayerPrivate> m_seekTimer;
+ IntSize m_size;
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
unsigned m_enabledTrackCount;
@@ -129,10 +170,12 @@ private:
bool m_hasUnsupportedTracks;
bool m_startedPlaying;
bool m_isStreaming;
+ bool m_visible;
+ bool m_newFrameAvailable;
#if DRAW_FRAME_RATE
- int m_frameCountWhilePlaying;
- int m_timeStartedPlaying;
- int m_timeStoppedPlaying;
+ double m_frameCountWhilePlaying;
+ double m_timeStartedPlaying;
+ double m_timeStoppedPlaying;
#endif
};
diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp
index 2d4c2ea..8fd6c71 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple, Inc. All rights reserved.
+ * 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
@@ -24,18 +24,15 @@
*/
#include "config.h"
-#include <windows.h>
-
#include "QTMovieWin.h"
// Put Movies.h first so build failures here point clearly to QuickTime
#include <Movies.h>
-#include <QuickTimeComponents.h>
-#include <GXMath.h>
-#include <QTML.h>
#include "QTMovieWinTimer.h"
-
+#include <GXMath.h>
+#include <QTML.h>
+#include <QuickTimeComponents.h>
#include <wtf/Assertions.h>
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
@@ -50,6 +47,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");
// Resizing GWorlds is slow, give them a minimum size so size of small
// videos can be animated smoothly
@@ -130,6 +128,11 @@ 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()
@@ -159,11 +162,19 @@ QTMovieWinPrivate::QTMovieWinPrivate()
#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()
{
+ ASSERT(!m_fullscreenWindow);
+
endTask();
if (m_gWorld)
deleteGWorld();
@@ -359,7 +370,7 @@ void QTMovieWinPrivate::createGWorld()
bounds.left = 0;
bounds.right = m_gWorldWidth;
bounds.bottom = m_gWorldHeight;
- OSErr err = QTNewGWorld(&m_gWorld, k32BGRAPixelFormat, &bounds, NULL, NULL, NULL);
+ OSErr err = QTNewGWorld(&m_gWorld, k32BGRAPixelFormat, &bounds, 0, 0, 0);
if (err)
return;
GetMovieGWorld(m_movie, &m_savedGWorld, 0);
@@ -597,6 +608,24 @@ void QTMovieWin::setVisible(bool 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)
@@ -729,7 +758,7 @@ void QTMovieWin::load(CFURLRef url, bool preservesPitch)
moviePropCount++;
ASSERT(moviePropCount <= sizeof(movieProps)/sizeof(movieProps[0]));
- m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, NULL, &m_private->m_movie);
+ m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, 0, &m_private->m_movie);
end:
m_private->startTask();
@@ -953,7 +982,7 @@ static void initializeSupportedTypes()
continue;
if (!(infoCD.componentFlags & hasMovieImportMIMEList))
continue;
- QTAtomContainer mimeList = NULL;
+ QTAtomContainer mimeList = 0;
err = MovieImportGetMIMETypeList((ComponentInstance)comp, &mimeList);
if (err || !mimeList)
continue;
@@ -962,7 +991,7 @@ static void initializeSupportedTypes()
QTLockContainer(mimeList);
int typeCount = QTCountChildrenOfType(mimeList, kParentAtomIsContainer, kMimeInfoMimeTypeTag);
for (int typeIndex = 1; typeIndex <= typeCount; typeIndex++) {
- QTAtom mimeTag = QTFindChildByIndex(mimeList, 0, kMimeInfoMimeTypeTag, typeIndex, NULL);
+ QTAtom mimeTag = QTFindChildByIndex(mimeList, 0, kMimeInfoMimeTypeTag, typeIndex, 0);
if (!mimeTag)
continue;
char* atomData;
@@ -980,7 +1009,7 @@ static void initializeSupportedTypes()
if (strncmp(typeBuffer, "audio/", 6) && strncmp(typeBuffer, "video/", 6))
continue;
- CFStringRef cfMimeType = CFStringCreateWithCString(NULL, typeBuffer, kCFStringEncodingUTF8);
+ CFStringRef cfMimeType = CFStringCreateWithCString(0, typeBuffer, kCFStringEncodingUTF8);
if (!cfMimeType)
continue;
@@ -1040,7 +1069,7 @@ bool QTMovieWin::initializeQuickTime()
if (!initialized) {
initialized = true;
// Initialize and check QuickTime version
- OSErr result = InitializeQTML(0);
+ OSErr result = InitializeQTML(kInitializeQTMLEnableDoubleBufferedSurface);
if (result == noErr)
result = Gestalt(gestaltQuickTime, &quickTimeVersion);
if (result != noErr) {
@@ -1058,15 +1087,80 @@ bool QTMovieWin::initializeQuickTime()
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()
+{
+ 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;
+}
+
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason) {
- case DLL_PROCESS_ATTACH:
- return TRUE;
- case DLL_PROCESS_DETACH:
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- return FALSE;
+ case DLL_PROCESS_ATTACH:
+ return TRUE;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ return FALSE;
}
ASSERT_NOT_REACHED();
return FALSE;
diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h
index 778f9aa..d2a7ed0 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.h
+++ b/WebCore/platform/graphics/win/QTMovieWin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple, Inc. All rights reserved.
+ * 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
@@ -27,6 +27,7 @@
#define QTMovieWin_h
#include <Unicode.h>
+#include <windows.h>
#ifdef QTMOVIEWIN_EXPORTS
#define QTMOVIEWIN_API __declspec(dllexport)
@@ -45,6 +46,11 @@ public:
virtual void movieNewImageAvailable(QTMovieWin*) = 0;
};
+class QTMovieWinFullscreenClient {
+public:
+ virtual LRESULT fullscreenClientWndProc(HWND, UINT message, WPARAM, LPARAM) = 0;
+};
+
enum {
QTMovieLoadStateError = -1L,
QTMovieLoadStateLoaded = 2000L,
@@ -91,6 +97,7 @@ public:
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);
void setDisabled(bool);
@@ -104,8 +111,13 @@ 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();
+
private:
void load(CFURLRef, bool preservesPitch);
+ static LRESULT fullscreenWndProc(HWND, UINT message, WPARAM, LPARAM);
QTMovieWinPrivate* m_private;
bool m_disabled;
diff --git a/WebCore/platform/graphics/win/TransformationMatrixWin.cpp b/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
index 38dbfbf..47806a2 100644
--- a/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
+++ b/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
@@ -26,6 +26,8 @@
#include "config.h"
#include "TransformationMatrix.h"
+#include <windows.h>
+
namespace WebCore {
TransformationMatrix::operator XFORM() const
diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp
index 21e010d..ad1fc85 100644
--- a/WebCore/platform/graphics/win/WKCACFLayer.cpp
+++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp
@@ -30,12 +30,19 @@
#include "WKCACFLayer.h"
#include "WKCACFContextFlusher.h"
+#include "WKCACFLayerRenderer.h"
#include <stdio.h>
#include <QuartzCore/CACFContext.h>
#include <QuartzCore/CARender.h>
+#include <QuartzCoreInterface/QuartzCoreInterface.h>
-#pragma comment(lib, "QuartzCore")
+#ifdef DEBUG_ALL
+#pragma comment(lib, "QuartzCore_debug")
+#else
+#pragma comment(lib, "QuartzCore")
+#endif
+#pragma comment(lib, "QuartzCoreInterface")
namespace WebCore {
@@ -47,11 +54,135 @@ static void displayInContext(CACFLayerRef layer, CGContextRef context)
WKCACFLayer::layer(layer)->display(context);
}
+#define STATIC_CACF_STRING(name) \
+ static CFStringRef name() \
+ { \
+ static CFStringRef name = wkqcCFStringRef(wkqc##name); \
+ return name; \
+ }
+
+STATIC_CACF_STRING(kCACFLayer)
+STATIC_CACF_STRING(kCACFTransformLayer)
+STATIC_CACF_STRING(kCACFGravityCenter)
+STATIC_CACF_STRING(kCACFGravityTop)
+STATIC_CACF_STRING(kCACFGravityBottom)
+STATIC_CACF_STRING(kCACFGravityLeft)
+STATIC_CACF_STRING(kCACFGravityRight)
+STATIC_CACF_STRING(kCACFGravityTopLeft)
+STATIC_CACF_STRING(kCACFGravityTopRight)
+STATIC_CACF_STRING(kCACFGravityBottomLeft)
+STATIC_CACF_STRING(kCACFGravityBottomRight)
+STATIC_CACF_STRING(kCACFGravityResize)
+STATIC_CACF_STRING(kCACFGravityResizeAspect)
+STATIC_CACF_STRING(kCACFGravityResizeAspectFill)
+STATIC_CACF_STRING(kCACFFilterLinear)
+STATIC_CACF_STRING(kCACFFilterNearest)
+STATIC_CACF_STRING(kCACFFilterTrilinear)
+STATIC_CACF_STRING(kCACFFilterLanczos)
+
+static CFStringRef toCACFLayerType(WKCACFLayer::LayerType type)
+{
+ switch (type) {
+ case WKCACFLayer::Layer: return kCACFLayer();
+ case WKCACFLayer::TransformLayer: return kCACFTransformLayer();
+ default: return 0;
+ }
+}
+
+static CFStringRef toCACFContentsGravityType(WKCACFLayer::ContentsGravityType type)
+{
+ switch (type) {
+ case WKCACFLayer::Center: return kCACFGravityCenter();
+ case WKCACFLayer::Top: return kCACFGravityTop();
+ case WKCACFLayer::Bottom: return kCACFGravityBottom();
+ case WKCACFLayer::Left: return kCACFGravityLeft();
+ case WKCACFLayer::Right: return kCACFGravityRight();
+ case WKCACFLayer::TopLeft: return kCACFGravityTopLeft();
+ case WKCACFLayer::TopRight: return kCACFGravityTopRight();
+ case WKCACFLayer::BottomLeft: return kCACFGravityBottomLeft();
+ case WKCACFLayer::BottomRight: return kCACFGravityBottomRight();
+ case WKCACFLayer::Resize: return kCACFGravityResize();
+ case WKCACFLayer::ResizeAspect: return kCACFGravityResizeAspect();
+ case WKCACFLayer::ResizeAspectFill: return kCACFGravityResizeAspectFill();
+ default: return 0;
+ }
+}
+
+static WKCACFLayer::ContentsGravityType fromCACFContentsGravityType(CFStringRef string)
+{
+ if (CFEqual(string, kCACFGravityTop()))
+ return WKCACFLayer::Top;
+
+ if (CFEqual(string, kCACFGravityBottom()))
+ return WKCACFLayer::Bottom;
+
+ if (CFEqual(string, kCACFGravityLeft()))
+ return WKCACFLayer::Left;
+
+ if (CFEqual(string, kCACFGravityRight()))
+ return WKCACFLayer::Right;
+
+ if (CFEqual(string, kCACFGravityTopLeft()))
+ return WKCACFLayer::TopLeft;
+
+ if (CFEqual(string, kCACFGravityTopRight()))
+ return WKCACFLayer::TopRight;
+
+ if (CFEqual(string, kCACFGravityBottomLeft()))
+ return WKCACFLayer::BottomLeft;
+
+ if (CFEqual(string, kCACFGravityBottomRight()))
+ return WKCACFLayer::BottomRight;
+
+ if (CFEqual(string, kCACFGravityResize()))
+ return WKCACFLayer::Resize;
+
+ if (CFEqual(string, kCACFGravityResizeAspect()))
+ return WKCACFLayer::ResizeAspect;
+
+ if (CFEqual(string, kCACFGravityResizeAspectFill()))
+ return WKCACFLayer::ResizeAspectFill;
+
+ return WKCACFLayer::Center;
+}
+
+static CFStringRef toCACFFilterType(WKCACFLayer::FilterType type)
+{
+ switch (type) {
+ case WKCACFLayer::Linear: return kCACFFilterLinear();
+ case WKCACFLayer::Nearest: return kCACFFilterNearest();
+ case WKCACFLayer::Trilinear: return kCACFFilterTrilinear();
+ case WKCACFLayer::Lanczos: return kCACFFilterLanczos();
+ default: return 0;
+ }
+}
+
+static WKCACFLayer::FilterType fromCACFFilterType(CFStringRef string)
+{
+ if (CFEqual(string, kCACFFilterNearest()))
+ return WKCACFLayer::Nearest;
+
+ if (CFEqual(string, kCACFFilterTrilinear()))
+ return WKCACFLayer::Trilinear;
+
+ if (CFEqual(string, kCACFFilterLanczos()))
+ return WKCACFLayer::Lanczos;
+
+ return WKCACFLayer::Linear;
+}
+
+PassRefPtr<WKCACFLayer> WKCACFLayer::create(LayerType type, GraphicsLayerCACF* owner)
+{
+ if (!WKCACFLayerRenderer::acceleratedCompositingAvailable())
+ return 0;
+ return adoptRef(new WKCACFLayer(type, owner));
+}
+
// FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually
// get destroyed in debug builds. A static counter could accomplish this pretty easily.
-WKCACFLayer::WKCACFLayer(CFStringRef className, GraphicsLayerCACF* owner)
- : m_layer(AdoptCF, CACFLayerCreate(className))
+WKCACFLayer::WKCACFLayer(LayerType type, GraphicsLayerCACF* owner)
+ : m_layer(AdoptCF, CACFLayerCreate(toCACFLayerType(type)))
, m_needsDisplayOnBoundsChange(false)
, m_owner(owner)
{
@@ -291,6 +422,39 @@ void WKCACFLayer::setFrame(const CGRect& rect)
setNeedsDisplay();
}
+void WKCACFLayer::setContentsGravity(ContentsGravityType type)
+{
+ CACFLayerSetContentsGravity(layer(), toCACFContentsGravityType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::ContentsGravityType WKCACFLayer::contentsGravity() const
+{
+ return fromCACFContentsGravityType(CACFLayerGetContentsGravity(layer()));
+}
+
+void WKCACFLayer::setMagnificationFilter(FilterType type)
+{
+ CACFLayerSetMagnificationFilter(layer(), toCACFFilterType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::FilterType WKCACFLayer::magnificationFilter() const
+{
+ return fromCACFFilterType(CACFLayerGetMagnificationFilter(layer()));
+}
+
+void WKCACFLayer::setMinificationFilter(FilterType type)
+{
+ CACFLayerSetMinificationFilter(layer(), toCACFFilterType(type));
+ setNeedsCommit();
+}
+
+WKCACFLayer::FilterType WKCACFLayer::minificationFilter() const
+{
+ return fromCACFFilterType(CACFLayerGetMinificationFilter(layer()));
+}
+
WKCACFLayer* WKCACFLayer::rootLayer() const
{
WKCACFLayer* layer = const_cast<WKCACFLayer*>(this);
diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h
index 6655f7a..6892c6e 100644
--- a/WebCore/platform/graphics/win/WKCACFLayer.h
+++ b/WebCore/platform/graphics/win/WKCACFLayer.h
@@ -50,7 +50,12 @@ class WKCACFTimingFunction;
class WKCACFLayer : public RefCounted<WKCACFLayer> {
public:
- static PassRefPtr<WKCACFLayer> create(CFStringRef className, GraphicsLayerCACF* owner = 0) { return adoptRef(new WKCACFLayer(className, owner)); }
+ enum LayerType { Layer, TransformLayer };
+ enum FilterType { Linear, Nearest, Trilinear, Lanczos };
+ enum ContentsGravityType { Center, Top, Bottom, Left, Right, TopLeft, TopRight,
+ BottomLeft, BottomRight, Resize, ResizeAspect, ResizeAspectFill };
+
+ static PassRefPtr<WKCACFLayer> create(LayerType, GraphicsLayerCACF* owner = 0);
static WKCACFLayer* layer(CACFLayerRef layer) { return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer)); }
~WKCACFLayer();
@@ -142,8 +147,8 @@ public:
void setContentsRect(const CGRect& contentsRect) { CACFLayerSetContentsRect(layer(), contentsRect); setNeedsCommit(); }
CGRect contentsRect() const { return CACFLayerGetContentsRect(layer()); }
- void setContentsGravity(CFStringRef str) { CACFLayerSetContentsGravity(layer(), str); setNeedsCommit(); }
- CFStringRef contentsGravity() const { return CACFLayerGetContentsGravity(layer()); }
+ void setContentsGravity(ContentsGravityType);
+ ContentsGravityType contentsGravity() const;
void setDoubleSided(bool b) { CACFLayerSetDoubleSided(layer(), b); setNeedsCommit(); }
bool doubleSided() const { return CACFLayerIsDoubleSided(layer()); }
@@ -163,11 +168,11 @@ public:
void setMasksToBounds(bool b) { CACFLayerSetMasksToBounds(layer(), b); }
bool masksToBounds() const { return CACFLayerGetMasksToBounds(layer()); }
- void setMagnificationFilter(const String& string) { CACFLayerSetMagnificationFilter(layer(), RetainPtr<CFStringRef>(AdoptCF, string.createCFString()).get()); }
- String magnificationFilter() const { return CACFLayerGetMagnificationFilter(layer()); }
+ void setMagnificationFilter(FilterType);
+ FilterType magnificationFilter() const;
- void setMinificationFilter(const String& string) { CACFLayerSetMinificationFilter(layer(), RetainPtr<CFStringRef>(AdoptCF, string.createCFString()).get()); }
- String minificationFilter() const { return CACFLayerGetMinificationFilter(layer()); }
+ void setMinificationFilter(FilterType);
+ FilterType minificationFilter() const;
void setMinificationFilterBias(float bias) { CACFLayerSetMinificationFilterBias(layer(), bias); }
float minificationFilterBias() const { return CACFLayerGetMinificationFilterBias(layer()); }
@@ -218,9 +223,9 @@ public:
void setGeometryFlipped(bool flipped) { CACFLayerSetGeometryFlipped(layer(), flipped); setNeedsCommit(); }
bool geometryFlipped() const { return CACFLayerIsGeometryFlipped(layer()); }
- WKCACFLayer(CFStringRef className, GraphicsLayerCACF* owner);
-
private:
+ WKCACFLayer(LayerType, GraphicsLayerCACF* owner);
+
void setNeedsCommit();
CACFLayerRef layer() const { return m_layer.get(); }
size_t numSublayers() const
diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
index 9fbd0fc..3bbd4f8 100644
--- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
+++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
@@ -34,15 +34,20 @@
#include <CoreGraphics/CGSRegion.h>
#include <QuartzCore/CACFContext.h>
#include <QuartzCore/CARenderOGL.h>
+#include <QuartzCoreInterface/QuartzCoreInterface.h>
#include <wtf/HashMap.h>
#include <wtf/OwnArrayPtr.h>
+#include <wtf/StdLibExtras.h>
#include <d3d9.h>
#include <d3dx9.h>
-#include <dxerr9.h>
-#pragma comment(lib, "d3d9")
-#pragma comment(lib, "d3dx9")
-#pragma comment(lib, "QuartzCore")
+#pragma comment(lib, "d3d9")
+#pragma comment(lib, "d3dx9")
+#ifdef DEBUG_ALL
+#pragma comment(lib, "QuartzCore_debug")
+#else
+#pragma comment(lib, "QuartzCore")
+#endif
static IDirect3D9* s_d3d = 0;
static IDirect3D9* d3d()
@@ -90,29 +95,29 @@ static D3DPRESENT_PARAMETERS initialPresentationParameters()
return parameters;
}
-bool WKCACFLayerRenderer::acceleratedCompositingAvailable()
-{
- static bool available;
- static bool tested;
-
- if (tested)
- return available;
-
- tested = true;
- HMODULE library = LoadLibrary(TEXT("d3d9.dll"));
- if (!library)
- return false;
-
- FreeLibrary(library);
- library = LoadLibrary(TEXT("QuartzCore.dll"));
- if (!library)
- return false;
-
- FreeLibrary(library);
- available = true;
- return available;
-}
-
+bool WKCACFLayerRenderer::acceleratedCompositingAvailable()
+{
+ static bool available;
+ static bool tested;
+
+ if (tested)
+ return available;
+
+ tested = true;
+ HMODULE library = LoadLibrary(TEXT("d3d9.dll"));
+ if (!library)
+ return false;
+
+ FreeLibrary(library);
+ library = LoadLibrary(TEXT("QuartzCore.dll"));
+ if (!library)
+ return false;
+
+ FreeLibrary(library);
+ available = true;
+ return available;
+}
+
void WKCACFLayerRenderer::didFlushContext(CACFContextRef context)
{
WKCACFLayerRenderer* window = windowsForContexts().get(context);
@@ -135,8 +140,7 @@ WKCACFLayerRenderer::WKCACFLayerRenderer()
, m_renderer(0)
, m_hostWindow(0)
, m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired)
- , m_scrollFrameWidth(1) // Default to 1 to avoid 0 size frames
- , m_scrollFrameHeight(1) // Default to 1 to avoid 0 size frames
+ , m_scrollFrame(0, 0, 1, 1) // Default to 1 to avoid 0 size frames
{
}
@@ -145,19 +149,15 @@ WKCACFLayerRenderer::~WKCACFLayerRenderer()
destroyRenderer();
}
-void WKCACFLayerRenderer::setScrollFrame(int width, int height, int scrollX, int scrollY)
+void WKCACFLayerRenderer::setScrollFrame(const IntRect& scrollFrame)
{
- m_scrollFrameWidth = width;
- m_scrollFrameHeight = height;
-
- CGRect contentsRect = CGRectMake(scrollX, scrollY, width, height);
- m_scrollLayer->setFrame(contentsRect);
+ m_scrollFrame = scrollFrame;
+ CGRect frameBounds = bounds();
+ m_scrollLayer->setBounds(CGRectMake(0, 0, m_scrollFrame.width(), m_scrollFrame.height()));
+ m_scrollLayer->setPosition(CGPointMake(0, frameBounds.size.height));
- if (m_rootChildLayer) {
- contentsRect.origin.x = 0;
- contentsRect.origin.y = 0;
- m_rootChildLayer->setFrame(contentsRect);
- }
+ if (m_rootChildLayer)
+ m_rootChildLayer->setPosition(CGPointMake(m_scrollFrame.x(), m_scrollFrame.height() + m_scrollFrame.y()));
}
void WKCACFLayerRenderer::setRootContents(CGImageRef image)
@@ -177,7 +177,8 @@ void WKCACFLayerRenderer::setRootChildLayer(WebCore::PlatformLayer* layer)
m_scrollLayer->addSublayer(layer);
// Set the frame
- layer->setFrame(CGRectMake(0, 0, m_scrollFrameWidth, m_scrollFrameHeight));
+ layer->setAnchorPoint(CGPointMake(0, 1));
+ setScrollFrame(m_scrollFrame);
}
m_rootChildLayer = layer;
@@ -225,14 +226,15 @@ void WKCACFLayerRenderer::createRenderer()
windowsForContexts().set(m_context.get(), this);
m_renderContext = static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get()));
- m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0);
+ m_renderer = CARenderOGLNew(wkqcCARenderOGLCallbacks(wkqckCARenderDX9Callbacks), m_d3dDevice.get(), 0);
// Create the root hierarchy
- m_rootLayer = WKCACFLayer::create(kCACFLayer);
- m_scrollLayer = WKCACFLayer::create(kCACFLayer);
+ m_rootLayer = WKCACFLayer::create(WKCACFLayer::Layer);
+ m_scrollLayer = WKCACFLayer::create(WKCACFLayer::Layer);
m_rootLayer->addSublayer(m_scrollLayer);
m_scrollLayer->setMasksToBounds(true);
+ m_scrollLayer->setAnchorPoint(CGPointMake(0, 1));
#ifndef NDEBUG
CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204));
@@ -240,14 +242,9 @@ void WKCACFLayerRenderer::createRenderer()
CGColorRelease(debugColor);
#endif
- if (IsWindow(m_hostWindow)) {
+ if (IsWindow(m_hostWindow))
m_rootLayer->setFrame(bounds());
- // For now this will include the scroll bars. Later in the setScrollFrame
- // we will fix it
- m_scrollLayer->setFrame(bounds());
- }
-
if (m_context)
m_rootLayer->becomeRootLayerForContext(m_context.get());
}
@@ -284,6 +281,7 @@ void WKCACFLayerRenderer::resize()
if (m_rootLayer) {
m_rootLayer->setFrame(bounds());
WKCACFContextFlusher::shared().flushAllContexts();
+ setScrollFrame(m_scrollFrame);
}
}
diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
index 12cde48..cb9f04f 100644
--- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
+++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
@@ -58,7 +58,7 @@ public:
static bool acceleratedCompositingAvailable();
static void didFlushContext(CACFContextRef);
- void setScrollFrame(int width, int height, int scrollX, int scrollY);
+ void setScrollFrame(const IntRect&);
void setRootContents(CGImageRef);
void setRootChildLayer(WebCore::PlatformLayer* layer);
void setNeedsDisplay();
@@ -96,7 +96,7 @@ private:
CARenderOGLContext* m_renderer;
HWND m_hostWindow;
Timer<WKCACFLayerRenderer> m_renderTimer;
- int m_scrollFrameWidth, m_scrollFrameHeight;
+ IntRect m_scrollFrame;
};
}
diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
index f22e6c9..0e387f5 100644
--- a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
+++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
@@ -1002,7 +1002,12 @@ void GraphicsContext::clipOut(const IntRect& rect)
ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
}
-void GraphicsContext::drawFocusRing(const Color& color)
+void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
{
if (!m_data->m_opacity || paintingDisabled())
return;
@@ -1011,10 +1016,9 @@ void GraphicsContext::drawFocusRing(const Color& color)
if (!m_data->m_dc)
return;
- int radius = (focusRingWidth() - 1) / 2;
- int offset = radius + focusRingOffset();
+ int radius = (width - 1) / 2;
+ offset += radius;
- const Vector<IntRect>& rects = focusRingRects();
unsigned rectCount = rects.size();
IntRect finalFocusRect;
for (unsigned i = 0; i < rectCount; i++) {
diff --git a/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h b/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h
index 2d6c358..a657e3e 100644
--- a/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h
+++ b/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h
@@ -61,20 +61,16 @@ namespace WebCore {
float duration() const;
float currentTime() const;
void seek(float time);
- void setEndTime(float);
void setRate(float);
void setVolume(float);
- int dataRate() const;
-
MediaPlayer::NetworkState networkState() const { return m_networkState; }
MediaPlayer::ReadyState readyState() const { return m_readyState; }
PassRefPtr<TimeRanges> buffered() const;
float maxTimeSeekable() const;
unsigned bytesLoaded() const;
- bool totalBytesKnown() const;
unsigned totalBytes() const;
void setVisible(bool);
diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
index 9c05ce5..839bc59 100644
--- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
+++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -270,7 +270,12 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
notImplemented();
}
-void GraphicsContext::drawFocusRing(const Color& color)
+void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
{
if (paintingDisabled())
return;
@@ -566,7 +571,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness
notImplemented();
}
-#if PLATFORM(WIN_OS)
+#if OS(WINDOWS)
HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
if (dstRect.isEmpty())