summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics')
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp1
-rw-r--r--WebCore/platform/graphics/BitmapImage.h14
-rw-r--r--WebCore/platform/graphics/Color.cpp39
-rw-r--r--WebCore/platform/graphics/Color.h7
-rw-r--r--WebCore/platform/graphics/FloatPoint.cpp2
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.cpp2
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.h4
-rw-r--r--WebCore/platform/graphics/FontCache.cpp26
-rw-r--r--WebCore/platform/graphics/GlyphBuffer.h2
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.cpp1
-rw-r--r--WebCore/platform/graphics/GlyphWidthMap.cpp37
-rw-r--r--WebCore/platform/graphics/GlyphWidthMap.h43
-rw-r--r--WebCore/platform/graphics/Gradient.cpp8
-rw-r--r--WebCore/platform/graphics/Gradient.h10
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp40
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h39
-rw-r--r--WebCore/platform/graphics/GraphicsContextPrivate.h13
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.cpp545
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.h407
-rw-r--r--WebCore/platform/graphics/GraphicsLayerClient.h69
-rw-r--r--WebCore/platform/graphics/GraphicsTypes.h8
-rw-r--r--WebCore/platform/graphics/Image.cpp4
-rw-r--r--WebCore/platform/graphics/Image.h10
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp254
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h88
-rw-r--r--WebCore/platform/graphics/MediaPlayerPrivate.h94
-rw-r--r--WebCore/platform/graphics/Pattern.h6
-rw-r--r--WebCore/platform/graphics/SimpleFontData.cpp14
-rw-r--r--WebCore/platform/graphics/SimpleFontData.h17
-rw-r--r--WebCore/platform/graphics/android/FontPlatformData.h2
-rw-r--r--WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp7
-rw-r--r--WebCore/platform/graphics/android/GraphicsContextAndroid.cpp18
-rw-r--r--WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp260
-rw-r--r--WebCore/platform/graphics/cairo/FontCairo.cpp53
-rw-r--r--WebCore/platform/graphics/cairo/GradientCairo.cpp16
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp24
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h2
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp32
-rw-r--r--WebCore/platform/graphics/cairo/ImageCairo.cpp27
-rw-r--r--WebCore/platform/graphics/cairo/ImageSourceCairo.cpp2
-rw-r--r--WebCore/platform/graphics/cairo/PatternCairo.cpp13
-rw-r--r--WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp248
-rw-r--r--WebCore/platform/graphics/cg/ColorCG.cpp6
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp8
-rw-r--r--WebCore/platform/graphics/cg/ImageCG.cpp2
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp2
-rw-r--r--WebCore/platform/graphics/cg/PatternCG.cpp7
-rw-r--r--WebCore/platform/graphics/cg/TransformationMatrixCG.cpp184
-rw-r--r--WebCore/platform/graphics/chromium/ColorChromium.cpp30
-rw-r--r--WebCore/platform/graphics/chromium/ColorChromiumMac.mm132
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp47
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheLinux.cpp10
-rw-r--r--WebCore/platform/graphics/chromium/FontChromiumWin.cpp427
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp6
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp42
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp2
-rw-r--r--WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp15
-rw-r--r--WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h17
-rw-r--r--WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp104
-rw-r--r--WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h98
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.cpp480
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.h252
-rw-r--r--WebCore/platform/graphics/chromium/UniscribeHelper.cpp83
-rw-r--r--WebCore/platform/graphics/chromium/UniscribeHelper.h16
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformData.h2
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp54
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp59
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp113
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h48
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp27
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp25
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp25
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.mm3
-rw-r--r--WebCore/platform/graphics/mac/FontCacheMac.mm13
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.cpp17
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.h1
-rw-r--r--WebCore/platform/graphics/mac/FontMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/FontMacATSUI.mm1
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformData.h18
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformDataMac.mm23
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContextMac.mm5
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.h138
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm1540
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h58
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm253
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerProxy.h118
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.h57
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.mm219
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.h45
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.mm111
-rw-r--r--WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp (renamed from WebCore/platform/graphics/win/OpenTypeUtilities.cpp)25
-rw-r--r--WebCore/platform/graphics/opentype/OpenTypeUtilities.h (renamed from WebCore/platform/graphics/win/OpenTypeUtilities.h)2
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformDataQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp81
-rw-r--r--WebCore/platform/graphics/qt/GradientQt.cpp17
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp138
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp107
-rw-r--r--WebCore/platform/graphics/qt/ImageQt.cpp58
-rw-r--r--WebCore/platform/graphics/qt/ImageSourceQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp58
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h43
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp80
-rw-r--r--WebCore/platform/graphics/qt/PatternQt.cpp5
-rw-r--r--WebCore/platform/graphics/qt/TransformationMatrixQt.cpp167
-rw-r--r--WebCore/platform/graphics/skia/GradientSkia.cpp20
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextSkia.cpp53
-rw-r--r--WebCore/platform/graphics/skia/ImageBufferSkia.cpp23
-rw-r--r--WebCore/platform/graphics/skia/ImageSkia.cpp8
-rw-r--r--WebCore/platform/graphics/skia/ImageSourceSkia.cpp14
-rw-r--r--WebCore/platform/graphics/skia/PathSkia.cpp2
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp165
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.h47
-rw-r--r--WebCore/platform/graphics/skia/SkiaFontWin.cpp155
-rw-r--r--WebCore/platform/graphics/skia/SkiaFontWin.h35
-rw-r--r--WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp189
-rw-r--r--WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp56
-rw-r--r--WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h72
-rw-r--r--WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp4
-rw-r--r--WebCore/platform/graphics/transforms/MatrixTransformOperation.h19
-rw-r--r--WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp58
-rw-r--r--WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h71
-rw-r--r--WebCore/platform/graphics/transforms/RotateTransformOperation.cpp61
-rw-r--r--WebCore/platform/graphics/transforms/RotateTransformOperation.h29
-rw-r--r--WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp9
-rw-r--r--WebCore/platform/graphics/transforms/ScaleTransformOperation.h23
-rw-r--r--WebCore/platform/graphics/transforms/TransformOperation.h26
-rw-r--r--WebCore/platform/graphics/transforms/TransformOperations.h10
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.cpp1051
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.h285
-rw-r--r--WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp7
-rw-r--r--WebCore/platform/graphics/transforms/TranslateTransformOperation.h25
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp55
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp19
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.cpp14
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp2
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp14
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp2
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp12
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp147
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h27
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.cpp6
-rw-r--r--WebCore/platform/graphics/win/QTMovieWinTimer.cpp26
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformData.h64
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformDataWx.cpp30
-rw-r--r--WebCore/platform/graphics/wx/ImageSourceWx.cpp2
-rw-r--r--WebCore/platform/graphics/wx/ImageWx.cpp2
-rw-r--r--WebCore/platform/graphics/wx/SimpleFontDataWx.cpp24
-rw-r--r--WebCore/platform/graphics/wx/TransformationMatrixWx.cpp231
149 files changed, 8663 insertions, 2769 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
index 68863df..1d97632 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -53,6 +53,7 @@ BitmapImage::BitmapImage(ImageObserver* observer)
, m_repetitionsComplete(0)
, m_desiredFrameStartTime(0)
, m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
, m_animationFinished(false)
, m_allDataReceived(false)
, m_haveSize(false)
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h
index 110aec4..db05d1c 100644
--- a/WebCore/platform/graphics/BitmapImage.h
+++ b/WebCore/platform/graphics/BitmapImage.h
@@ -166,7 +166,7 @@ protected:
virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator);
#endif
virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
-#if PLATFORM(QT) || PLATFORM(WX)
+#if PLATFORM(WX)
virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
#endif
@@ -218,9 +218,18 @@ protected:
void invalidatePlatformData();
// Checks to see if the image is a 1x1 solid color. We optimize these images and just do a fill rect instead.
+ // This check should happen regardless whether m_checkedForSolidColor is already set, as the frame may have
+ // changed.
void checkForSolidColor();
- virtual bool mayFillWithSolidColor() const { return m_isSolidColor && m_currentFrame == 0; }
+ virtual bool mayFillWithSolidColor()
+ {
+ if (!m_checkedForSolidColor && frameCount() > 0) {
+ checkForSolidColor();
+ ASSERT(m_checkedForSolidColor);
+ }
+ return m_isSolidColor && m_currentFrame == 0;
+ }
virtual Color solidColor() const { return m_solidColor; }
ImageSource m_source;
@@ -242,6 +251,7 @@ protected:
Color m_solidColor; // If we're a 1x1 solid color, this is the color to use to fill.
bool m_isSolidColor; // Whether or not we are a 1x1 solid image.
+ bool m_checkedForSolidColor; // Whether we've checked the frame for solid color.
bool m_animationFinished; // Whether or not we've completed the entire animation.
diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp
index c7e11ee..e85ac00 100644
--- a/WebCore/platform/graphics/Color.cpp
+++ b/WebCore/platform/graphics/Color.cpp
@@ -116,6 +116,15 @@ RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double
static_cast<int>(alpha * scaleFactor));
}
+RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a)
+{
+ double colors = 1 - k;
+ int r = static_cast<int>(nextafter(256, 0) * (colors * (1 - c)));
+ int g = static_cast<int>(nextafter(256, 0) * (colors * (1 - m)));
+ int b = static_cast<int>(nextafter(256, 0) * (colors * (1 - y)));
+ return makeRGBA(r, g, b, static_cast<float>(nextafter(256, 0) * a));
+}
+
// originally moved here from the CSS parser
bool Color::parseHexColor(const String& name, RGBA32& rgb)
{
@@ -312,4 +321,34 @@ void Color::getRGBA(double& r, double& g, double& b, double& a) const
a = alpha() / 255.0;
}
+Color colorFromPremultipliedARGB(unsigned pixelColor)
+{
+ RGBA32 rgba;
+
+ if (unsigned alpha = (pixelColor & 0xFF000000) >> 24) {
+ rgba = makeRGBA(((pixelColor & 0x00FF0000) >> 16) * 255 / alpha,
+ ((pixelColor & 0x0000FF00) >> 8) * 255 / alpha,
+ (pixelColor & 0x000000FF) * 255 / alpha,
+ alpha);
+ } else
+ rgba = pixelColor;
+
+ return Color(rgba);
+}
+
+unsigned premultipliedARGBFromColor(const Color& color)
+{
+ unsigned pixelColor;
+
+ if (unsigned alpha = color.alpha()) {
+ pixelColor = alpha << 24 |
+ ((color.red() * alpha + 254) / 255) << 16 |
+ ((color.green() * alpha + 254) / 255) << 8 |
+ ((color.blue() * alpha + 254) / 255);
+ } else
+ pixelColor = color.rgb();
+
+ return pixelColor;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h
index 61fc74c..3c889f9 100644
--- a/WebCore/platform/graphics/Color.h
+++ b/WebCore/platform/graphics/Color.h
@@ -60,6 +60,7 @@ RGBA32 makeRGBA(int r, int g, int b, int a);
RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha);
RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a);
RGBA32 makeRGBAFromHSLA(double h, double s, double l, double a);
+RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a);
int differenceSquared(const Color&, const Color&);
@@ -71,6 +72,8 @@ public:
Color(int r, int g, int b, int a) : m_color(makeRGBA(r, g, b, a)), m_valid(true) { }
// Color is currently limited to 32bit RGBA, perhaps some day we'll support better colors
Color(float r, float g, float b, float a) : m_color(makeRGBA32FromFloats(r, g, b, a)), m_valid(true) { }
+ // Creates a new color from the specific CMYK and alpha values.
+ Color(float c, float m, float y, float k, float a) : m_color(makeRGBAFromCMYKA(c, m, y, k, a)), m_valid(true) { }
explicit Color(const String&);
explicit Color(const char*);
@@ -146,9 +149,11 @@ inline bool operator!=(const Color& a, const Color& b)
}
Color focusRingColor();
+Color colorFromPremultipliedARGB(unsigned);
+unsigned premultipliedARGBFromColor(const Color&);
#if PLATFORM(CG)
-CGColorRef cgColor(const Color&);
+CGColorRef createCGColor(const Color&);
#endif
} // namespace WebCore
diff --git a/WebCore/platform/graphics/FloatPoint.cpp b/WebCore/platform/graphics/FloatPoint.cpp
index 564ea86..7765ba9 100644
--- a/WebCore/platform/graphics/FloatPoint.cpp
+++ b/WebCore/platform/graphics/FloatPoint.cpp
@@ -40,7 +40,7 @@ FloatPoint::FloatPoint(const IntPoint& p) : m_x(p.x()), m_y(p.y())
FloatPoint FloatPoint::matrixTransform(const TransformationMatrix& transform) const
{
double newX, newY;
- transform.map(static_cast<double>(m_x), static_cast<double>(m_y), &newX, &newY);
+ transform.map(static_cast<double>(m_x), static_cast<double>(m_y), newX, newY);
return narrowPrecision(newX, newY);
}
diff --git a/WebCore/platform/graphics/FloatPoint3D.cpp b/WebCore/platform/graphics/FloatPoint3D.cpp
index e3ba422..8c21ef3 100644
--- a/WebCore/platform/graphics/FloatPoint3D.cpp
+++ b/WebCore/platform/graphics/FloatPoint3D.cpp
@@ -21,7 +21,6 @@
#include "config.h"
-#if ENABLE(SVG)
#include <math.h>
#include "FloatPoint.h"
#include "FloatPoint3D.h"
@@ -62,4 +61,3 @@ void FloatPoint3D::normalize()
} // namespace WebCore
-#endif // ENABLE(SVG)
diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h
index 184e914..2e71ddd 100644
--- a/WebCore/platform/graphics/FloatPoint3D.h
+++ b/WebCore/platform/graphics/FloatPoint3D.h
@@ -22,8 +22,6 @@
#ifndef FloatPoint3D_h
#define FloatPoint3D_h
-#if ENABLE(SVG)
-
namespace WebCore {
class FloatPoint;
@@ -53,6 +51,4 @@ private:
} // namespace WebCore
-#endif // ENABLE(SVG)
-
#endif // FloatPoint3D_h
diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp
index 2d219be..130313d 100644
--- a/WebCore/platform/graphics/FontCache.cpp
+++ b/WebCore/platform/graphics/FontCache.cpp
@@ -139,8 +139,13 @@ static const AtomicString& alternateFamilyName(const AtomicString& familyName)
DEFINE_STATIC_LOCAL(AtomicString, courierNew, ("Courier New"));
if (equalIgnoringCase(familyName, courier))
return courierNew;
+#if !PLATFORM(WIN_OS)
+ // 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.
if (equalIgnoringCase(familyName, courierNew))
return courier;
+#endif
// Alias Times and Times New Roman.
DEFINE_STATIC_LOCAL(AtomicString, times, ("Times"));
@@ -158,6 +163,21 @@ static const AtomicString& alternateFamilyName(const AtomicString& familyName)
if (equalIgnoringCase(familyName, helvetica))
return arial;
+#if PLATFORM(WIN_OS)
+ // 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"));
+ DEFINE_STATIC_LOCAL(AtomicString, microsoftSans, ("Microsoft Sans Serif"));
+ if (equalIgnoringCase(familyName, msSans))
+ return microsoftSans;
+
+ // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no
+ // 'Microsoft Sans Serif-equivalent' for Serif.
+ static AtomicString msSerif("MS Serif");
+ if (equalIgnoringCase(familyName, msSerif))
+ return timesNewRoman;
+#endif
+
return emptyAtom;
}
@@ -216,7 +236,7 @@ struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
static const bool needsDestruction = true;
static const FontPlatformData& emptyValue()
{
- DEFINE_STATIC_LOCAL(FontPlatformData, key, ());
+ DEFINE_STATIC_LOCAL(FontPlatformData, key, (0.f, false, false));
return key;
}
static void constructDeletedValue(FontPlatformData& slot)
@@ -304,7 +324,7 @@ void FontCache::purgeInactiveFontData(int count)
}
Vector<FontPlatformDataCacheKey> keysToRemove;
- keysToRemove.reserveCapacity(gFontPlatformDataCache->size());
+ keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size());
FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end();
for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) {
if (platformData->second && !gFontDataCache->contains(*platformData->second))
@@ -424,7 +444,7 @@ void FontCache::invalidate()
Vector<RefPtr<FontSelector> > clients;
size_t numClients = gClients->size();
- clients.reserveCapacity(numClients);
+ clients.reserveInitialCapacity(numClients);
HashSet<FontSelector*>::iterator end = gClients->end();
for (HashSet<FontSelector*>::iterator it = gClients->begin(); it != end; ++it)
clients.append(*it);
diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h
index fdb306f..dcda419 100644
--- a/WebCore/platform/graphics/GlyphBuffer.h
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -37,7 +37,7 @@
#include <ApplicationServices/ApplicationServices.h>
#endif
-#if PLATFORM(CAIRO)
+#if PLATFORM(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__))
#include <cairo.h>
#endif
diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
index 6b9d23d..bd838de 100644
--- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
@@ -218,6 +218,7 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu
}
haveGlyphs |= pageToFill->fill(from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), range.fontData());
if (scratchPage) {
+ ASSERT(to <= static_cast<int>(GlyphPage::size));
for (int j = from; j < to; j++) {
if (!m_page->m_glyphs[j].glyph && pageToFill->m_glyphs[j].glyph)
m_page->m_glyphs[j] = pageToFill->m_glyphs[j];
diff --git a/WebCore/platform/graphics/GlyphWidthMap.cpp b/WebCore/platform/graphics/GlyphWidthMap.cpp
index 6e8d68d..43cab65 100644
--- a/WebCore/platform/graphics/GlyphWidthMap.cpp
+++ b/WebCore/platform/graphics/GlyphWidthMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 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
@@ -29,43 +29,22 @@
#include "config.h"
#include "GlyphWidthMap.h"
-namespace WebCore
-{
-
-float GlyphWidthMap::widthForGlyph(Glyph g)
-{
- unsigned pageNumber = (g / GlyphWidthPage::size);
- GlyphWidthPage* page = locatePage(pageNumber);
- if (page)
- return page->widthForGlyph(g);
- return cGlyphWidthUnknown;
-}
-
-void GlyphWidthMap::setWidthForGlyph(Glyph glyph, float width)
-{
- unsigned pageNumber = (glyph / GlyphWidthPage::size);
- GlyphWidthPage* page = locatePage(pageNumber);
- if (page)
- page->setWidthForGlyph(glyph, width);
-}
+namespace WebCore {
-inline GlyphWidthMap::GlyphWidthPage* GlyphWidthMap::locatePage(unsigned pageNumber)
+GlyphWidthMap::GlyphWidthPage* GlyphWidthMap::locatePageSlowCase(unsigned pageNumber)
{
GlyphWidthPage* page;
if (pageNumber == 0) {
- if (m_filledPrimaryPage)
- return &m_primaryPage;
+ ASSERT(!m_filledPrimaryPage);
page = &m_primaryPage;
m_filledPrimaryPage = true;
} else {
if (m_pages) {
- GlyphWidthPage* result = m_pages->get(pageNumber);
- if (result)
- return result;
- }
+ if ((page = m_pages->get(pageNumber)))
+ return page;
+ } else
+ m_pages.set(new HashMap<int, GlyphWidthPage*>);
page = new GlyphWidthPage;
- if (!m_pages)
- m_pages = new HashMap<int, GlyphWidthPage*>;
m_pages->set(pageNumber, page);
}
diff --git a/WebCore/platform/graphics/GlyphWidthMap.h b/WebCore/platform/graphics/GlyphWidthMap.h
index 1633769..e194ecf 100644
--- a/WebCore/platform/graphics/GlyphWidthMap.h
+++ b/WebCore/platform/graphics/GlyphWidthMap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 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
@@ -29,9 +29,9 @@
#ifndef GlyphWidthMap_h
#define GlyphWidthMap_h
-#include <wtf/unicode/Unicode.h>
-#include <wtf/Noncopyable.h>
#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/unicode/Unicode.h>
namespace WebCore {
@@ -41,34 +41,49 @@ const float cGlyphWidthUnknown = -1;
class GlyphWidthMap : Noncopyable {
public:
- GlyphWidthMap() : m_filledPrimaryPage(false), m_pages(0) {}
- ~GlyphWidthMap() { if (m_pages) { deleteAllValues(*m_pages); delete m_pages; } }
+ GlyphWidthMap() : m_filledPrimaryPage(false) { }
+ ~GlyphWidthMap() { if (m_pages) { deleteAllValues(*m_pages); } }
+
+ float widthForGlyph(Glyph glyph)
+ {
+ return locatePage(glyph / GlyphWidthPage::size)->widthForGlyph(glyph);
+ }
- float widthForGlyph(Glyph);
- void setWidthForGlyph(Glyph, float);
+ void setWidthForGlyph(Glyph glyph, float width)
+ {
+ locatePage(glyph / GlyphWidthPage::size)->setWidthForGlyph(glyph, width);
+ }
private:
struct GlyphWidthPage {
static const size_t size = 256; // Usually covers Latin-1 in a single page.
float m_widths[size];
- float widthForGlyph(Glyph g) const { return m_widths[g % size]; }
- void setWidthForGlyph(Glyph g, float w)
+ float widthForGlyph(Glyph glyph) const { return m_widths[glyph % size]; }
+ void setWidthForGlyph(Glyph glyph, float width)
{
- setWidthForIndex(g % size, w);
+ setWidthForIndex(glyph % size, width);
}
- void setWidthForIndex(unsigned index, float w)
+ void setWidthForIndex(unsigned index, float width)
{
- m_widths[index] = w;
+ m_widths[index] = width;
}
};
- GlyphWidthPage* locatePage(unsigned page);
+ GlyphWidthPage* locatePage(unsigned pageNumber)
+ {
+ if (!pageNumber && m_filledPrimaryPage)
+ return &m_primaryPage;
+ return locatePageSlowCase(pageNumber);
+ }
+
+ GlyphWidthPage* locatePageSlowCase(unsigned pageNumber);
bool m_filledPrimaryPage;
GlyphWidthPage m_primaryPage; // We optimize for the page that contains glyph indices 0-255.
- HashMap<int, GlyphWidthPage*>* m_pages;
+ OwnPtr<HashMap<int, GlyphWidthPage*> > m_pages;
};
}
+
#endif
diff --git a/WebCore/platform/graphics/Gradient.cpp b/WebCore/platform/graphics/Gradient.cpp
index 2e6a5d2..24e8bbf 100644
--- a/WebCore/platform/graphics/Gradient.cpp
+++ b/WebCore/platform/graphics/Gradient.cpp
@@ -39,6 +39,7 @@ Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1)
, m_r1(0)
, m_stopsSorted(false)
, m_lastStop(0)
+ , m_spreadMethod(SpreadMethodPad)
{
platformInit();
}
@@ -146,4 +147,11 @@ int Gradient::findStop(float value) const
return m_lastStop;
}
+void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
+{
+ // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set.
+ ASSERT(m_gradient == 0);
+ m_spreadMethod = spreadMethod;
+}
+
} //namespace
diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h
index 00ef2b6..764deee 100644
--- a/WebCore/platform/graphics/Gradient.h
+++ b/WebCore/platform/graphics/Gradient.h
@@ -29,6 +29,8 @@
#include "FloatPoint.h"
#include "Generator.h"
+#include "GraphicsTypes.h"
+#include "TransformationMatrix.h"
#include <wtf/PassRefPtr.h>
#include <wtf/Vector.h>
@@ -93,6 +95,12 @@ namespace WebCore {
void setStopsSorted(bool s) { m_stopsSorted = s; }
+ void setSpreadMethod(GradientSpreadMethod);
+ GradientSpreadMethod spreadMethod() { return m_spreadMethod; }
+ void setGradientSpaceTransform(const TransformationMatrix& gradientSpaceTransformation) { m_gradientSpaceTransformation = gradientSpaceTransformation; }
+ // Qt and CG transform the gradient at draw time
+ TransformationMatrix gradientSpaceTransform() { return m_gradientSpaceTransformation; }
+
virtual void fill(GraphicsContext*, const FloatRect&);
private:
@@ -112,6 +120,8 @@ namespace WebCore {
mutable Vector<ColorStop> m_stops;
mutable bool m_stopsSorted;
mutable int m_lastStop;
+ GradientSpreadMethod m_spreadMethod;
+ TransformationMatrix m_gradientSpaceTransformation;
PlatformGradient m_gradient;
};
diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp
index 8426011..8cad794 100644
--- a/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -128,6 +128,11 @@ void GraphicsContext::setStrokeColor(const Color& color)
setPlatformStrokeColor(color);
}
+ColorSpace GraphicsContext::strokeColorSpace() const
+{
+ return m_common->state.strokeColorSpace;
+}
+
void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
{
m_common->state.shadowSize = size;
@@ -178,16 +183,6 @@ void GraphicsContext::setFillRule(WindRule fillRule)
m_common->state.fillRule = fillRule;
}
-GradientSpreadMethod GraphicsContext::spreadMethod() const
-{
- return m_common->state.spreadMethod;
-}
-
-void GraphicsContext::setSpreadMethod(GradientSpreadMethod spreadMethod)
-{
- m_common->state.spreadMethod = spreadMethod;
-}
-
void GraphicsContext::setFillColor(const Color& color)
{
m_common->state.fillColorSpace = SolidColorSpace;
@@ -255,6 +250,31 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
m_common->state.fillGradient = gradient;
}
+Gradient* GraphicsContext::fillGradient() const
+{
+ return m_common->state.fillGradient.get();
+}
+
+ColorSpace GraphicsContext::fillColorSpace() const
+{
+ return m_common->state.fillColorSpace;
+}
+
+Gradient* GraphicsContext::strokeGradient() const
+{
+ return m_common->state.strokeGradient.get();
+}
+
+Pattern* GraphicsContext::fillPattern() const
+{
+ return m_common->state.fillPattern.get();
+}
+
+Pattern* GraphicsContext::strokePattern() const
+{
+ return m_common->state.strokePattern.get();
+}
+
void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms)
{
m_common->state.shadowsIgnoreTransforms = ignoreTransforms;
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index c27f38f..7c1c4b0 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -123,6 +123,18 @@ namespace WebCore {
DashedStroke
};
+// FIXME: This is a place-holder until we decide to add
+// real color space support to WebCore. At that time, ColorSpace will be a
+// class and instances will be held off of Colors. There will be
+// special singleton Gradient and Pattern color spaces to mark when
+// a fill or stroke is using a gradient or pattern instead of a solid color.
+// https://bugs.webkit.org/show_bug.cgi?id=20558
+ enum ColorSpace {
+ SolidColorSpace,
+ PatternColorSpace,
+ GradientColorSpace
+ };
+
enum InterpolationQuality {
InterpolationDefault,
InterpolationNone,
@@ -131,14 +143,6 @@ namespace WebCore {
InterpolationHigh
};
- // FIXME: Currently these constants have to match the values used in the SVG
- // DOM API. That's a mistake. We need to make cut that dependency.
- enum GradientSpreadMethod {
- SpreadMethodPad = 1,
- SpreadMethodReflect = 2,
- SpreadMethodRepeat = 3
- };
-
class GraphicsContext : Noncopyable {
public:
GraphicsContext(PlatformGraphicsContext*);
@@ -152,17 +156,28 @@ namespace WebCore {
void setStrokeStyle(const StrokeStyle& style);
Color strokeColor() const;
void setStrokeColor(const Color&);
+
+ ColorSpace strokeColorSpace() const;
+
void setStrokePattern(PassRefPtr<Pattern>);
+ Pattern* strokePattern() const;
+
void setStrokeGradient(PassRefPtr<Gradient>);
+ Gradient* strokeGradient() const;
WindRule fillRule() const;
void setFillRule(WindRule);
- GradientSpreadMethod spreadMethod() const;
- void setSpreadMethod(GradientSpreadMethod);
Color fillColor() const;
void setFillColor(const Color&);
+
void setFillPattern(PassRefPtr<Pattern>);
+ Pattern* fillPattern() const;
+
void setFillGradient(PassRefPtr<Gradient>);
+ Gradient* fillGradient() const;
+
+ ColorSpace fillColorSpace() const;
+
void setShadowsIgnoreTransforms(bool);
void setShouldAntialias(bool);
@@ -206,6 +221,9 @@ namespace WebCore {
void restore();
// These draw methods will do both stroking and filling.
+ // FIXME: ...except drawRect(), which fills properly but always strokes
+ // using a 1-pixel stroke inset from the rect borders (of the correct
+ // stroke color).
void drawRect(const IntRect&);
void drawLine(const IntPoint&, const IntPoint&);
void drawEllipse(const IntRect&);
@@ -402,3 +420,4 @@ namespace WebCore {
} // namespace WebCore
#endif // GraphicsContext_h
+
diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h
index 87123eb..98baab1 100644
--- a/WebCore/platform/graphics/GraphicsContextPrivate.h
+++ b/WebCore/platform/graphics/GraphicsContextPrivate.h
@@ -33,18 +33,6 @@
namespace WebCore {
-// FIXME: This is a place-holder until we decide to add
-// real color space support to WebCore. At that time, ColorSpace will be a
-// class and instances will be held off of Colors. There will be
-// special singleton Gradient and Pattern color spaces to mark when
-// a fill or stroke is using a gradient or pattern instead of a solid color.
-// https://bugs.webkit.org/show_bug.cgi?id=20558
- enum ColorSpace {
- SolidColorSpace,
- PatternColorSpace,
- GradientColorSpace
- };
-
struct GraphicsContextState {
GraphicsContextState()
: textDrawingMode(cTextFill)
@@ -80,7 +68,6 @@ namespace WebCore {
RefPtr<Pattern> strokePattern;
WindRule fillRule;
- GradientSpreadMethod spreadMethod;
ColorSpace fillColorSpace;
Color fillColor;
RefPtr<Gradient> fillGradient;
diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp
new file mode 100644
index 0000000..0c442a2
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsLayer.cpp
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayer.h"
+
+#include "FloatPoint.h"
+#include "RotateTransformOperation.h"
+#include "TextStream.h"
+
+namespace WebCore {
+
+void GraphicsLayer::FloatValue::set(float key, float value, const TimingFunction* timingFunction)
+{
+ m_key = key;
+ m_value = value;
+ if (timingFunction != m_timingFunction) {
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ else
+ m_timingFunction.clear();
+ }
+}
+
+void GraphicsLayer::TransformValue::set(float key, const TransformOperations* value, const TimingFunction* timingFunction)
+{
+ m_key = key;
+ if (value != m_value) {
+ if (value)
+ m_value.set(new TransformOperations(*value));
+ else
+ m_value.clear();
+ }
+ if (timingFunction != m_timingFunction) {
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ else
+ m_timingFunction.clear();
+ }
+}
+
+void GraphicsLayer::FloatValueList::insert(float key, float value, const TimingFunction* timingFunction)
+{
+ for (size_t i = 0; i < m_values.size(); ++i) {
+ FloatValue& curFloatValue = m_values[i];
+ if (curFloatValue.key() == key) {
+ curFloatValue.set(key, value, timingFunction);
+ return;
+ }
+ if (curFloatValue.key() > key) {
+ // insert before
+ m_values.insert(i, FloatValue(key, value, timingFunction));
+ return;
+ }
+ }
+
+ // append
+ m_values.append(FloatValue(key, value, timingFunction));
+}
+
+void GraphicsLayer::TransformValueList::insert(float key, const TransformOperations* value, const TimingFunction* timingFunction)
+{
+ for (size_t i = 0; i < m_values.size(); ++i) {
+ TransformValue& curTransValue = m_values[i];
+ if (curTransValue.key() == key) {
+ curTransValue.set(key, value, timingFunction);
+ return;
+ }
+ if (curTransValue.key() > key) {
+ // insert before
+ m_values.insert(i, TransformValue(key, value, timingFunction));
+ return;
+ }
+ }
+
+ // append
+ m_values.append(TransformValue(key, value, timingFunction));
+}
+
+// An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
+// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is
+// true if the rotation between any two keyframes is >= 180 degrees.
+void GraphicsLayer::TransformValueList::makeFunctionList(FunctionList& list, bool& isValid, bool& hasBigRotation) const
+{
+ list.clear();
+ isValid = false;
+ hasBigRotation = false;
+
+ if (m_values.size() < 2)
+ return;
+
+ // empty transforms match anything, so find the first non-empty entry as the reference
+ size_t firstIndex = 0;
+ for ( ; firstIndex < m_values.size(); ++firstIndex) {
+ if (m_values[firstIndex].value()->operations().size() > 0)
+ break;
+ }
+
+ if (firstIndex >= m_values.size())
+ return;
+
+ const TransformOperations* firstVal = m_values[firstIndex].value();
+
+ // see if the keyframes are valid
+ for (size_t i = firstIndex + 1; i < m_values.size(); ++i) {
+ const TransformOperations* val = m_values[i].value();
+
+ // a null transform matches anything
+ if (val->operations().isEmpty())
+ continue;
+
+ if (firstVal->operations().size() != val->operations().size())
+ return;
+
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ if (!firstVal->operations().at(j)->isSameType(*val->operations().at(j)))
+ return;
+ }
+ }
+
+ // keyframes are valid, fill in the list
+ isValid = true;
+
+ double lastRotAngle = 0.0;
+ double maxRotAngle = -1.0;
+
+ list.resize(firstVal->operations().size());
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType();
+ list[j] = type;
+
+ // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
+ if (type == TransformOperation::ROTATE_X ||
+ type == TransformOperation::ROTATE_Y ||
+ type == TransformOperation::ROTATE_Z ||
+ type == TransformOperation::ROTATE_3D) {
+ lastRotAngle = static_cast<RotateTransformOperation*>(firstVal->operations().at(j).get())->angle();
+
+ if (maxRotAngle < 0)
+ maxRotAngle = fabs(lastRotAngle);
+
+ for (size_t i = firstIndex + 1; i < m_values.size(); ++i) {
+ const TransformOperations* val = m_values[i].value();
+ double rotAngle = val->operations().isEmpty() ? 0 : (static_cast<RotateTransformOperation*>(val->operations().at(j).get())->angle());
+ double diffAngle = fabs(rotAngle - lastRotAngle);
+ if (diffAngle > maxRotAngle)
+ maxRotAngle = diffAngle;
+ lastRotAngle = rotAngle;
+ }
+ }
+ }
+
+ hasBigRotation = maxRotAngle >= 180.0;
+}
+
+GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
+ : m_client(client)
+ , m_anchorPoint(0.5f, 0.5f, 0)
+ , m_opacity(1)
+#ifndef NDEBUG
+ , m_zPosition(0)
+#endif
+ , m_backgroundColorSet(false)
+ , m_contentsOpaque(false)
+ , m_preserves3D(false)
+ , m_backfaceVisibility(true)
+ , m_usingTiledLayer(false)
+ , m_masksToBounds(false)
+ , m_drawsContent(false)
+ , m_paintingPhase(GraphicsLayerPaintAllMask)
+ , m_parent(0)
+#ifndef NDEBUG
+ , m_repaintCount(0)
+#endif
+{
+}
+
+GraphicsLayer::~GraphicsLayer()
+{
+ removeAllAnimations();
+
+ removeAllChildren();
+ removeFromParent();
+}
+
+void GraphicsLayer::addChild(GraphicsLayer* childLayer)
+{
+ ASSERT(childLayer != this);
+
+ if (childLayer->parent())
+ childLayer->removeFromParent();
+
+ childLayer->setParent(this);
+ m_children.append(childLayer);
+}
+
+void GraphicsLayer::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ ASSERT(childLayer != this);
+
+ if (childLayer->parent())
+ childLayer->removeFromParent();
+
+ childLayer->setParent(this);
+ m_children.insert(index, childLayer);
+}
+
+void GraphicsLayer::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ ASSERT(childLayer != this);
+ childLayer->removeFromParent();
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i, childLayer);
+ found = true;
+ break;
+ }
+ }
+
+ childLayer->setParent(this);
+
+ if (!found)
+ m_children.append(childLayer);
+}
+
+void GraphicsLayer::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ childLayer->removeFromParent();
+ ASSERT(childLayer != this);
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i+1, childLayer);
+ found = true;
+ break;
+ }
+ }
+
+ childLayer->setParent(this);
+
+ if (!found)
+ m_children.append(childLayer);
+}
+
+bool GraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ ASSERT(!newChild->parent());
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (oldChild == m_children[i]) {
+ m_children[i] = newChild;
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ oldChild->setParent(0);
+
+ newChild->removeFromParent();
+ newChild->setParent(this);
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayer::removeAllChildren()
+{
+ while (m_children.size()) {
+ GraphicsLayer* curLayer = m_children[0];
+ ASSERT(curLayer->parent());
+ curLayer->removeFromParent();
+ }
+}
+
+void GraphicsLayer::removeFromParent()
+{
+ if (m_parent) {
+ unsigned i;
+ for (i = 0; i < m_parent->m_children.size(); i++) {
+ if (this == m_parent->m_children[i]) {
+ m_parent->m_children.remove(i);
+ break;
+ }
+ }
+
+ setParent(0);
+ }
+}
+
+void GraphicsLayer::setBackgroundColor(const Color& inColor, const Animation*, double /*beginTime*/)
+{
+ m_backgroundColor = inColor;
+ m_backgroundColorSet = true;
+}
+
+void GraphicsLayer::clearBackgroundColor()
+{
+ m_backgroundColor = Color();
+ m_backgroundColorSet = false;
+}
+
+bool GraphicsLayer::setOpacity(float opacity, const Animation*, double)
+{
+ m_opacity = opacity;
+ return false; // not animating
+}
+
+void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip)
+{
+ m_client->paintContents(this, context, m_paintingPhase, clip);
+}
+
+String GraphicsLayer::propertyIdToString(AnimatedPropertyID property)
+{
+ switch (property) {
+ case AnimatedPropertyWebkitTransform:
+ return "transform";
+ case AnimatedPropertyOpacity:
+ return "opacity";
+ case AnimatedPropertyBackgroundColor:
+ return "backgroundColor";
+ case AnimatedPropertyInvalid:
+ ASSERT_NOT_REACHED();
+ }
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+int GraphicsLayer::findAnimationEntry(AnimatedPropertyID property, short index) const
+{
+ for (size_t i = 0; i < m_animations.size(); ++i) {
+ if (m_animations[i].matches(property, index))
+ return static_cast<int>(i);
+ }
+ return -1;
+}
+
+void GraphicsLayer::addAnimationEntry(AnimatedPropertyID property, short index, bool isTransition, const Animation* transition)
+{
+ int i = findAnimationEntry(property, index);
+
+ if (i >= 0)
+ m_animations[i].reset(transition, isTransition);
+ else
+ m_animations.append(AnimationEntry(transition, property, index, isTransition));
+}
+
+void GraphicsLayer::removeAllAnimations()
+{
+ size_t size = m_animations.size();
+ for (size_t i = 0; i < size; ++i)
+ removeAnimation(0, true);
+}
+
+void GraphicsLayer::removeAllAnimationsForProperty(AnimatedPropertyID property)
+{
+ for (short j = 0; ; ++j) {
+ int i = findAnimationEntry(property, j);
+ if (i < 0)
+ break;
+ removeAnimation(i, false);
+ }
+}
+
+void GraphicsLayer::removeFinishedAnimations(const String& name, int /*index*/, bool reset)
+{
+ size_t size = m_animations.size();
+ for (size_t i = 0; i < size; ) {
+ AnimationEntry& anim = m_animations[i];
+ if (!anim.isTransition() && anim.animation()->name() == name) {
+ removeAnimation(i, reset);
+ --size;
+ } else
+ ++i;
+ }
+}
+
+void GraphicsLayer::removeFinishedTransitions(AnimatedPropertyID property)
+{
+ size_t size = m_animations.size();
+ for (size_t i = 0; i < size; ) {
+ AnimationEntry& anim = m_animations[i];
+ if (anim.isTransition() && property == anim.property()) {
+ removeAnimation(i, false);
+ --size;
+ } else
+ ++i;
+ }
+}
+
+void GraphicsLayer::suspendAnimations()
+{
+}
+
+void GraphicsLayer::resumeAnimations()
+{
+}
+
+#ifndef NDEBUG
+void GraphicsLayer::updateDebugIndicators()
+{
+ if (GraphicsLayer::showDebugBorders()) {
+ if (drawsContent()) {
+ if (m_usingTiledLayer)
+ setDebugBorder(Color(0, 255, 0, 204), 2.0f); // tiled layer: green
+ else
+ setDebugBorder(Color(255, 0, 0, 204), 2.0f); // normal layer: red
+ } else if (masksToBounds()) {
+ setDebugBorder(Color(128, 255, 255, 178), 2.0f); // masking layer: pale blue
+ if (GraphicsLayer::showDebugBorders())
+ setDebugBackgroundColor(Color(128, 255, 255, 52));
+ } else
+ setDebugBorder(Color(255, 255, 0, 204), 2.0f); // container: yellow
+ }
+}
+
+void GraphicsLayer::setZPosition(float position)
+{
+ m_zPosition = position;
+}
+#endif
+
+static void writeIndent(TextStream& ts, int indent)
+{
+ for (int i = 0; i != indent; ++i)
+ ts << " ";
+}
+
+void GraphicsLayer::dumpLayer(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent);
+ ts << "(" << "GraphicsLayer" << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this));
+ ts << " \"" << m_name << "\"\n";
+ dumpProperties(ts, indent);
+ writeIndent(ts, indent);
+ ts << ")\n";
+}
+
+void GraphicsLayer::dumpProperties(TextStream& ts, int indent) const
+{
+ writeIndent(ts, indent + 1);
+ ts << "(position " << m_position.x() << " " << m_position.y() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(anchor " << m_anchorPoint.x() << " " << m_anchorPoint.y() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(bounds " << m_size.width() << " " << m_size.height() << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(opacity " << m_opacity << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(usingTiledLayer " << m_usingTiledLayer << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(m_preserves3D " << m_preserves3D << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(drawsContent " << m_drawsContent << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(m_backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(client ";
+ if (m_client)
+ ts << static_cast<void*>(m_client);
+ else
+ ts << "none";
+ ts << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(backgroundColor ";
+ if (!m_backgroundColorSet)
+ ts << "none";
+ else
+ ts << m_backgroundColor.name();
+ ts << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(transform ";
+ if (m_transform.isIdentity())
+ ts << "identity";
+ else {
+ ts << "[" << m_transform.m11() << " " << m_transform.m12() << " " << m_transform.m13() << " " << m_transform.m14() << "] ";
+ ts << "[" << m_transform.m21() << " " << m_transform.m22() << " " << m_transform.m23() << " " << m_transform.m24() << "] ";
+ ts << "[" << m_transform.m31() << " " << m_transform.m32() << " " << m_transform.m33() << " " << m_transform.m34() << "] ";
+ ts << "[" << m_transform.m41() << " " << m_transform.m42() << " " << m_transform.m43() << " " << m_transform.m44() << "]";
+ }
+ ts << ")\n";
+
+ writeIndent(ts, indent + 1);
+ ts << "(childrenTransform ";
+ if (m_childrenTransform.isIdentity())
+ ts << "identity";
+ else {
+ ts << "[" << m_childrenTransform.m11() << " " << m_childrenTransform.m12() << " " << m_childrenTransform.m13() << " " << m_childrenTransform.m14() << "] ";
+ ts << "[" << m_childrenTransform.m21() << " " << m_childrenTransform.m22() << " " << m_childrenTransform.m23() << " " << m_childrenTransform.m24() << "] ";
+ ts << "[" << m_childrenTransform.m31() << " " << m_childrenTransform.m32() << " " << m_childrenTransform.m33() << " " << m_childrenTransform.m34() << "] ";
+ ts << "[" << m_childrenTransform.m41() << " " << m_childrenTransform.m42() << " " << m_childrenTransform.m43() << " " << m_childrenTransform.m44() << "]";
+ }
+ ts << ")\n";
+
+ 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
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h
new file mode 100644
index 0000000..f928ce8
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsLayer.h
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsLayer_h
+#define GraphicsLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Animation.h"
+#include "Color.h"
+#include "FloatPoint.h"
+#include "FloatPoint3D.h"
+#include "FloatSize.h"
+#include "GraphicsLayerClient.h"
+#include "TransformationMatrix.h"
+#include "TransformOperations.h"
+#include <wtf/OwnPtr.h>
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class WebLayer;
+@class CALayer;
+typedef WebLayer PlatformLayer;
+typedef CALayer* NativeLayer;
+#else
+typedef void* PlatformLayer;
+typedef void* NativeLayer;
+#endif
+#else
+typedef void* PlatformLayer;
+typedef void* NativeLayer;
+#endif
+
+namespace WebCore {
+
+class FloatPoint3D;
+class GraphicsContext;
+class Image;
+class TextStream;
+class TimingFunction;
+
+// GraphicsLayer is an abstraction for a rendering surface with backing store,
+// which may have associated transformation and animations.
+
+class GraphicsLayer {
+public:
+ // Used to store one float value of a keyframe animation.
+ class FloatValue {
+ public:
+ FloatValue(float key, float value, const TimingFunction* timingFunction = 0)
+ : m_key(key), m_value(value), m_timingFunction(0)
+ {
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ }
+
+ FloatValue(const FloatValue& other)
+ : m_key(other.key()), m_value(other.value()), m_timingFunction(0)
+ {
+ if (other.timingFunction())
+ m_timingFunction.set(new TimingFunction(*other.timingFunction()));
+ }
+
+ const FloatValue& operator=(const FloatValue& other)
+ {
+ if (&other != this)
+ set(other.key(), other.value(), other.timingFunction());
+ return *this;
+ }
+
+ void set(float key, float value, const TimingFunction*);
+
+ float key() const { return m_key; }
+ float value() const { return m_value; }
+ const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
+
+ private:
+ float m_key;
+ float m_value;
+ OwnPtr<TimingFunction> m_timingFunction;
+ };
+
+
+ class FloatValueList {
+ public:
+ void insert(float key, float value, const TimingFunction* timingFunction);
+
+ size_t size() const { return m_values.size(); }
+ const FloatValue& at(size_t i) const { return m_values.at(i); }
+ const Vector<FloatValue>& values() const { return m_values; }
+
+ private:
+ Vector<FloatValue> m_values;
+ };
+
+ // Used to store one transform in a keyframe list.
+ class TransformValue {
+ public:
+ TransformValue(float key = NAN, const TransformOperations* value = 0, const TimingFunction* timingFunction = 0)
+ : m_key(key)
+ {
+ if (value)
+ m_value.set(new TransformOperations(*value));
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ }
+
+ TransformValue(const TransformValue& other)
+ : m_key(other.key())
+ {
+ if (other.value())
+ m_value.set(new TransformOperations(*other.value()));
+ if (other.timingFunction())
+ m_timingFunction.set(new TimingFunction(*other.timingFunction()));
+ }
+
+ const TransformValue& operator=(const TransformValue& other)
+ {
+ if (&other != this)
+ set(other.key(), other.value(), other.timingFunction());
+ return *this;
+ }
+
+ void set(float key, const TransformOperations* value, const TimingFunction* timingFunction);
+
+ float key() const { return m_key; }
+ const TransformOperations* value() const { return m_value.get(); }
+ const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
+
+ private:
+ float m_key;
+ OwnPtr<TransformOperations> m_value;
+ OwnPtr<TimingFunction> m_timingFunction;
+ };
+
+ // Used to store a series of transforms in a keyframe list.
+ class TransformValueList {
+ public:
+ typedef Vector<TransformOperation::OperationType> FunctionList;
+
+ size_t size() const { return m_values.size(); }
+ const TransformValue& at(size_t i) const { return m_values.at(i); }
+ const Vector<TransformValue>& values() const { return m_values; }
+
+ void insert(float key, const TransformOperations* value, const TimingFunction* timingFunction);
+
+ // return a list of the required functions. List is empty if keyframes are not valid
+ // If return value is true, functions contain rotations of >= 180 degrees
+ void makeFunctionList(FunctionList& list, bool& isValid, bool& hasBigRotation) const;
+ private:
+ Vector<TransformValue> m_values;
+ };
+
+ static GraphicsLayer* createGraphicsLayer(GraphicsLayerClient*);
+
+ virtual ~GraphicsLayer();
+
+ GraphicsLayerClient* client() const { return m_client; }
+
+ // Layer name. Only used to identify layers in debug output
+ const String& name() const { return m_name; }
+ virtual void setName(const String& name) { m_name = name; }
+
+ // For hosting this GraphicsLayer in a native layer hierarchy.
+ virtual NativeLayer nativeLayer() const { return 0; }
+
+ GraphicsLayer* parent() const { return m_parent; };
+ void setParent(GraphicsLayer* layer) { m_parent = layer; } // Internal use only.
+
+ const Vector<GraphicsLayer*>& children() const { return m_children; }
+
+ // Add child layers. If the child is already parented, it will be removed from its old parent.
+ 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);
+
+ void removeAllChildren();
+ virtual void removeFromParent();
+
+ // 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; }
+
+ // The position of the layer (the location of its top-left corner in its parent)
+ const FloatPoint& position() const { return m_position; }
+ virtual void setPosition(const FloatPoint& p) { m_position = p; }
+
+ // Anchor point: (0, 0) is top left, (1, 1) is bottom right. The anchor point
+ // affects the origin of the transforms.
+ const FloatPoint3D& anchorPoint() const { return m_anchorPoint; }
+ virtual void setAnchorPoint(const FloatPoint3D& p) { m_anchorPoint = p; }
+
+ // The bounds of the layer
+ const FloatSize& size() const { return m_size; }
+ virtual void setSize(const FloatSize& size) { m_size = size; }
+
+ const TransformationMatrix& transform() const { return m_transform; }
+ virtual void setTransform(const TransformationMatrix& t) { m_transform = t; }
+
+ const TransformationMatrix& childrenTransform() const { return m_childrenTransform; }
+ virtual void setChildrenTransform(const TransformationMatrix& t) { m_childrenTransform = t; }
+
+ bool preserves3D() const { return m_preserves3D; }
+ virtual void setPreserves3D(bool b) { m_preserves3D = b; }
+
+ bool masksToBounds() const { return m_masksToBounds; }
+ virtual void setMasksToBounds(bool b) { m_masksToBounds = b; }
+
+ bool drawsContent() const { return m_drawsContent; }
+ virtual void setDrawsContent(bool b) { m_drawsContent = b; }
+
+ // The color used to paint the layer backgrounds
+ const Color& backgroundColor() const { return m_backgroundColor; }
+ virtual void setBackgroundColor(const Color&, const Animation* = 0, double beginTime = 0);
+ virtual void clearBackgroundColor();
+ bool backgroundColorSet() const { return m_backgroundColorSet; }
+
+ // opaque means that we know the layer contents have no alpha
+ bool contentsOpaque() const { return m_contentsOpaque; }
+ virtual void setContentsOpaque(bool b) { m_contentsOpaque = b; }
+
+ bool backfaceVisibility() const { return m_backfaceVisibility; }
+ virtual void setBackfaceVisibility(bool b) { m_backfaceVisibility = b; }
+
+ float opacity() const { return m_opacity; }
+ // return true if we started an animation
+ virtual bool setOpacity(float o, const Animation* = 0, double beginTime = 0);
+
+ // Some GraphicsLayers paint only the foreground or the background content
+ GraphicsLayerPaintingPhase drawingPhase() const { return m_paintingPhase; }
+ void setDrawingPhase(GraphicsLayerPaintingPhase phase) { m_paintingPhase = phase; }
+
+ virtual void setNeedsDisplay() = 0;
+ // mark the given rect (in layer coords) as needing dispay. Never goes deep.
+ virtual void setNeedsDisplayInRect(const FloatRect&) = 0;
+
+ virtual bool animateTransform(const TransformValueList&, const IntSize&, const Animation*, double beginTime, bool isTransition) = 0;
+ virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&, const Animation*, double beginTime) = 0;
+
+ void removeFinishedAnimations(const String& name, int index, bool reset);
+ void removeFinishedTransitions(AnimatedPropertyID);
+ void removeAllAnimations();
+
+ virtual void suspendAnimations();
+ virtual void resumeAnimations();
+
+ // Layer contents
+ virtual void setContentsToImage(Image*) { }
+ virtual void setContentsToVideo(PlatformLayer*) { }
+ virtual void setContentsBackgroundColor(const Color&) { }
+ virtual void clearContents() { }
+
+ virtual void updateContentsRect() { }
+
+ // Callback from the underlying graphics system to draw layer contents.
+ void paintGraphicsLayerContents(GraphicsContext&, const IntRect& clip);
+
+ virtual PlatformLayer* platformLayer() const { return 0; }
+
+ void dumpLayer(TextStream&, int indent = 0) const;
+
+#ifndef NDEBUG
+ int repaintCount() const { return m_repaintCount; }
+ int incrementRepaintCount() { return ++m_repaintCount; }
+#endif
+
+ // Platform behaviors
+ static bool graphicsContextsFlipped();
+
+#ifndef NDEBUG
+ static bool showDebugBorders();
+ static bool showRepaintCounter();
+
+ void updateDebugIndicators();
+
+ virtual void setDebugBackgroundColor(const Color&) { }
+ virtual void setDebugBorder(const Color&, float /*borderWidth*/) { }
+ // z-position is the z-equivalent of position(). It's only used for debugging purposes.
+ virtual float zPosition() const { return m_zPosition; }
+ virtual void setZPosition(float);
+#endif
+
+ static String propertyIdToString(AnimatedPropertyID);
+
+protected:
+ GraphicsLayer(GraphicsLayerClient*);
+
+ void dumpProperties(TextStream&, int indent) const;
+
+ // returns -1 if not found
+ int findAnimationEntry(AnimatedPropertyID, short index) const;
+ void addAnimationEntry(AnimatedPropertyID, short index, bool isTransition, const Animation*);
+
+ virtual void removeAnimation(int /*index*/, bool /*reset*/) {}
+ void removeAllAnimationsForProperty(AnimatedPropertyID);
+
+ GraphicsLayerClient* m_client;
+ String m_name;
+
+ // Offset from the owning renderer
+ IntSize m_offsetFromRenderer;
+
+ // Position is relative to the parent GraphicsLayer
+ FloatPoint m_position;
+ FloatPoint3D m_anchorPoint;
+ FloatSize m_size;
+ TransformationMatrix m_transform;
+ TransformationMatrix m_childrenTransform;
+
+ Color m_backgroundColor;
+ float m_opacity;
+#ifndef NDEBUG
+ float m_zPosition;
+#endif
+
+ bool m_backgroundColorSet : 1;
+ bool m_contentsOpaque : 1;
+ bool m_preserves3D: 1;
+ bool m_backfaceVisibility : 1;
+ bool m_usingTiledLayer : 1;
+ bool m_masksToBounds : 1;
+ bool m_drawsContent : 1;
+
+ GraphicsLayerPaintingPhase m_paintingPhase;
+
+ Vector<GraphicsLayer*> m_children;
+ GraphicsLayer* m_parent;
+
+ // AnimationEntry represents an animation of a property on this layer.
+ // For transform only, there may be more than one, in which case 'index'
+ // is an index into the list of transforms.
+ class AnimationEntry {
+ public:
+ AnimationEntry(const Animation* animation, AnimatedPropertyID property, short index, bool isTransition)
+ : m_animation(const_cast<Animation*>(animation))
+ , m_property(property)
+ , m_index(index)
+ , m_isCurrent(true)
+ , m_isTransition(isTransition)
+ {
+ }
+
+ const Animation* animation() const { return m_animation.get(); }
+ AnimatedPropertyID property() const { return m_property; }
+ int index() const { return m_index; }
+ bool isCurrent() const { return m_isCurrent; }
+ void setIsCurrent(bool b = true) { m_isCurrent = b; }
+ bool isTransition() const { return m_isTransition; }
+
+ bool matches(AnimatedPropertyID property, short index) const
+ {
+ return m_property == property && m_index == index;
+ }
+
+ void reset(const Animation* animation, bool isTransition)
+ {
+ m_animation = const_cast<Animation*>(animation);
+ m_isTransition = isTransition;
+ m_isCurrent = true;
+ }
+
+ private:
+ RefPtr<Animation> m_animation;
+ AnimatedPropertyID m_property : 14;
+ short m_index : 16;
+ bool m_isCurrent : 1;
+ bool m_isTransition : 1;
+ };
+
+ Vector<AnimationEntry> m_animations; // running animations/transitions
+
+#ifndef NDEBUG
+ int m_repaintCount;
+#endif
+};
+
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayer_h
+
diff --git a/WebCore/platform/graphics/GraphicsLayerClient.h b/WebCore/platform/graphics/GraphicsLayerClient.h
new file mode 100644
index 0000000..46382f2
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsLayerClient.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsLayerClient_h
+#define GraphicsLayerClient_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+namespace WebCore {
+
+class GraphicsContext;
+class GraphicsLayer;
+class IntPoint;
+class IntRect;
+class FloatPoint;
+
+enum GraphicsLayerPaintingPhase {
+ GraphicsLayerPaintBackgroundMask = (1 << 0),
+ GraphicsLayerPaintForegroundMask = (1 << 1),
+ GraphicsLayerPaintAllMask = (GraphicsLayerPaintBackgroundMask | GraphicsLayerPaintForegroundMask)
+};
+
+enum AnimatedPropertyID {
+ AnimatedPropertyInvalid,
+ AnimatedPropertyWebkitTransform,
+ AnimatedPropertyOpacity,
+ AnimatedPropertyBackgroundColor
+};
+
+class GraphicsLayerClient {
+public:
+ virtual ~GraphicsLayerClient() {}
+
+ // Callbacks for when hardware-accelerated transitions and animation started
+ virtual void notifyAnimationStarted(const GraphicsLayer*, double time) = 0;
+
+ virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0;
+
+ // Return a rect for the "contents" of the graphics layer, i.e. video or image content, in GraphicsLayer coordinates.
+ virtual IntRect contentsBox(const GraphicsLayer*) = 0;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerClient_h
diff --git a/WebCore/platform/graphics/GraphicsTypes.h b/WebCore/platform/graphics/GraphicsTypes.h
index cdf5e31..769207a 100644
--- a/WebCore/platform/graphics/GraphicsTypes.h
+++ b/WebCore/platform/graphics/GraphicsTypes.h
@@ -50,6 +50,14 @@ namespace WebCore {
CompositePlusLighter
};
+ // FIXME: Currently these constants have to match the values used in the SVG
+ // DOM API. That's a mistake. We need to make cut that dependency.
+ enum GradientSpreadMethod {
+ SpreadMethodPad = 1,
+ SpreadMethodReflect = 2,
+ SpreadMethodRepeat = 3
+ };
+
enum LineCap { ButtCap, RoundCap, SquareCap };
enum LineJoin { MiterJoin, RoundJoin, BevelJoin };
diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp
index 49961e1..08d96b4 100644
--- a/WebCore/platform/graphics/Image.cpp
+++ b/WebCore/platform/graphics/Image.cpp
@@ -119,7 +119,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl
FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(),
scaledTileSize.height() / intrinsicTileSize.height());
- TransformationMatrix patternTransform = TransformationMatrix().scale(scale.width(), scale.height());
+ TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height());
FloatRect oneTileRect;
oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width()));
@@ -158,7 +158,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const Flo
vRule = RepeatTile;
FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule);
- TransformationMatrix patternTransform = TransformationMatrix().scale(scale.width(), scale.height());
+ TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height());
// We want to construct the phase such that the pattern is centered (when stretch is not
// set for a particular rule).
diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h
index c3cf2e7..70f6d49 100644
--- a/WebCore/platform/graphics/Image.h
+++ b/WebCore/platform/graphics/Image.h
@@ -118,9 +118,9 @@ public:
SharedBuffer* data() { return m_data.get(); }
- // It may look unusual that there is no start animation call as public API. This is because
- // we start and stop animating lazily. Animation begins whenever someone draws the image. It will
- // automatically pause once all observers no longer want to render the image anywhere.
+ // Animation begins whenever someone draws the image, so startAnimation() is not normally called.
+ // It will automatically pause once all observers no longer want to render the image anywhere.
+ virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { }
virtual void stopAnimation() {}
virtual void resetAnimation() {}
@@ -164,11 +164,9 @@ protected:
void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator);
// Supporting tiled drawing
- virtual bool mayFillWithSolidColor() const { return false; }
+ virtual bool mayFillWithSolidColor() { return false; }
virtual Color solidColor() const { return Color(); }
- virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { }
-
virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
#if PLATFORM(CG)
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
index 21e31fc..99d6aa4 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,7 +27,9 @@
#if ENABLE(VIDEO)
#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
+#include "ContentType.h"
#include "IntRect.h"
#include "MIMETypeRegistry.h"
#include "FrameView.h"
@@ -47,26 +49,196 @@
#endif
namespace WebCore {
+
+// a null player to make MediaPlayer logic simpler
+
+class NullMediaPlayerPrivate : public MediaPlayerPrivateInterface {
+public:
+ NullMediaPlayerPrivate(MediaPlayer*) { }
+
+ virtual void load(const String&) { }
+ virtual void cancelLoad() { }
+
+ virtual void play() { }
+ virtual void pause() { }
+
+ virtual IntSize naturalSize() const { return IntSize(0, 0); }
+
+ virtual bool hasVideo() const { return false; }
+
+ virtual void setVisible(bool) { }
+
+ virtual float duration() const { return 0; }
+
+ virtual float currentTime() const { return 0; }
+ virtual void seek(float) { }
+ virtual bool seeking() const { return false; }
+
+ virtual void setEndTime(float) { }
+
+ virtual void setRate(float) { }
+ virtual bool paused() const { return false; }
+
+ virtual void setVolume(float) { }
+
+ virtual MediaPlayer::NetworkState networkState() const { return MediaPlayer::Empty; }
+ virtual MediaPlayer::ReadyState readyState() const { return MediaPlayer::HaveNothing; }
+
+ virtual float maxTimeSeekable() const { return 0; }
+ virtual float maxTimeBuffered() const { return 0; }
+
+ virtual int dataRate() const { return 0; }
+
+ virtual bool totalBytesKnown() const { return false; }
+ virtual unsigned totalBytes() const { return 0; }
+ virtual unsigned bytesLoaded() const { return 0; }
+
+ virtual void setSize(const IntSize&) { }
+
+ virtual void paint(GraphicsContext*, const IntRect&) { }
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ virtual void setPoster(const String& /*url*/) { }
+ virtual void deliverNotification(MediaPlayerProxyNotificationType) { }
+ virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) { }
+#endif
+};
+
+static MediaPlayerPrivateInterface* createNullMediaPlayer(MediaPlayer* player)
+{
+ return new NullMediaPlayerPrivate(player);
+}
+
+
+// engine support
+
+struct MediaPlayerFactory {
+ MediaPlayerFactory(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsTypeAndCodecs)
+ : constructor(constructor)
+ , getSupportedTypes(getSupportedTypes)
+ , supportsTypeAndCodecs(supportsTypeAndCodecs)
+ {
+ }
+
+ CreateMediaEnginePlayer constructor;
+ MediaEngineSupportedTypes getSupportedTypes;
+ MediaEngineSupportsType supportsTypeAndCodecs;
+};
+
+static void addMediaEngine(CreateMediaEnginePlayer, MediaEngineSupportedTypes, MediaEngineSupportsType);
+static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, const String& codecs);
+
+static Vector<MediaPlayerFactory*>& installedMediaEngines()
+{
+ DEFINE_STATIC_LOCAL(Vector<MediaPlayerFactory*>, installedEngines, ());
+ static bool enginesQueried = false;
+
+ if (!enginesQueried) {
+ enginesQueried = true;
+ MediaPlayerPrivate::registerMediaEngine(addMediaEngine);
+
+ // register additional engines here
+ }
- MediaPlayer::MediaPlayer(MediaPlayerClient* client)
+ return installedEngines;
+}
+
+static void addMediaEngine(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsType)
+{
+ ASSERT(constructor);
+ ASSERT(getSupportedTypes);
+ ASSERT(supportsType);
+ installedMediaEngines().append(new MediaPlayerFactory(constructor, getSupportedTypes, supportsType));
+}
+
+static MediaPlayerFactory* chooseBestEngineForTypeAndCodecs(const String& type, const String& codecs)
+{
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+
+ if (engines.isEmpty())
+ return 0;
+
+ MediaPlayerFactory* engine = 0;
+ MediaPlayer::SupportsType supported = MediaPlayer::IsNotSupported;
+
+ unsigned count = engines.size();
+ for (unsigned ndx = 0; ndx < count; ndx++) {
+ MediaPlayer::SupportsType engineSupport = engines[ndx]->supportsTypeAndCodecs(type, codecs);
+ if (engineSupport > supported) {
+ supported = engineSupport;
+ engine = engines[ndx];
+ }
+ }
+
+ return engine;
+}
+
+// media player
+
+MediaPlayer::MediaPlayer(MediaPlayerClient* client)
: m_mediaPlayerClient(client)
- , m_private(new MediaPlayerPrivate(this))
+ , m_private(createNullMediaPlayer(this))
+ , m_currentMediaEngine(0)
, m_frameView(0)
, m_visible(false)
, m_rate(1.0f)
, m_volume(1.0f)
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ , m_playerProxy(0)
+#endif
{
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+ if (!engines.isEmpty()) {
+ m_currentMediaEngine = engines[0];
+ m_private.clear();
+ m_private.set(engines[0]->constructor(this));
+ }
+#endif
}
MediaPlayer::~MediaPlayer()
{
- delete m_private;
}
-void MediaPlayer::load(const String& url)
+void MediaPlayer::load(const String& url, const ContentType& contentType)
+{
+ String type = contentType.type();
+ String codecs = contentType.parameter("codecs");
+
+ // if we don't know the MIME type, see if the path can help
+ if (type.isEmpty())
+ type = MIMETypeRegistry::getMIMETypeForPath(url);
+
+ MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, codecs);
+
+ // if we didn't find an engine that claims the MIME type, just use the first engine
+ if (!engine)
+ engine = installedMediaEngines()[0];
+
+ // don't delete and recreate the player unless it comes from a different engine
+ if (engine && m_currentMediaEngine != engine) {
+ m_currentMediaEngine = engine;
+ m_private.clear();
+ m_private.set(engine->constructor(this));
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ m_private->setMediaPlayerProxy(m_playerProxy);
+#endif
+
+ }
+
+ if (m_private)
+ m_private->load(url);
+ else
+ m_private.set(createNullMediaPlayer(this));
+}
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+void MediaPlayer::setPoster(const String& url)
{
- m_private->load(url);
+ m_private->setPoster(url);
}
+#endif
void MediaPlayer::cancelLoad()
{
@@ -90,7 +262,7 @@ float MediaPlayer::duration() const
float MediaPlayer::currentTime() const
{
- return m_private->currentTime();
+ return m_private->currentTime();
}
void MediaPlayer::seek(float time)
@@ -193,10 +365,10 @@ unsigned MediaPlayer::totalBytes()
return m_private->totalBytes();
}
-void MediaPlayer::setRect(const IntRect& r)
+void MediaPlayer::setSize(const IntSize& size)
{
- m_rect = r;
- m_private->setRect(r);
+ m_size = size;
+ m_private->setSize(size);
}
bool MediaPlayer::visible() const
@@ -215,29 +387,47 @@ void MediaPlayer::paint(GraphicsContext* p, const IntRect& r)
m_private->paint(p, r);
}
-bool MediaPlayer::supportsType(const String& type)
+MediaPlayer::SupportsType MediaPlayer::supportsType(ContentType contentType)
{
- HashSet<String> types;
- getSupportedTypes(types);
- return MIMETypeRegistry::isSupportedMediaMIMEType(type) && types.contains(type);
+ String type = contentType.type();
+ String codecs = contentType.parameter("codecs");
+ MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, codecs);
+
+ if (!engine)
+ return IsNotSupported;
+
+ return engine->supportsTypeAndCodecs(type, codecs);
}
void MediaPlayer::getSupportedTypes(HashSet<String>& types)
{
- MediaPlayerPrivate::getSupportedTypes(types);
+ Vector<MediaPlayerFactory*>& engines = installedMediaEngines();
+ if (engines.isEmpty())
+ return;
+
+ unsigned count = engines.size();
+ for (unsigned ndx = 0; ndx < count; ndx++)
+ engines[ndx]->getSupportedTypes(types);
}
-
+
bool MediaPlayer::isAvailable()
{
- static bool availabityKnown = false;
- static bool isAvailable;
- if (!availabityKnown) {
- isAvailable = MediaPlayerPrivate::isAvailable();
- availabityKnown = true;
- }
- return isAvailable;
+ return !installedMediaEngines().isEmpty();
}
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+void MediaPlayer::deliverNotification(MediaPlayerProxyNotificationType notification)
+{
+ m_private->deliverNotification(notification);
+}
+
+void MediaPlayer::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
+{
+ m_playerProxy = proxy;
+ m_private->setMediaPlayerProxy(proxy);
+}
+#endif
+
void MediaPlayer::networkStateChanged()
{
if (m_mediaPlayerClient)
@@ -262,11 +452,29 @@ void MediaPlayer::timeChanged()
m_mediaPlayerClient->mediaPlayerTimeChanged(this);
}
+void MediaPlayer::sizeChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerSizeChanged(this);
+}
+
void MediaPlayer::repaint()
{
if (m_mediaPlayerClient)
m_mediaPlayerClient->mediaPlayerRepaint(this);
}
+void MediaPlayer::durationChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerDurationChanged(this);
+}
+
+void MediaPlayer::rateChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerRateChanged(this);
+}
+
}
#endif
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index 203f299..7d90e44 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -28,52 +28,78 @@
#if ENABLE(VIDEO)
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "MediaPlayerProxy.h"
+#endif
+
#include "IntRect.h"
#include "StringHash.h"
#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
#include <wtf/Noncopyable.h>
namespace WebCore {
+class ContentType;
class FrameView;
class GraphicsContext;
+class IntRect;
class IntSize;
class MediaPlayer;
-class MediaPlayerPrivate;
+class MediaPlayerPrivateInterface;
class String;
class MediaPlayerClient {
public:
virtual ~MediaPlayerClient() { }
+
+ // the network state has changed
virtual void mediaPlayerNetworkStateChanged(MediaPlayer*) { }
+
+ // the ready state has changed
virtual void mediaPlayerReadyStateChanged(MediaPlayer*) { }
+
+ // the volume or muted state has changed
virtual void mediaPlayerVolumeChanged(MediaPlayer*) { }
+
+ // time has jumped, eg. not as a result of normal playback
virtual void mediaPlayerTimeChanged(MediaPlayer*) { }
+
+ // a new frame of video is available
virtual void mediaPlayerRepaint(MediaPlayer*) { }
+
+ // the media file duration has changed, or is now known
+ virtual void mediaPlayerDurationChanged(MediaPlayer*) { }
+
+ // the playback rate has changed
+ virtual void mediaPlayerRateChanged(MediaPlayer*) { }
+
+ // the movie size has changed
+ virtual void mediaPlayerSizeChanged(MediaPlayer*) { }
};
class MediaPlayer : Noncopyable {
public:
MediaPlayer(MediaPlayerClient*);
virtual ~MediaPlayer();
-
- static bool isAvailable();
- static bool supportsType(const String&);
+
+ // media engine support
+ enum SupportsType { IsNotSupported, IsSupported, MayBeSupported };
+ static MediaPlayer::SupportsType supportsType(ContentType contentType);
static void getSupportedTypes(HashSet<String>&);
+ static bool isAvailable();
IntSize naturalSize();
bool hasVideo();
void setFrameView(FrameView* frameView) { m_frameView = frameView; }
+ FrameView* frameView() { return m_frameView; }
bool inMediaDocument();
- // FIXME: it would be better to just have a getter and setter for size.
- // This is currently an absolute rect, which is not appropriate for
- // content with transforms
- IntRect rect() const { return m_rect; }
- void setRect(const IntRect& r);
+ IntSize size() const { return m_size; }
+ void setSize(const IntSize& size);
- void load(const String& url);
+ void load(const String& url, const ContentType& contentType);
void cancelLoad();
bool visible() const;
@@ -96,7 +122,7 @@ public:
float maxTimeBuffered();
float maxTimeSeekable();
-
+
unsigned bytesLoaded();
bool totalBytesKnown();
unsigned totalBytes();
@@ -108,33 +134,55 @@ public:
void paint(GraphicsContext*, const IntRect&);
- enum NetworkState { Empty, LoadFailed, Loading, LoadedMetaData, LoadedFirstFrame, Loaded };
+ enum NetworkState { Empty, Idle, Loading, Loaded, FormatError, NetworkError, DecodeError };
NetworkState networkState();
- enum ReadyState { DataUnavailable, CanShowCurrentFrame, CanPlay, CanPlayThrough };
+ enum ReadyState { HaveNothing, HaveMetadata, HaveCurrentData, HaveFutureData, HaveEnoughData };
ReadyState readyState();
void networkStateChanged();
void readyStateChanged();
void volumeChanged();
void timeChanged();
+ void sizeChanged();
+ void rateChanged();
+ void durationChanged();
void repaint();
-
+
+ MediaPlayerClient* mediaPlayerClient() const { return m_mediaPlayerClient; }
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ void setPoster(const String& url);
+ void deliverNotification(MediaPlayerProxyNotificationType notification);
+ void setMediaPlayerProxy(WebMediaPlayerProxy* proxy);
+#endif
+
private:
-
- friend class MediaPlayerPrivate;
-
+ static void initializeMediaEngines();
+
MediaPlayerClient* m_mediaPlayerClient;
- MediaPlayerPrivate* m_private;
+ OwnPtr<MediaPlayerPrivateInterface*> m_private;
+ void* m_currentMediaEngine;
FrameView* m_frameView;
- IntRect m_rect;
+ IntSize m_size;
bool m_visible;
float m_rate;
float m_volume;
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private
+#endif
};
+typedef MediaPlayerPrivateInterface* (*CreateMediaEnginePlayer)(MediaPlayer*);
+typedef void (*MediaEngineSupportedTypes)(HashSet<String>& types);
+typedef MediaPlayer::SupportsType (*MediaEngineSupportsType)(const String& type, const String& codecs);
+
+typedef void (*MediaEngineRegistrar)(CreateMediaEnginePlayer, MediaEngineSupportedTypes, MediaEngineSupportsType);
+
+
}
-#endif
+#endif // ENABLE(VIDEO)
+
#endif
diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h
new file mode 100644
index 0000000..2e73e7e
--- /dev/null
+++ b/WebCore/platform/graphics/MediaPlayerPrivate.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaPlayerPrivate_h
+#define MediaPlayerPrivate_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayer.h"
+
+namespace WebCore {
+
+class IntRect;
+class IntSize;
+class String;
+
+class MediaPlayerPrivateInterface {
+public:
+ virtual ~MediaPlayerPrivateInterface() { }
+
+ virtual void load(const String& url) = 0;
+ virtual void cancelLoad() = 0;
+
+ virtual void play() = 0;
+ virtual void pause() = 0;
+
+ virtual IntSize naturalSize() const = 0;
+
+ virtual bool hasVideo() const = 0;
+
+ virtual void setVisible(bool) = 0;
+
+ virtual float duration() const = 0;
+
+ virtual float currentTime() const = 0;
+ virtual void seek(float time) = 0;
+ virtual bool seeking() const = 0;
+
+ virtual void setEndTime(float time) = 0;
+
+ virtual void setRate(float) = 0;
+ virtual bool paused() const = 0;
+
+ virtual void setVolume(float) = 0;
+
+ virtual MediaPlayer::NetworkState networkState() const = 0;
+ virtual MediaPlayer::ReadyState readyState() const = 0;
+
+ virtual float maxTimeSeekable() const = 0;
+ virtual float maxTimeBuffered() 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;
+
+ virtual void paint(GraphicsContext*, const IntRect&) = 0 ;
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ virtual void setPoster(const String& url) = 0;
+ virtual void deliverNotification(MediaPlayerProxyNotificationType) = 0;
+ virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) = 0;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h
index 716a645..6981748 100644
--- a/WebCore/platform/graphics/Pattern.h
+++ b/WebCore/platform/graphics/Pattern.h
@@ -30,6 +30,7 @@
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include "TransformationMatrix.h"
#if PLATFORM(CG)
typedef struct CGPattern* CGPatternRef;
@@ -67,7 +68,9 @@ namespace WebCore {
Image* tileImage() const { return m_tileImage.get(); }
- PlatformPatternPtr createPlatformPattern(const TransformationMatrix& patternTransform) const;
+ // Pattern space is an abstract space that maps to the default user space by the transformation 'userSpaceTransformation'
+ PlatformPatternPtr createPlatformPattern(const TransformationMatrix& userSpaceTransformation) const;
+ void setPatternSpaceTransform(const TransformationMatrix& patternSpaceTransformation) { m_patternSpaceTransformation = patternSpaceTransformation; }
private:
Pattern(Image*, bool repeatX, bool repeatY);
@@ -75,6 +78,7 @@ namespace WebCore {
RefPtr<Image> m_tileImage;
bool m_repeatX;
bool m_repeatY;
+ TransformationMatrix m_patternSpaceTransformation;
};
} //namespace
diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp
index 9670b55..9f51037 100644
--- a/WebCore/platform/graphics/SimpleFontData.cpp
+++ b/WebCore/platform/graphics/SimpleFontData.cpp
@@ -136,20 +136,6 @@ SimpleFontData::~SimpleFontData()
}
}
-#if !PLATFORM(QT)
-float SimpleFontData::widthForGlyph(Glyph glyph) const
-{
- float width = m_glyphToWidthMap.widthForGlyph(glyph);
- if (width != cGlyphWidthUnknown)
- return width;
-
- width = platformWidthForGlyph(glyph);
- m_glyphToWidthMap.setWidthForGlyph(glyph, width);
-
- return width;
-}
-#endif
-
const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
{
return this;
diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h
index e572e30..d2dd0b9 100644
--- a/WebCore/platform/graphics/SimpleFontData.h
+++ b/WebCore/platform/graphics/SimpleFontData.h
@@ -131,7 +131,7 @@ public:
#endif
#if PLATFORM(WX)
- wxFont getWxFont() const { return m_font.font(); }
+ wxFont* getWxFont() const { return m_font.font(); }
#endif
private:
@@ -205,6 +205,21 @@ public:
mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
#endif
};
+
+
+#if !PLATFORM(QT)
+ALWAYS_INLINE float SimpleFontData::widthForGlyph(Glyph glyph) const
+{
+ float width = m_glyphToWidthMap.widthForGlyph(glyph);
+ if (width != cGlyphWidthUnknown)
+ return width;
+
+ width = platformWidthForGlyph(glyph);
+ m_glyphToWidthMap.setWidthForGlyph(glyph, width);
+
+ return width;
+}
+#endif
} // namespace WebCore
diff --git a/WebCore/platform/graphics/android/FontPlatformData.h b/WebCore/platform/graphics/android/FontPlatformData.h
index 2bb8834..35b7200 100644
--- a/WebCore/platform/graphics/android/FontPlatformData.h
+++ b/WebCore/platform/graphics/android/FontPlatformData.h
@@ -42,6 +42,8 @@ public:
FontPlatformData(const FontPlatformData&);
FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic);
FontPlatformData(const FontPlatformData& src, float textSize);
+ FontPlatformData(float size, bool syntheticBold, bool syntheticOblique);
+
~FontPlatformData();
FontPlatformData(WTF::HashTableDeletedValueType)
diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
index e82c1f6..4496408 100644
--- a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
+++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
@@ -103,6 +103,13 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
trace(4);
}
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : mTypeface(NULL), mTextSize(size), mFakeBold(bold), mFakeItalic(oblique)
+{
+ inc_count();
+ trace(5);
+}
+
FontPlatformData::~FontPlatformData()
{
dec_count();
diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
index 6a92a7f..7571926 100644
--- a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
+++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -315,7 +315,8 @@ static SkShader::TileMode SpreadMethod2TileMode(GradientSpreadMethod sm) {
}
static void extactShader(SkPaint* paint, ColorSpace cs, Pattern* pat,
- Gradient* grad, GradientSpreadMethod sm) {
+ Gradient* grad)
+{
switch (cs) {
case PatternColorSpace:
// createPlatformPattern() returns a new inst
@@ -324,6 +325,7 @@ static void extactShader(SkPaint* paint, ColorSpace cs, Pattern* pat,
break;
case GradientColorSpace: {
// grad->getShader() returns a cached obj
+ GradientSpreadMethod sm = grad->spreadMethod();
paint->setShader(grad->getShader(SpreadMethod2TileMode(sm)));
break;
}
@@ -670,7 +672,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
extactShader(&paint, m_common->state.fillColorSpace,
m_common->state.fillPattern.get(),
- m_common->state.fillGradient.get(), spreadMethod());
+ m_common->state.fillGradient.get());
GC2Canvas(this)->drawRect(r, paint);
}
@@ -1077,7 +1079,13 @@ void GraphicsContext::setPlatformShouldAntialias(bool useAA)
TransformationMatrix GraphicsContext::getCTM() const
{
- return TransformationMatrix(GC2Canvas(this)->getTotalMatrix());
+ const SkMatrix& m = GC2Canvas(this)->getTotalMatrix();
+ return TransformationMatrix(SkScalarToDouble(m.getScaleX()), // a
+ SkScalarToDouble(m.getSkewY()), // b
+ SkScalarToDouble(m.getSkewX()), // c
+ SkScalarToDouble(m.getScaleY()), // d
+ SkScalarToDouble(m.getTranslateX()), // e
+ SkScalarToDouble(m.getTranslateY())); // f
}
///////////////////////////////////////////////////////////////////////////////
@@ -1118,7 +1126,7 @@ void GraphicsContext::fillPath()
extactShader(&paint, m_common->state.fillColorSpace,
m_common->state.fillPattern.get(),
- m_common->state.fillGradient.get(), spreadMethod());
+ m_common->state.fillGradient.get());
GC2Canvas(this)->drawPath(*path, paint);
}
@@ -1134,7 +1142,7 @@ void GraphicsContext::strokePath()
extactShader(&paint, m_common->state.strokeColorSpace,
m_common->state.strokePattern.get(),
- m_common->state.strokeGradient.get(), spreadMethod());
+ m_common->state.strokeGradient.get());
GC2Canvas(this)->drawPath(*path, paint);
}
diff --git a/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp b/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp
index 6a4c670..a57abc0 100644
--- a/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp
+++ b/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp
@@ -1,232 +1,56 @@
-/*
- * Copyright 2007, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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 THE COPYRIGHT HOLDERS ``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.
- */
+// Copyright (c) 2008, Google 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "config.h"
#include "TransformationMatrix.h"
-#include "FloatRect.h"
-#include "IntRect.h"
-
-#include "android_graphics.h"
+#include "SkiaUtils.h"
namespace WebCore {
-static const double deg2rad = 0.017453292519943295769; // pi/180
-
-TransformationMatrix::TransformationMatrix()
-{
- m_transform.reset();
-}
-
-TransformationMatrix::TransformationMatrix(const SkMatrix& mat) : m_transform(mat) {}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform.reset();
-
- m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
- m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
- m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
-
- m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
- m_transform.set(SkMatrix::kMSkewY, SkDoubleToScalar(c));
- m_transform.set(SkMatrix::kMTransY, SkDoubleToScalar(ty));
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
- m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
- m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
-
- m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
- m_transform.set(SkMatrix::kMSkewY, SkDoubleToScalar(c));
- m_transform.set(SkMatrix::kMTransY, SkDoubleToScalar(ty));
-}
-
-void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
-{
- SkPoint pt;
-
- m_transform.mapXY(SkDoubleToScalar(x), SkDoubleToScalar(y), &pt);
- *x2 = SkScalarToDouble(pt.fX);
- *y2 = SkScalarToDouble(pt.fY);
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const
-{
- SkRect src, dst;
- SkIRect ir;
-
- android_setrect(&src, rect);
- m_transform.mapRect(&dst, src);
- // we round out to mimic enclosingIntRect()
- dst.roundOut(&ir);
-
- return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
-{
- SkRect r;
-
- android_setrect(&r, rect);
- m_transform.mapRect(&r);
-
- return FloatRect(r.fLeft, r.fTop, r.width(), r.height());
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return m_transform.isIdentity();
-}
-
-void TransformationMatrix::reset()
-{
- m_transform.reset();
-}
-
-double TransformationMatrix::a() const
-{
- return SkScalarToDouble(m_transform[0]);
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.set(0, SkDoubleToScalar(a));
-}
-
-double TransformationMatrix::b() const
-{
- return SkScalarToDouble(m_transform[1]);
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.set(1, SkDoubleToScalar(b));
-}
-
-double TransformationMatrix::c() const
-{
- return SkScalarToDouble(m_transform[3]);
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.set(3, SkDoubleToScalar(c));
-}
-
-double TransformationMatrix::d() const {
- return SkScalarToDouble(m_transform[4]);
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.set(4, SkDoubleToScalar(d));
-}
-
-double TransformationMatrix::e() const
-{
- return SkScalarToDouble(m_transform[2]);
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.set(2, SkDoubleToScalar(e));
-}
-
-double TransformationMatrix::f() const {
- return SkScalarToDouble(m_transform[5]);
-}
-void TransformationMatrix::setF(double f) {
- m_transform.set(5, SkDoubleToScalar(f));
-}
-
-TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
-{
- m_transform.preScale(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::rotate(double d)
-{
- m_transform.preRotate(SkDoubleToScalar(d));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
-{
- m_transform.preTranslate(SkDoubleToScalar(tx), SkDoubleToScalar(ty));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
-{
- m_transform.preSkew(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return SkScalarToDouble(m_transform[SkMatrix::kMScaleX]) * SkScalarToDouble(m_transform[SkMatrix::kMScaleY]) -
- SkScalarToDouble(m_transform[SkMatrix::kMSkewX]) * SkScalarToDouble(m_transform[SkMatrix::kMSkewY]);
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- // the constructor initializes inverse to the identity
- TransformationMatrix inverse;
-
- // if we are not invertible, inverse will stay identity
- m_transform.invert(&inverse.m_transform);
-
- return inverse;
-}
-
TransformationMatrix::operator SkMatrix() const
{
- return m_transform;
-}
+ SkMatrix result;
-bool TransformationMatrix::operator==(const TransformationMatrix &m2) const
-{
- return m_transform == m2.m_transform;
-}
+ result.setScaleX(WebCoreDoubleToSkScalar(a()));
+ result.setSkewX(WebCoreDoubleToSkScalar(c()));
+ result.setTranslateX(WebCoreDoubleToSkScalar(e()));
-TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
-{
- m_transform.setConcat(m2.m_transform, m_transform);
- return *this;
-}
+ result.setScaleY(WebCoreDoubleToSkScalar(d()));
+ result.setSkewY(WebCoreDoubleToSkScalar(b()));
+ result.setTranslateY(WebCoreDoubleToSkScalar(f()));
-TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
-{
- TransformationMatrix cat;
-
- cat.m_transform.setConcat(m2.m_transform, m_transform);
- return cat;
+ // FIXME: Set perspective properly.
+ result.setPerspX(0);
+ result.setPerspY(0);
+ result.set(SkMatrix::kMPersp2, SK_Scalar1);
+ return result;
}
-}
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp
index 9da9426..b23182d 100644
--- a/WebCore/platform/graphics/cairo/FontCairo.cpp
+++ b/WebCore/platform/graphics/cairo/FontCairo.cpp
@@ -2,6 +2,7 @@
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
* Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,8 +30,11 @@
#include "Font.h"
#include "GlyphBuffer.h"
+#include "Gradient.h"
#include "GraphicsContext.h"
+#include "Pattern.h"
#include "SimpleFontData.h"
+#include "TransformationMatrix.h"
namespace WebCore {
@@ -78,18 +82,51 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
}
if (context->textDrawingMode() & cTextFill) {
- float red, green, blue, alpha;
- fillColor.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
-
+ if (context->fillGradient()) {
+ cairo_set_source(cr, context->fillGradient()->platformGradient());
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else if (context->fillPattern()) {
+ TransformationMatrix affine;
+ cairo_set_source(cr, context->fillPattern()->createPlatformPattern(affine));
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else {
+ float red, green, blue, alpha;
+ fillColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
+ }
cairo_show_glyphs(cr, glyphs, numGlyphs);
}
if (context->textDrawingMode() & cTextStroke) {
- Color strokeColor = context->strokeColor();
- float red, green, blue, alpha;
- strokeColor.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
+ if (context->strokeGradient()) {
+ cairo_set_source(cr, context->strokeGradient()->platformGradient());
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else if (context->strokePattern()) {
+ TransformationMatrix affine;
+ cairo_set_source(cr, context->strokePattern()->createPlatformPattern(affine));
+ if (context->getAlpha() < 1.0f) {
+ cairo_push_group(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+ cairo_pop_group_to_source(cr);
+ }
+ } else {
+ Color strokeColor = context->strokeColor();
+ float red, green, blue, alpha;
+ strokeColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha());
+ }
cairo_glyph_path(cr, glyphs, numGlyphs);
cairo_set_line_width(cr, context->strokeThickness());
cairo_stroke(cr);
diff --git a/WebCore/platform/graphics/cairo/GradientCairo.cpp b/WebCore/platform/graphics/cairo/GradientCairo.cpp
index 7776424..72fb0c5 100644
--- a/WebCore/platform/graphics/cairo/GradientCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GradientCairo.cpp
@@ -57,6 +57,22 @@ cairo_pattern_t* Gradient::platformGradient()
++stopIterator;
}
+ switch (m_spreadMethod) {
+ case SpreadMethodPad:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_PAD);
+ break;
+ case SpreadMethodReflect:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REFLECT);
+ break;
+ case SpreadMethodRepeat:
+ cairo_pattern_set_extend(m_gradient, CAIRO_EXTEND_REPEAT);
+ break;
+ }
+
+ cairo_matrix_t matrix = m_gradientSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(m_gradient, &matrix);
+
return m_gradient;
}
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index ef748cf..35ebd3c 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -87,22 +87,6 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const
cairo_fill(cr);
}
-static inline cairo_pattern_t* applySpreadMethod(cairo_pattern_t* pattern, GradientSpreadMethod spreadMethod)
-{
- switch (spreadMethod) {
- case SpreadMethodPad:
- cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
- break;
- case SpreadMethodReflect:
- cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REFLECT);
- break;
- case SpreadMethodRepeat:
- cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
- break;
- }
- return pattern;
-}
-
GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr)
: m_common(createGraphicsContextPrivate())
, m_data(new GraphicsContextPlatformPrivate)
@@ -122,7 +106,7 @@ TransformationMatrix GraphicsContext::getCTM() const
cairo_t* cr = platformContext();
cairo_matrix_t m;
cairo_get_matrix(cr, &m);
- return m;
+ return TransformationMatrix(m.xx, m.yx, m.xy, m.yy, m.x0, m.y0);
}
cairo_t* GraphicsContext::platformContext() const
@@ -463,7 +447,6 @@ void GraphicsContext::fillPath()
}
case GradientColorSpace:
cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient();
- pattern = applySpreadMethod(pattern, spreadMethod());
cairo_set_source(cr, pattern);
cairo_clip(cr);
cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
@@ -501,7 +484,6 @@ void GraphicsContext::strokePath()
}
case GradientColorSpace:
cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient();
- pattern = applySpreadMethod(pattern, spreadMethod());
cairo_set_source(cr, pattern);
if (m_common->state.globalAlpha < 1.0f) {
cairo_push_group(cr);
@@ -750,8 +732,8 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform)
return;
cairo_t* cr = m_data->cr;
- const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
- cairo_transform(cr, matrix);
+ const cairo_matrix_t matrix = cairo_matrix_t(transform);
+ cairo_transform(cr, &matrix);
m_data->concatCTM(transform);
}
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
index 535f70d..55b2e25 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -51,6 +51,7 @@ public:
// NOTE: These may note be needed: review and remove once Cairo implementation is complete
, m_hdc(0)
, m_transparencyCount(0)
+ , m_shouldIncludeChildWindows(false)
#endif
{
}
@@ -94,6 +95,7 @@ public:
#elif PLATFORM(WIN)
HDC m_hdc;
unsigned m_transparencyCount;
+ bool m_shouldIncludeChildWindows;
#endif
};
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index 3e06669..dff39b7 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2007 Holger Hans Peter Freyther <zecke@selfish.org>
- * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
#include "Base64.h"
#include "BitmapImage.h"
+#include "Color.h"
#include "GraphicsContext.h"
#include "ImageData.h"
#include "MIMETypeRegistry.h"
@@ -126,17 +127,15 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4;
for (int y = 0; y < numRows; ++y) {
- unsigned char *row = dataSrc + stride * (y + originy);
+ unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * (y + originy));
for (int x = 0; x < numColumns; x++) {
- uint32_t *pixel = (uint32_t *) row + x + originx;
int basex = x * 4;
- if (unsigned int alpha = (*pixel & 0xff000000) >> 24) {
- destRows[basex] = (*pixel & 0x00ff0000) >> 16;
- destRows[basex + 1] = (*pixel & 0x0000ff00) >> 8;
- destRows[basex + 2] = (*pixel & 0x000000ff);
- destRows[basex + 3] = alpha;
- } else
- reinterpret_cast<uint32_t*>(destRows + basex)[0] = pixel[0];
+ unsigned* pixel = row + x + originx;
+ Color pixelColor = colorFromPremultipliedARGB(*pixel);
+ destRows[basex] = pixelColor.red();
+ destRows[basex + 1] = pixelColor.green();
+ destRows[basex + 2] = pixelColor.blue();
+ destRows[basex + 3] = pixelColor.alpha();
}
destRows += destBytesPerRow;
}
@@ -181,14 +180,15 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con
unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
for (int y = 0; y < numRows; ++y) {
- unsigned char *row = dataDst + stride * (y + desty);
+ unsigned* row = reinterpret_cast<unsigned*>(dataDst + stride * (y + desty));
for (int x = 0; x < numColumns; x++) {
- uint32_t *pixel = (uint32_t *) row + x + destx;
int basex = x * 4;
- if (unsigned int alpha = srcRows[basex + 3]) {
- *pixel = alpha << 24 | srcRows[basex] << 16 | srcRows[basex + 1] << 8 | srcRows[basex + 2];
- } else
- pixel[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ unsigned* pixel = row + x + destx;
+ Color pixelColor(srcRows[basex],
+ srcRows[basex + 1],
+ srcRows[basex + 2],
+ srcRows[basex + 3]);
+ *pixel = premultipliedARGBFromColor(pixelColor);
}
srcRows += srcBytesPerRow;
}
diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp
index 2850488..224154e 100644
--- a/WebCore/platform/graphics/cairo/ImageCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,10 +30,11 @@
#if PLATFORM(CAIRO)
-#include "TransformationMatrix.h"
+#include "Color.h"
#include "FloatRect.h"
#include "GraphicsContext.h"
#include "ImageObserver.h"
+#include "TransformationMatrix.h"
#include <cairo.h>
#include <math.h>
@@ -60,6 +62,7 @@ BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer)
, m_repetitionCountStatus(Unknown)
, m_repetitionsComplete(0)
, m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
, m_animationFinished(true)
, m_allDataReceived(true)
, m_haveSize(true)
@@ -180,8 +183,28 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con
void BitmapImage::checkForSolidColor()
{
- // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1.
m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+
+ if (frameCount() > 1)
+ return;
+
+ cairo_surface_t* frameSurface = frameAtIndex(0);
+ if (!frameSurface)
+ return;
+
+ ASSERT(cairo_surface_get_type(frameSurface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ int width = cairo_image_surface_get_width(frameSurface);
+ int height = cairo_image_surface_get_height(frameSurface);
+
+ if (width != 1 || height != 1)
+ return;
+
+ unsigned* pixelColor = reinterpret_cast<unsigned*>(cairo_image_surface_get_data(frameSurface));
+ m_solidColor = colorFromPremultipliedARGB(*pixelColor);
+
+ m_isSolidColor = true;
}
}
diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
index 6841599..c6d54f2 100644
--- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
@@ -111,7 +111,7 @@ void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer*
delete m_decoder;
m_decoder = 0;
if (data)
- setData(data, allDataReceived);
+ setData(data, allDataReceived);
}
bool ImageSource::initialized() const
diff --git a/WebCore/platform/graphics/cairo/PatternCairo.cpp b/WebCore/platform/graphics/cairo/PatternCairo.cpp
index 7d75db3..58c5d00 100644
--- a/WebCore/platform/graphics/cairo/PatternCairo.cpp
+++ b/WebCore/platform/graphics/cairo/PatternCairo.cpp
@@ -26,23 +26,26 @@
#include "config.h"
#include "Pattern.h"
-#include "TransformationMatrix.h"
#include "GraphicsContext.h"
+#include "TransformationMatrix.h"
#include <cairo.h>
namespace WebCore {
-cairo_pattern_t* Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const
+cairo_pattern_t* Pattern::createPlatformPattern(const TransformationMatrix&) const
{
cairo_surface_t* surface = tileImage()->nativeImageForCurrentFrame();
if (!surface)
return 0;
cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
- const TransformationMatrix& inverse = patternTransform.inverse();
- const cairo_matrix_t* pattern_matrix = reinterpret_cast<const cairo_matrix_t*>(&inverse);
- cairo_pattern_set_matrix(pattern, pattern_matrix);
+
+ // cairo merges patter space and user space itself
+ cairo_matrix_t matrix = m_patternSpaceTransformation;
+ cairo_matrix_invert(&matrix);
+ cairo_pattern_set_matrix(pattern, &matrix);
+
if (m_repeatX || m_repeatY)
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
return pattern;
diff --git a/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp b/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
index b78620f..1b83a29 100644
--- a/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
+++ b/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
@@ -32,248 +32,18 @@
namespace WebCore {
-static const double deg2rad = 0.017453292519943295769; // pi/180
-
-TransformationMatrix::TransformationMatrix()
-{
- cairo_matrix_init_identity(&m_transform);
-}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- cairo_matrix_init(&m_transform, a, b, c, d, tx, ty);
-}
-
-TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
-{
- m_transform = matrix;
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- cairo_matrix_init(&m_transform, a, b, c, d, tx, ty);
-}
-
-void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
-{
- *x2 = x;
- *y2 = y;
- cairo_matrix_transform_point(&m_transform, x2, y2);
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const
-{
- FloatRect floatRect(rect);
- FloatRect enclosingFloatRect = this->mapRect(floatRect);
-
- return enclosingIntRect(enclosingFloatRect);
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
-{
- double rectMinX = rect.x();
- double rectMaxX = rect.x() + rect.width();
- double rectMinY = rect.y();
- double rectMaxY = rect.y() + rect.height();
-
- double px = rectMinX;
- double py = rectMinY;
- cairo_matrix_transform_point(&m_transform, &px, &py);
-
- double enclosingRectMinX = px;
- double enclosingRectMinY = py;
- double enclosingRectMaxX = px;
- double enclosingRectMaxY = py;
-
- px = rectMaxX;
- py = rectMinY;
- cairo_matrix_transform_point(&m_transform, &px, &py);
- if (px < enclosingRectMinX)
- enclosingRectMinX = px;
- else if (px > enclosingRectMaxX)
- enclosingRectMaxX = px;
- if (py < enclosingRectMinY)
- enclosingRectMinY = py;
- else if (py > enclosingRectMaxY)
- enclosingRectMaxY = py;
-
- px = rectMaxX;
- py = rectMaxY;
- cairo_matrix_transform_point(&m_transform, &px, &py);
- if (px < enclosingRectMinX)
- enclosingRectMinX = px;
- else if (px > enclosingRectMaxX)
- enclosingRectMaxX = px;
- if (py < enclosingRectMinY)
- enclosingRectMinY = py;
- else if (py > enclosingRectMaxY)
- enclosingRectMaxY = py;
-
- px = rectMinX;
- py = rectMaxY;
- cairo_matrix_transform_point(&m_transform, &px, &py);
- if (px < enclosingRectMinX)
- enclosingRectMinX = px;
- else if (px > enclosingRectMaxX)
- enclosingRectMaxX = px;
- if (py < enclosingRectMinY)
- enclosingRectMinY = py;
- else if (py > enclosingRectMaxY)
- enclosingRectMaxY = py;
-
-
- double enclosingRectWidth = enclosingRectMaxX - enclosingRectMinX;
- double enclosingRectHeight = enclosingRectMaxY - enclosingRectMinY;
-
- return FloatRect(enclosingRectMinX, enclosingRectMinY, enclosingRectWidth, enclosingRectHeight);
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return ((m_transform.xx == 1) && (m_transform.yy == 1)
- && (m_transform.xy == 0) && (m_transform.yx == 0)
- && (m_transform.x0 == 0) && (m_transform.y0 == 0));
-}
-
-double TransformationMatrix::a() const
-{
- return m_transform.xx;
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.xx = a;
-}
-
-double TransformationMatrix::b() const
-{
- return m_transform.yx;
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.yx = b;
-}
-
-double TransformationMatrix::c() const
-{
- return m_transform.xy;
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.xy = c;
-}
-
-double TransformationMatrix::d() const
-{
- return m_transform.yy;
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.yy = d;
-}
-
-double TransformationMatrix::e() const
-{
- return m_transform.x0;
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.x0 = e;
-}
-
-double TransformationMatrix::f() const
-{
- return m_transform.y0;
-}
-
-void TransformationMatrix::setF(double f)
-{
- m_transform.y0 = f;
-}
-
-void TransformationMatrix::reset()
-{
- cairo_matrix_init_identity(&m_transform);
-}
-
-TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
-{
- cairo_matrix_scale(&m_transform, sx, sy);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::rotate(double d)
-{
- cairo_matrix_rotate(&m_transform, d * deg2rad);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
-{
- cairo_matrix_translate(&m_transform, tx, ty);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
-{
- cairo_matrix_t shear;
- cairo_matrix_init(&shear, 1, sy, sx, 1, 0, 0);
-
- cairo_matrix_t result;
- cairo_matrix_multiply(&result, &shear, &m_transform);
- m_transform = result;
-
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return m_transform.xx * m_transform.yy - m_transform.xy * m_transform.yx;
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- if (!isInvertible()) return TransformationMatrix();
-
- cairo_matrix_t result = m_transform;
- cairo_matrix_invert(&result);
- return TransformationMatrix(result);
-}
-
TransformationMatrix::operator cairo_matrix_t() const
{
- return m_transform;
-}
+ cairo_matrix_t m;
-bool TransformationMatrix::operator== (const TransformationMatrix &m2) const
-{
- return ((m_transform.xx == m2.m_transform.xx)
- && (m_transform.yy == m2.m_transform.yy)
- && (m_transform.xy == m2.m_transform.xy)
- && (m_transform.yx == m2.m_transform.yx)
- && (m_transform.x0 == m2.m_transform.x0)
- && (m_transform.y0 == m2.m_transform.y0));
-
-}
-
-TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
-{
- cairo_matrix_t result;
- cairo_matrix_multiply(&result, &m_transform, &m2.m_transform);
- m_transform = result;
-
- return *this;
-}
-
-TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
-{
- cairo_matrix_t result;
- cairo_matrix_multiply(&result, &m_transform, &m2.m_transform);
- return result;
+ cairo_matrix_init (&m,
+ a(),
+ b(),
+ c(),
+ d(),
+ e(),
+ f());
+ return m;
}
}
diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp
index 48ce9f2..0465c0b 100644
--- a/WebCore/platform/graphics/cg/ColorCG.cpp
+++ b/WebCore/platform/graphics/cg/ColorCG.cpp
@@ -67,9 +67,9 @@ Color::Color(CGColorRef color)
m_color = makeRGBA(r * 255, g * 255, b * 255, a * 255);
}
-#if !PLATFORM(MAC)
+#if PLATFORM(WIN_OS)
-CGColorRef cgColor(const Color& c)
+CGColorRef createCGColor(const Color& c)
{
CGColorRef color = NULL;
CMProfileRef prof = NULL;
@@ -89,7 +89,7 @@ CGColorRef cgColor(const Color& c)
return color;
}
-#endif // !PLATFORM(MAC)
+#endif // PLATFORM(WIN_OS)
}
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
index 1cc55a4..4b8a555 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -504,6 +504,7 @@ void GraphicsContext::fillPath()
CGContextEOClip(context);
else
CGContextClip(context);
+ CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform());
CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
CGContextRestoreGState(context);
break;
@@ -529,6 +530,7 @@ void GraphicsContext::strokePath()
CGContextSaveGState(context);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
+ CGContextConcatCTM(context, m_common->state.strokeGradient->gradientSpaceTransform());
CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient());
CGContextRestoreGState(context);
break;
@@ -552,6 +554,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
case GradientColorSpace:
CGContextSaveGState(context);
CGContextClipToRect(context, rect);
+ CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform());
CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
CGContextRestoreGState(context);
break;
@@ -734,7 +737,7 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Col
if (!color.isValid())
CGContextSetShadow(context, CGSizeMake(width, height), blurRadius);
else {
- CGColorRef colorCG = cgColor(color);
+ CGColorRef colorCG = createCGColor(color);
CGContextSetShadowWithColor(context,
CGSizeMake(width, height),
blurRadius,
@@ -907,7 +910,8 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform)
TransformationMatrix GraphicsContext::getCTM() const
{
- return CGContextGetCTM(platformContext());
+ CGAffineTransform t = CGContextGetCTM(platformContext());
+ return TransformationMatrix(t.a, t.b, t.c, t.d, t.tx, t.ty);
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp
index 13c8c07..dbf1d85 100644
--- a/WebCore/platform/graphics/cg/ImageCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -73,6 +73,7 @@ BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
, m_repetitionCountStatus(Unknown)
, m_repetitionsComplete(0)
, m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
, m_animationFinished(true)
, m_allDataReceived(true)
, m_haveSize(true)
@@ -99,6 +100,7 @@ BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
void BitmapImage::checkForSolidColor()
{
+ m_checkedForSolidColor = true;
if (frameCount() > 1)
m_isSolidColor = false;
else {
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
index 0b276cc..c059985 100644
--- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -58,7 +58,7 @@ void ImageSource::clear(bool, size_t, SharedBuffer* data, bool allDataReceived)
m_decoder = 0;
}
if (data)
- setData(data, allDataReceived);
+ setData(data, allDataReceived);
}
static CFDictionaryRef imageSourceOptions()
diff --git a/WebCore/platform/graphics/cg/PatternCG.cpp b/WebCore/platform/graphics/cg/PatternCG.cpp
index 2b9c12f..697bc57 100644
--- a/WebCore/platform/graphics/cg/PatternCG.cpp
+++ b/WebCore/platform/graphics/cg/PatternCG.cpp
@@ -50,12 +50,13 @@ static void patternReleaseCallback(void* info)
static_cast<Image*>(info)->deref();
}
-CGPatternRef Pattern::createPlatformPattern(const TransformationMatrix& transform) const
+CGPatternRef Pattern::createPlatformPattern(const TransformationMatrix& userSpaceTransformation) const
{
IntRect tileRect = tileImage()->rect();
- TransformationMatrix patternTransform = transform;
- patternTransform.scale(1, -1);
+ TransformationMatrix patternTransform = m_patternSpaceTransformation;
+ patternTransform.multiply(userSpaceTransformation);
+ patternTransform.scaleNonUniform(1, -1);
patternTransform.translate(0, -tileRect.height());
// If FLT_MAX should also be used for xStep or yStep, nothing is rendered. Using fractions of FLT_MAX also
diff --git a/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
index 9b3181a..568a6b3 100644
--- a/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
+++ b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
@@ -28,187 +28,19 @@
#if PLATFORM(CG)
+#include <CoreGraphics/CGAffineTransform.h>
#include "FloatConversion.h"
-#include "FloatRect.h"
-#include "IntRect.h"
-
-#include <wtf/MathExtras.h>
namespace WebCore {
-TransformationMatrix::TransformationMatrix()
- : m_transform(CGAffineTransformIdentity)
-{
-}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a),
- narrowPrecisionToCGFloat(b),
- narrowPrecisionToCGFloat(c),
- narrowPrecisionToCGFloat(d),
- narrowPrecisionToCGFloat(tx),
- narrowPrecisionToCGFloat(ty));
-}
-
-TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& t)
- : m_transform(t)
-{
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a),
- narrowPrecisionToCGFloat(b),
- narrowPrecisionToCGFloat(c),
- narrowPrecisionToCGFloat(d),
- narrowPrecisionToCGFloat(tx),
- narrowPrecisionToCGFloat(ty));
-}
-
-void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
-{
- CGPoint result = CGPointApplyAffineTransform(CGPointMake(narrowPrecisionToCGFloat(x), narrowPrecisionToCGFloat(y)), m_transform);
- *x2 = result.x;
- *y2 = result.y;
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const
-{
- return enclosingIntRect(CGRectApplyAffineTransform(CGRect(rect), m_transform));
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
-{
- return FloatRect(CGRectApplyAffineTransform(CGRect(rect), m_transform));
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return CGAffineTransformIsIdentity(m_transform);
-}
-
-double TransformationMatrix::a() const
-{
- return m_transform.a;
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.a = narrowPrecisionToCGFloat(a);
-}
-
-double TransformationMatrix::b() const
-{
- return m_transform.b;
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.b = narrowPrecisionToCGFloat(b);
-}
-
-double TransformationMatrix::c() const
-{
- return m_transform.c;
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.c = narrowPrecisionToCGFloat(c);
-}
-
-double TransformationMatrix::d() const
-{
- return m_transform.d;
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.d = narrowPrecisionToCGFloat(d);
-}
-
-double TransformationMatrix::e() const
-{
- return m_transform.tx;
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.tx = narrowPrecisionToCGFloat(e);
-}
-
-double TransformationMatrix::f() const
-{
- return m_transform.ty;
-}
-
-void TransformationMatrix::setF(double f)
-{
- m_transform.ty = narrowPrecisionToCGFloat(f);
-}
-
-void TransformationMatrix::reset()
-{
- m_transform = CGAffineTransformIdentity;
-}
-
-TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
-{
- m_transform = CGAffineTransformScale(m_transform, narrowPrecisionToCGFloat(sx), narrowPrecisionToCGFloat(sy));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::rotate(double d)
-{
- m_transform = CGAffineTransformRotate(m_transform, narrowPrecisionToCGFloat(deg2rad(d)));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
-{
- m_transform = CGAffineTransformTranslate(m_transform, narrowPrecisionToCGFloat(tx), narrowPrecisionToCGFloat(ty));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
-{
- CGAffineTransform shear = CGAffineTransformMake(1.0f, narrowPrecisionToCGFloat(sy), narrowPrecisionToCGFloat(sx), 1.0f, 0.0f, 0.0f);
- m_transform = CGAffineTransformConcat(shear, m_transform);
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return m_transform.a * m_transform.d - m_transform.b * m_transform.c;
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- if (isInvertible())
- return TransformationMatrix(CGAffineTransformInvert(m_transform));
- return TransformationMatrix();
-}
-
-TransformationMatrix::operator PlatformTransformationMatrix() const
-{
- return m_transform;
-}
-
-bool TransformationMatrix::operator== (const TransformationMatrix &m2) const
-{
- return CGAffineTransformEqualToTransform(m_transform, CGAffineTransform(m2));
-}
-
-TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
-{
- m_transform = CGAffineTransformConcat(m_transform, CGAffineTransform(m2));
- return *this;
-}
-
-TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
+TransformationMatrix::operator CGAffineTransform() const
{
- return CGAffineTransformConcat(m_transform, CGAffineTransform(m2));
+ return CGAffineTransformMake(narrowPrecisionToCGFloat(a()),
+ narrowPrecisionToCGFloat(b()),
+ narrowPrecisionToCGFloat(c()),
+ narrowPrecisionToCGFloat(d()),
+ narrowPrecisionToCGFloat(e()),
+ narrowPrecisionToCGFloat(f()));
}
}
diff --git a/WebCore/platform/graphics/chromium/ColorChromium.cpp b/WebCore/platform/graphics/chromium/ColorChromium.cpp
index 16ca17d..647169c 100644
--- a/WebCore/platform/graphics/chromium/ColorChromium.cpp
+++ b/WebCore/platform/graphics/chromium/ColorChromium.cpp
@@ -28,35 +28,15 @@
namespace WebCore {
+#if !PLATFORM(DARWIN)
+// On OS X, there's code to monitor changes in the focus color system setting.
+// On Windows/Linux there is no equivalent system setting and therefore a static
+// color is all we need.
Color focusRingColor()
{
-// FIXME: This should be split up to ColorChromiumWin and ColorChromiumMac.
-#if PLATFORM(DARWIN)
- // To avoid the Mac Chromium build having to rebasline 500+ layout tests and
- // continue to do this w/ new tests that get landed in WebKit, we want to
- // run the layout tests w/ the same color that stock WebKit uses.
- //
- // TODO: For now we've hard coded the color that WebKit uses for layout
- // tests. We need to revisit this and do either of the following:
- // A. Fully honor the color from the UI, which means collecting the color
- // (and change notifications) in the browser process, and messaging the
- // color to the render process.
- // B. Adding a "layout tests" flag, to control the orage vs. blue colors
- // depending if we're running layout tests.
- // To see the WebKit implementation of using the UI color and/or a flag for
- // layout tests see WebKit/WebCore/platform/graphics/mac/ColorMac.mm.
- // (Reality is we just need an api to override the focus color and both
- // of the above are covered for what this file needs to provide, the
- // two options would be details that happen in other places.)
-
- // From WebKit:
- // static RGBA32 oldAquaFocusRingColorRGBA = 0xFF7DADD9;
- static Color oldAquaFocusRingColor(0x7D, 0xAD, 0xD9, 0xFF);
- return oldAquaFocusRingColor;
-#else
static Color focusRingColor(229, 151, 0, 255);
return focusRingColor;
-#endif
}
+#endif
} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/ColorChromiumMac.mm b/WebCore/platform/graphics/chromium/ColorChromiumMac.mm
new file mode 100644
index 0000000..01dff7e
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/ColorChromiumMac.mm
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#import <AppKit/NSColor.h>
+#import <wtf/Assertions.h>
+#import <wtf/StdLibExtras.h>
+#import <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+Color focusRingColor()
+{
+ // To avoid the Mac Chromium build having to rebasline 500+ layout tests and
+ // continue to do this w/ new tests that get landed in WebKit, we want to
+ // run the layout tests w/ the same color that stock WebKit uses.
+ //
+ // FIXME: For now we've hard coded the color that WebKit uses for layout
+ // tests. We need to revisit this and do either of the following:
+ // A. Fully honor the color from the UI, which means collecting the color
+ // (and change notifications) in the browser process, and messaging the
+ // color to the render process.
+ // B. Adding a "layout tests" flag, to control the orage vs. blue colors
+ // depending if we're running layout tests.
+ // To see the WebKit implementation of using the UI color and/or a flag for
+ // layout tests see WebKit/WebCore/platform/graphics/mac/ColorMac.mm.
+ // (Reality is we just need an api to override the focus color and both
+ // of the above are covered for what this file needs to provide, the
+ // two options would be details that happen in other places.)
+
+ // From WebKit:
+ // static RGBA32 oldAquaFocusRingColorRGBA = 0xFF7DADD9;
+ static Color oldAquaFocusRingColor(0x7D, 0xAD, 0xD9, 0xFF);
+ return oldAquaFocusRingColor;
+}
+
+// createCGColor() and the functions it calls are verbatum copies of
+// graphics/mac/ColorMac.mm. These are copied here so that we don't need to
+// include ColorMac.mm in the Chromium build.
+// FIXME: Check feasibility of using pure CG calls and unifying this copy with
+// ColorMac.mm's under graphics/cg.
+
+NSColor* nsColor(const Color& color)
+{
+ unsigned c = color.rgb();
+ switch (c) {
+ case 0: {
+ // Need this to avoid returning nil because cachedRGBAValues will default to 0.
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:0.0f]));
+ return clearColor.get();
+ }
+ case Color::black: {
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:1.0f]));
+ return blackColor.get();
+ }
+ case Color::white: {
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f]));
+ return whiteColor.get();
+ }
+ default: {
+ const int cacheSize = 32;
+ static unsigned cachedRGBAValues[cacheSize];
+ static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize];
+
+ for (int i = 0; i != cacheSize; ++i)
+ if (cachedRGBAValues[i] == c)
+ return cachedColors[i].get();
+
+ NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f
+ green:color.green() / 255.0f
+ blue:color.blue() / 255.0f
+ alpha:color.alpha() /255.0f];
+
+ static int cursor;
+ cachedRGBAValues[cursor] = c;
+ cachedColors[cursor] = result;
+ if (++cursor == cacheSize)
+ cursor = 0;
+ return result;
+ }
+ }
+}
+
+static CGColorRef CGColorFromNSColor(NSColor* color)
+{
+ // This needs to always use device colorspace so it can de-calibrate the color for
+ // CGColor to possibly recalibrate it.
+ NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+ CGFloat red = [deviceColor redComponent];
+ CGFloat green = [deviceColor greenComponent];
+ CGFloat blue = [deviceColor blueComponent];
+ CGFloat alpha = [deviceColor alphaComponent];
+ const CGFloat components[4] = { red, green, blue, alpha };
+ static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB();
+ CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components);
+ return cgColor;
+}
+
+CGColorRef createCGColor(const Color& c)
+{
+ // We could directly create a CGColor here, but that would
+ // skip any RGB caching the nsColor method does. A direct
+ // creation could be investigated for a possible performance win.
+ return CGColorFromNSColor(nsColor(c));
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
index 03583a0..129776e 100644
--- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
@@ -394,53 +394,18 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons
family = panUniFonts[i];
data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)));
}
- if (i < numFonts) // we found the font that covers this character !
+ // When i-th font (0-base) in |panUniFonts| contains a character and
+ // we get out of the loop, |i| will be |i + 1|. That is, if only the
+ // last font in the array covers the character, |i| will be numFonts.
+ // So, we have to use '<=" rather than '<' to see if we found a font
+ // covering the character.
+ if (i <= numFonts)
return getCachedFontData(data);
return 0;
}
-const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName)
-{
- // Note that mapping to Courier is removed because
- // because it's a bitmap font on Windows.
- // Alias Courier -> Courier New
- static AtomicString courier("Courier"), courierNew("Courier New");
- if (equalIgnoringCase(familyName, courier))
- return courierNew;
-
- // Alias Times <-> Times New Roman.
- static AtomicString times("Times"), timesNewRoman("Times New Roman");
- if (equalIgnoringCase(familyName, times))
- return timesNewRoman;
- if (equalIgnoringCase(familyName, timesNewRoman))
- return times;
-
- // Alias Helvetica <-> Arial
- static AtomicString arial("Arial"), helvetica("Helvetica");
- if (equalIgnoringCase(familyName, helvetica))
- return arial;
- if (equalIgnoringCase(familyName, arial))
- return helvetica;
-
- // We block bitmap fonts altogether so that we have to
- // alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font)
- static AtomicString msSans("MS Sans Serif");
- static AtomicString microsoftSans("Microsoft Sans Serif");
- if (equalIgnoringCase(familyName, msSans))
- return microsoftSans;
-
- // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no
- // 'Microsoft Sans Serif-equivalent' for Serif.
- static AtomicString msSerif("MS Serif");
- if (equalIgnoringCase(familyName, msSerif))
- return timesNewRoman;
-
- // FIXME: should we map 'system' to something ('Tahoma') ?
- return emptyAtom;
-}
-
FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
{
return 0;
diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
index f187c55..89433e1 100644
--- a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
@@ -91,16 +91,6 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font,
return ret;
}
-const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName)
-{
- notImplemented();
-
- // This is just to stop GCC emitting a warning about returning a reference
- // to a temporary variable
- static AtomicString a;
- return a;
-}
-
FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
{
return 0;
diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
index 3cf18a6..1b71946 100644
--- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
@@ -32,7 +32,6 @@
#include "config.h"
#include "Font.h"
-#include "TransformationMatrix.h"
#include "ChromiumBridge.h"
#include "FontFallbackList.h"
#include "GlyphBuffer.h"
@@ -40,6 +39,7 @@
#include "SimpleFontData.h"
#include "SkiaFontWin.h"
#include "SkiaUtils.h"
+#include "TransparencyWin.h"
#include "UniscribeHelperTextRun.h"
#include "skia/ext/platform_canvas_win.h"
@@ -49,122 +49,274 @@
namespace WebCore {
-static bool windowsCanHandleTextDrawing(GraphicsContext* context)
+namespace {
+
+bool canvasHasMultipleLayers(const SkCanvas* canvas)
+{
+ SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
+ iter.next(); // There is always at least one layer.
+ return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
+}
+
+class TransparencyAwareFontPainter {
+public:
+ TransparencyAwareFontPainter(GraphicsContext*, const FloatPoint&);
+ ~TransparencyAwareFontPainter();
+
+protected:
+ // Called by our subclass' constructor to initialize GDI if necessary. This
+ // is a separate function so it can be called after the subclass finishes
+ // construction (it calls virtual functions).
+ void init();
+
+ virtual IntRect estimateTextBounds() = 0;
+
+ // Use the context from the transparency helper when drawing with GDI. It
+ // may point to a temporary one.
+ GraphicsContext* m_graphicsContext;
+ PlatformGraphicsContext* m_platformContext;
+
+ FloatPoint m_point;
+
+ // Set when Windows can handle the type of drawing we're doing.
+ bool m_useGDI;
+
+ // These members are valid only when m_useGDI is set.
+ HDC m_hdc;
+ TransparencyWin m_transparency;
+
+private:
+ // Call when we're using GDI mode to initialize the TransparencyWin to help
+ // us draw GDI text.
+ void initializeForGDI();
+
+ bool m_createdTransparencyLayer; // We created a layer to give the font some alpha.
+};
+
+TransparencyAwareFontPainter::TransparencyAwareFontPainter(GraphicsContext* context,
+ const FloatPoint& point)
+ : m_graphicsContext(context)
+ , m_platformContext(context->platformContext())
+ , m_point(point)
+ , m_useGDI(windowsCanHandleTextDrawing(context))
+ , m_hdc(0)
+ , m_createdTransparencyLayer(false)
+{
+}
+
+void TransparencyAwareFontPainter::init()
{
- // Check for non-translation transforms. Sometimes zooms will look better in
- // Skia, and sometimes better in Windows. The main problem is that zooming
- // in using Skia will show you the hinted outlines for the smaller size,
- // which look weird. All else being equal, it's better to use Windows' text
- // drawing, so we don't check for zooms.
- const TransformationMatrix& matrix = context->getCTM();
- if (matrix.b() != 0 || matrix.c() != 0) // Check for skew.
- return false;
-
- // Check for stroke effects.
- if (context->platformContext()->getTextDrawingMode() != cTextFill)
- return false;
-
- // Check for shadow effects.
- if (context->platformContext()->getDrawLooper())
- return false;
-
- return true;
+ if (m_useGDI)
+ initializeForGDI();
}
-// Skia equivalents to Windows text drawing functions. They
-// will get the outlines from Windows and draw then using Skia using the given
-// parameters in the paint arguments. This allows more complex effects and
-// transforms to be drawn than Windows allows.
-//
-// These functions will be significantly slower than Windows GDI, and the text
-// will look different (no ClearType), so use only when necessary.
-//
-// When you call a Skia* text drawing function, various glyph outlines will be
-// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont
-// when the font is destroyed so that the cache does not outlive the font (since
-// the HFONTs are recycled).
-
-// Analog of the Windows GDI function DrawText, except using the given SkPaint
-// attributes for the text. See above for more.
-//
-// Returns true of the text was drawn successfully. False indicates an error
-// from Windows.
-static bool skiaDrawText(HFONT hfont,
- SkCanvas* canvas,
- const SkPoint& point,
- SkPaint* paint,
- const WORD* glyphs,
- const int* advances,
- int numGlyphs)
+void TransparencyAwareFontPainter::initializeForGDI()
{
- HDC dc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(dc, hfont);
-
- canvas->save();
- canvas->translate(point.fX, point.fY);
-
- for (int i = 0; i < numGlyphs; i++) {
- const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);
- if (!path)
- return false;
- canvas->drawPath(*path, *paint);
- canvas->translate(advances[i], 0);
+ SkColor color = m_platformContext->effectiveFillColor();
+ if (SkColorGetA(color) != 0xFF) {
+ // When the font has some transparency, apply it by creating a new
+ // transparency layer with that opacity applied.
+ m_createdTransparencyLayer = true;
+ m_graphicsContext->beginTransparencyLayer(SkColorGetA(color) / 255.0f);
+ // The color should be opaque now.
+ color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
}
- canvas->restore();
+ TransparencyWin::LayerMode layerMode;
+ IntRect layerRect;
+ if (m_platformContext->isDrawingToImageBuffer()) {
+ // Assume if we're drawing to an image buffer that the background
+ // is not opaque and we have to undo ClearType. We may want to
+ // enhance this to actually check, since it will often be opaque
+ // and we could do ClearType in that case.
+ layerMode = TransparencyWin::TextComposite;
+ layerRect = estimateTextBounds();
+
+ // The transparency helper requires that we draw text in black in
+ // this mode and it will apply the color.
+ m_transparency.setTextCompositeColor(color);
+ color = SkColorSetRGB(0, 0, 0);
+ } else if (canvasHasMultipleLayers(m_platformContext->canvas())) {
+ // When we're drawing a web page, we know the background is opaque,
+ // but if we're drawing to a layer, we still need extra work.
+ layerMode = TransparencyWin::OpaqueCompositeLayer;
+ layerRect = estimateTextBounds();
+ } else {
+ // Common case of drawing onto the bottom layer of a web page: we
+ // know everything is opaque so don't need to do anything special.
+ layerMode = TransparencyWin::NoLayer;
+ }
+ m_transparency.init(m_graphicsContext, layerMode, TransparencyWin::KeepTransform, layerRect);
- SelectObject(dc, oldFont);
- ReleaseDC(0, dc);
- return true;
+ // Set up the DC, using the one from the transparency helper.
+ m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint();
+ SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(m_hdc, TRANSPARENT);
}
-static bool paintSkiaText(PlatformContextSkia* platformContext,
- HFONT hfont,
- int numGlyphs,
- const WORD* glyphs,
- const int* advances,
- const SkPoint& origin)
+TransparencyAwareFontPainter::~TransparencyAwareFontPainter()
{
- int textMode = platformContext->getTextDrawingMode();
-
- // Filling (if necessary). This is the common case.
- SkPaint paint;
- platformContext->setupPaintForFilling(&paint);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- bool didFill = false;
- if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) {
- if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs))
- return false;
- didFill = true;
- }
+ if (!m_useGDI)
+ return; // Nothing to do.
+ m_transparency.composite();
+ if (m_createdTransparencyLayer)
+ m_graphicsContext->endTransparencyLayer();
+ m_platformContext->canvas()->endPlatformPaint();
+}
- // Stroking on top (if necessary).
- if ((textMode & WebCore::cTextStroke)
- && platformContext->getStrokeStyle() != NoStroke
- && platformContext->getStrokeThickness() > 0) {
-
- paint.reset();
- platformContext->setupPaintForStroking(&paint, 0, 0);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
- if (didFill) {
- // If there is a shadow and we filled above, there will already be
- // a shadow. We don't want to draw it again or it will be too dark
- // and it will go on top of the fill.
- //
- // Note that this isn't strictly correct, since the stroke could be
- // very thick and the shadow wouldn't account for this. The "right"
- // thing would be to draw to a new layer and then draw that layer
- // with a shadow. But this is a lot of extra work for something
- // that isn't normally an issue.
- paint.setLooper(0)->safeUnref();
- }
+// Specialization for simple GlyphBuffer painting.
+class TransparencyAwareGlyphPainter : public TransparencyAwareFontPainter {
+ public:
+ TransparencyAwareGlyphPainter(GraphicsContext*,
+ const SimpleFontData*,
+ const GlyphBuffer&,
+ int from, int numGlyphs,
+ const FloatPoint&);
+ ~TransparencyAwareGlyphPainter();
+
+ // Draws the partial string of glyphs, starting at |startAdvance| to the
+ // left of m_point. We express it this way so that if we're using the Skia
+ // drawing path we can use floating-point positioning, even though we have
+ // to use integer positioning in the GDI path.
+ bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, int startAdvance) const;
+
+ private:
+ virtual IntRect estimateTextBounds();
+
+ const SimpleFontData* m_font;
+ const GlyphBuffer& m_glyphBuffer;
+ int m_from;
+ int m_numGlyphs;
+
+ // When m_useGdi is set, this stores the previous HFONT selected into the
+ // m_hdc so we can restore it.
+ HGDIOBJ m_oldFont; // For restoring the DC to its original state.
+};
+
+TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter(
+ GraphicsContext* context,
+ const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs,
+ const FloatPoint& point)
+ : TransparencyAwareFontPainter(context, point)
+ , m_font(font)
+ , m_glyphBuffer(glyphBuffer)
+ , m_from(from)
+ , m_numGlyphs(numGlyphs)
+ , m_oldFont(0)
+{
+ init();
+
+ m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
+}
- if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs))
- return false;
+TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter()
+{
+ if (m_useGDI)
+ ::SelectObject(m_hdc, m_oldFont);
+}
+
+
+// Estimates the bounding box of the given text. This is copied from
+// FontCGWin.cpp, it is possible, but a lot more work, to get the precide
+// bounds.
+IntRect TransparencyAwareGlyphPainter::estimateTextBounds()
+{
+ int totalWidth = 0;
+ for (int i = 0; i < m_numGlyphs; i++)
+ totalWidth += lroundf(m_glyphBuffer.advanceAt(m_from + i));
+
+ return IntRect(m_point.x() - (m_font->ascent() + m_font->descent()) / 2,
+ m_point.y() - m_font->ascent() - m_font->lineGap(),
+ totalWidth + m_font->ascent() + m_font->descent(),
+ m_font->lineSpacing());
+}
+
+bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ int startAdvance) const
+{
+ if (!m_useGDI) {
+ SkPoint origin = m_point;
+ origin.fX += startAdvance;
+ return paintSkiaText(m_graphicsContext, m_font->platformData().hfont(),
+ numGlyphs, glyphs, advances, 0, &origin);
}
- return true;
+
+ // Windows' origin is the top-left of the bounding box, so we have
+ // to subtract off the font ascent to get it.
+ int x = lroundf(m_point.x() + startAdvance);
+ int y = lroundf(m_point.y() - m_font->ascent());
+ return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
+}
+
+
+class TransparencyAwareUniscribePainter : public TransparencyAwareFontPainter {
+ public:
+ TransparencyAwareUniscribePainter(GraphicsContext*,
+ const Font*,
+ const TextRun&,
+ int from, int to,
+ const FloatPoint&);
+ ~TransparencyAwareUniscribePainter();
+
+ // Uniscibe will draw directly into our buffer, so we need to expose our DC.
+ HDC hdc() const { return m_hdc; }
+
+ private:
+ virtual IntRect estimateTextBounds();
+
+ const Font* m_font;
+ const TextRun& m_run;
+ int m_from;
+ int m_to;
+};
+
+TransparencyAwareUniscribePainter::TransparencyAwareUniscribePainter(
+ GraphicsContext* context,
+ const Font* font,
+ const TextRun& run,
+ int from, int to,
+ const FloatPoint& point)
+ : TransparencyAwareFontPainter(context, point)
+ , m_font(font)
+ , m_run(run)
+ , m_from(from)
+ , m_to(to)
+{
+ init();
}
+TransparencyAwareUniscribePainter::~TransparencyAwareUniscribePainter()
+{
+}
+
+IntRect TransparencyAwareUniscribePainter::estimateTextBounds()
+{
+ // This case really really sucks. There is no convenient way to estimate
+ // the bounding box. So we run Uniscribe twice. If we find this happens a
+ // lot, the way to fix it is to make the extra layer after the
+ // UniscribeHelper has measured the text.
+ IntPoint intPoint(lroundf(m_point.x()),
+ lroundf(m_point.y()));
+
+ UniscribeHelperTextRun state(m_run, *m_font);
+ int left = lroundf(m_point.x()) + state.characterToX(m_from);
+ int right = lroundf(m_point.x()) + state.characterToX(m_to);
+
+ // This algorithm for estimating how much extra space we need (the text may
+ // go outside the selection rect) is based roughly on
+ // TransparencyAwareGlyphPainter::estimateTextBounds above.
+ return IntRect(left - (m_font->ascent() + m_font->descent()) / 2,
+ m_point.y() - m_font->ascent() - m_font->lineGap(),
+ (right - left) + m_font->ascent() + m_font->descent(),
+ m_font->lineSpacing());
+}
+
+} // namespace
+
void Font::drawGlyphs(GraphicsContext* graphicsContext,
const SimpleFontData* font,
const GlyphBuffer& glyphBuffer,
@@ -172,51 +324,27 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
int numGlyphs,
const FloatPoint& point) const
{
- PlatformGraphicsContext* context = graphicsContext->platformContext();
-
- // Max buffer length passed to the underlying windows API.
- const int kMaxBufferLength = 1024;
- // Default size for the buffer. It should be enough for most of cases.
- const int kDefaultBufferLength = 256;
-
- SkColor color = context->fillColor();
+ SkColor color = graphicsContext->platformContext()->effectiveFillColor();
unsigned char alpha = SkColorGetA(color);
// Skip 100% transparent text; no need to draw anything.
- if (!alpha && context->getStrokeStyle() == NoStroke)
+ if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
return;
- // Set up our graphics context.
- HDC hdc = context->canvas()->beginPlatformPaint();
- HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont());
-
- // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
- // Enforce non-transparent color.
- color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
- SetTextColor(hdc, skia::SkColorToCOLORREF(color));
- SetBkMode(hdc, TRANSPARENT);
-
- // Windows needs the characters and the advances in nice contiguous
- // buffers, which we build here.
- Vector<WORD, kDefaultBufferLength> glyphs;
- Vector<int, kDefaultBufferLength> advances;
-
- // Compute the coordinate. The 'origin' represents the baseline, so we need
- // to move it up to the top of the bounding square.
- int x = static_cast<int>(point.x());
- int lineTop = static_cast<int>(point.y()) - font->ascent();
-
- bool canUseGDI = windowsCanHandleTextDrawing(graphicsContext);
+ TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
// We draw the glyphs in chunks to avoid having to do a heap allocation for
// the arrays of characters and advances. Since ExtTextOut is the
// lowest-level text output function on Windows, there should be little
// penalty for splitting up the text. On the other hand, the buffer cannot
// be bigger than 4094 or the function will fail.
- int glyphIndex = 0;
+ const int kMaxBufferLength = 256;
+ Vector<WORD, kMaxBufferLength> glyphs;
+ Vector<int, kMaxBufferLength> advances;
+ int glyphIndex = 0; // The starting glyph of the current chunk.
+ int curAdvance = 0; // How far from the left the current chunk is.
while (glyphIndex < numGlyphs) {
- // how many chars will be in this chunk?
+ // How many chars will be in this chunk?
int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
-
glyphs.resize(curLen);
advances.resize(curLen);
@@ -227,17 +355,10 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
curWidth += advances[i];
}
+ // Actually draw the glyphs (with retry on failure).
bool success = false;
for (int executions = 0; executions < 2; ++executions) {
- if (canUseGDI)
- success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), curLen, &advances[0]);
- else {
- // Skia's text draing origin is the baseline, like WebKit, not
- // the top, like Windows.
- SkPoint origin = { x, point.y() };
- success = paintSkiaText(context, font->platformData().hfont(), numGlyphs, reinterpret_cast<const WORD*>(&glyphs[0]), &advances[0], origin);
- }
-
+ success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], curAdvance);
if (!success && executions == 0) {
// Ask the browser to load the font for us and retry.
ChromiumBridge::ensureFontLoaded(font->platformData().hfont());
@@ -247,12 +368,8 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
}
ASSERT(success);
-
- x += curWidth;
+ curAdvance += curWidth;
}
-
- SelectObject(hdc, oldFont);
- context->canvas()->endPlatformPaint();
}
FloatRect Font::selectionRectForComplexText(const TextRun& run,
@@ -283,13 +400,15 @@ void Font::drawComplexText(GraphicsContext* graphicsContext,
PlatformGraphicsContext* context = graphicsContext->platformContext();
UniscribeHelperTextRun state(run, *this);
- SkColor color = context->fillColor();
+ SkColor color = graphicsContext->platformContext()->effectiveFillColor();
unsigned char alpha = SkColorGetA(color);
// Skip 100% transparent text; no need to draw anything.
- if (!alpha)
+ if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
return;
- HDC hdc = context->canvas()->beginPlatformPaint();
+ TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point);
+
+ HDC hdc = painter.hdc();
// TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
// Enforce non-transparent color.
@@ -299,7 +418,9 @@ void Font::drawComplexText(GraphicsContext* graphicsContext,
// Uniscribe counts the coordinates from the upper left, while WebKit uses
// the baseline, so we have to subtract off the ascent.
- state.draw(hdc, static_cast<int>(point.x()), static_cast<int>(point.y() - ascent()), from, to);
+ state.draw(graphicsContext, hdc, static_cast<int>(point.x()),
+ static_cast<int>(point.y() - ascent()), from, to);
+
context->canvas()->endPlatformPaint();
}
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
index 8f8df88..1e923ac 100644
--- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
@@ -116,7 +116,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
// Streams the concatenation of a header and font data.
class EOTStream {
public:
- EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
+ EOTStream(const Vector<uint8_t, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
: m_eotHeader(eotHeader)
, m_fontData(fontData)
, m_overlayDst(overlayDst)
@@ -130,7 +130,7 @@ public:
size_t read(void* buffer, size_t count);
private:
- const Vector<UInt8, 512>& m_eotHeader;
+ const Vector<uint8_t, 512>& m_eotHeader;
const SharedBuffer* m_fontData;
size_t m_overlayDst;
size_t m_overlaySrc;
@@ -200,7 +200,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
// TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data,
// so we need to create an EOT header and prepend it to the font data.
- Vector<UInt8, 512> eotHeader;
+ Vector<uint8_t, 512> eotHeader;
size_t overlayDst;
size_t overlaySrc;
size_t overlayLength;
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
index 7a3e614..2b7c562 100644
--- a/WebCore/platform/graphics/chromium/FontLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -49,14 +49,6 @@ namespace WebCore {
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
const FloatPoint& point) const {
- SkCanvas* canvas = gc->platformContext()->canvas();
- SkPaint paint;
-
- gc->platformContext()->setupPaintCommon(&paint);
- font->platformData().setupPaint(&paint);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setColor(gc->fillColor().rgb());
-
SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
@@ -78,7 +70,39 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
x += SkFloatToScalar(adv[i].width());
y += SkFloatToScalar(adv[i].height());
}
- canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+
+ SkCanvas* canvas = gc->platformContext()->canvas();
+ int textMode = gc->platformContext()->getTextDrawingMode();
+
+ // We draw text up to two times (once for fill, once for stroke).
+ if (textMode & cTextFill) {
+ SkPaint paint;
+ gc->platformContext()->setupPaintForFilling(&paint);
+ font->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->fillColor().rgb());
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+ }
+
+ if ((textMode & cTextStroke)
+ && gc->platformContext()->getStrokeStyle() != NoStroke
+ && gc->platformContext()->getStrokeThickness() > 0) {
+
+ SkPaint paint;
+ gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
+ font->platformData().setupPaint(&paint);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->strokeColor().rgb());
+
+ if (textMode & cTextFill) {
+ // If we also filled, we don't want to draw shadows twice.
+ // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
+ paint.setLooper(0)->safeUnref();
+ }
+
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+ }
}
void Font::drawComplexText(GraphicsContext* context, const TextRun& run,
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
index 86f96ee..7b7d197 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
@@ -86,7 +86,7 @@ void FontPlatformData::setupPaint(SkPaint* paint) const
{
const float ts = m_textSize > 0 ? m_textSize : 12;
- paint->setAntiAlias(false);
+ paint->setAntiAlias(true);
paint->setSubpixelText(false);
paint->setTextSize(SkFloatToScalar(ts));
paint->setTypeface(m_typeface);
diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
index 4c5cf7b..31c5256 100644
--- a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
@@ -147,27 +147,17 @@ static bool fillBMPGlyphs(unsigned offset,
// When this character should be a space, we ignore whatever the font
// says and use a space. Otherwise, if fonts don't map one of these
// space or zero width glyphs, we will get a box.
- if (Font::treatAsSpace(c))
+ if (Font::treatAsSpace(c)) {
// Hard code the glyph indices for characters that should be
// treated like spaces.
glyph = initSpaceGlyph(dc, &spaceGlyph);
- else if (Font::treatAsZeroWidthSpace(c) || c == 0x200B) {
- // FIXME: change Font::treatAsZeroWidthSpace to use
- // u_hasBinaryProperty, per jungshik's comment here:
- // https://bugs.webkit.org/show_bug.cgi?id=20237#c6.
- // Then the additional OR above won't be necessary.
- glyph = initSpaceGlyph(dc, &spaceGlyph);
- glyphFontData = fontData->zeroWidthFontData();
} else if (glyph == invalidGlyph) {
// WebKit expects both the glyph index and FontData
// pointer to be 0 if the glyph is not present
glyph = 0;
glyphFontData = 0;
- } else {
- if (SimpleFontData::isCJKCodePoint(c))
- glyphFontData = fontData->cjkWidthFontData();
+ } else
haveGlyphs = true;
- }
page->setGlyphDataForCharacter(offset + i, glyph, glyphFontData);
}
@@ -205,6 +195,7 @@ static bool fillNonBMPGlyphs(unsigned offset,
fontData->m_font.scriptCache(),
fontData->m_font.scriptFontProperties());
state.setInhibitLigate(true);
+ state.setDisableFontFallback(true);
state.init();
for (unsigned i = 0; i < length; i++) {
diff --git a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
index 959147a..e8ba0ad 100644
--- a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
+++ b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
@@ -33,13 +33,13 @@
#if ENABLE(VIDEO)
-#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
namespace WebCore {
-class MediaPlayerPrivate : public Noncopyable {
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
public:
- MediaPlayerPrivate(MediaPlayer*);
+ static void registerMediaEngine(MediaEngineRegistrar);
~MediaPlayerPrivate();
IntSize naturalSize() const;
@@ -74,13 +74,10 @@ public:
unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect&);
+ void setSize(const IntSize&);
void paint(GraphicsContext*, const IntRect&);
- static void getSupportedTypes(HashSet<String>&);
- static bool isAvailable();
-
// Public methods to be called by WebMediaPlayer
FrameView* frameView();
void networkStateChanged();
@@ -90,6 +87,12 @@ public:
void repaint();
private:
+ MediaPlayerPrivate(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
MediaPlayer* m_player;
void* m_data;
};
diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp
deleted file mode 100644
index 798ee32..0000000
--- a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Google 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:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ThemeHelperChromiumWin.h"
-
-#include "FloatRect.h"
-#include "GraphicsContext.h"
-
-namespace WebCore {
-
-ThemeHelperWin::ThemeHelperWin(GraphicsContext* context, const IntRect& rect)
- : m_orgContext(context)
- , m_orgMatrix(context->getCTM())
- , m_orgRect(rect)
-{
- if (m_orgMatrix.b() != 0 || m_orgMatrix.c() != 0) { // Check for skew.
- // Complicated effects, make a copy and draw the bitmap there.
- m_type = COPY;
- m_rect.setSize(rect.size());
-
- m_newBuffer.set(ImageBuffer::create(rect.size(), false).release());
-
- // Theme drawing messes with the transparency.
- // FIXME: Ideally, we would leave this transparent, but I was
- // having problems with button drawing, so we fill with white. Buttons
- // looked good with transparent here and no fixing up of the alpha
- // later, but text areas didn't. This makes text areas look good but
- // gives buttons a white halo. Is there a way to fix this? I think
- // buttons actually have antialised edges which is just not possible
- // to handle on a transparent background given that it messes with the
- // alpha channel.
- FloatRect newContextRect(0, 0, rect.width(), rect.height());
- GraphicsContext* newContext = m_newBuffer->context();
- newContext->setFillColor(Color::white);
- newContext->fillRect(newContextRect);
-
- return;
- }
-
- if (m_orgMatrix.a() != 1.0 || m_orgMatrix.d() != 1.0) { // Check for scale.
- // Only a scaling is applied.
- m_type = SCALE;
-
- // Save the transformed coordinates to draw.
- m_rect = m_orgMatrix.mapRect(rect);
-
- m_orgContext->save();
- m_orgContext->concatCTM(m_orgContext->getCTM().inverse());
- return;
- }
-
- // Nothing interesting.
- m_rect = rect;
- m_type = ORIGINAL;
-}
-
-ThemeHelperWin::~ThemeHelperWin()
-{
- switch (m_type) {
- case SCALE:
- m_orgContext->restore();
- break;
- case COPY: {
- // Copy the duplicate bitmap with our control to the original canvas.
- FloatRect destRect(m_orgRect);
- m_newBuffer->context()->platformContext()->canvas()->
- getTopPlatformDevice().fixupAlphaBeforeCompositing();
- m_orgContext->drawImage(m_newBuffer->image(), destRect);
- break;
- }
- case ORIGINAL:
- break;
- }
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h
deleted file mode 100644
index 1771fb4..0000000
--- a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Google 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:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ThemeHelperWin_h
-#define ThemeHelperWin_h
-
-#include "TransformationMatrix.h"
-#include "ImageBuffer.h"
-#include "IntRect.h"
-#include <wtf/OwnPtr.h>
-
-namespace WebCore {
-
-class GraphicsContext;
-class IntRect;
-
-// Helps drawing theme elements like buttons and scroll bars. This will handle
-// translations and scalings that Windows might not, by either making Windows
-// draw the appropriate sized control, or by rendering it into an off-screen
-// context and transforming it ourselves.
-class ThemeHelperWin {
- enum Type {
- // Use the original canvas with no changes. This is the normal mode.
- ORIGINAL,
-
- // Use the original canvas but scale the rectangle of the control so
- // that it will be the correct size, undoing any scale already on the
- // canvas. This will have the effect of just drawing the control bigger
- // or smaller and not actually expanding or contracting the pixels in
- // it. This usually looks better.
- SCALE,
-
- // Make a copy of the control and then transform it ourselves after
- // Windows draws it. This allows us to get complex effects.
- COPY,
- };
-
-public:
- // Prepares drawing a control with the given rect to the given context.
- ThemeHelperWin(GraphicsContext* context, const IntRect& rect);
- ~ThemeHelperWin();
-
- // Returns the context to draw the control into, which may be the original
- // or the copy, depending on the mode.
- GraphicsContext* context()
- {
- return m_newBuffer.get() ? m_newBuffer->context() : m_orgContext;
- }
-
- // Returns the rectangle in which to draw into the canvas() by Windows.
- const IntRect& rect() { return m_rect; }
-
-private:
- Type m_type;
-
- // The original canvas to wrote to. Not owned by this class.
- GraphicsContext* m_orgContext;
- TransformationMatrix m_orgMatrix;
- IntRect m_orgRect;
-
- // When m_type == COPY, this will be a new surface owned by this class that
- // represents the copy.
- OwnPtr<ImageBuffer> m_newBuffer;
-
- // The control rectangle in the coordinate space of canvas().
- IntRect m_rect;
-};
-
-} // namespace WebCore
-
-#endif // ThemeHelperWin_h
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
new file mode 100644
index 0000000..8c790af
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <windows.h>
+
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "PlatformContextSkia.h"
+#include "SimpleFontData.h"
+#include "TransformationMatrix.h"
+#include "TransparencyWin.h"
+
+#include "SkColorPriv.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace WebCore {
+
+namespace {
+
+// The maximum size in pixels of the buffer we'll keep around for drawing text
+// into. Buffers larger than this will be destroyed when we're done with them.
+const int maxCachedBufferPixelSize = 65536;
+
+inline skia::PlatformCanvas* canvasForContext(const GraphicsContext& context)
+{
+ return context.platformContext()->canvas();
+}
+
+inline const SkBitmap& bitmapForContext(const GraphicsContext& context)
+{
+ return canvasForContext(context)->getTopPlatformDevice().accessBitmap(false);
+}
+
+void compositeToCopy(const GraphicsContext& sourceLayers,
+ GraphicsContext& destContext,
+ const TransformationMatrix& matrix)
+{
+ // Make a list of all devices. The iterator goes top-down, and we want
+ // bottom-up. Note that each layer can also have an offset in canvas
+ // coordinates, which is the (x, y) position.
+ struct DeviceInfo {
+ DeviceInfo(SkDevice* d, int lx, int ly)
+ : device(d)
+ , x(lx)
+ , y(ly) {}
+ SkDevice* device;
+ int x;
+ int y;
+ };
+ Vector<DeviceInfo> devices;
+ SkCanvas* sourceCanvas = canvasForContext(sourceLayers);
+ SkCanvas::LayerIter iter(sourceCanvas, false);
+ while (!iter.done()) {
+ devices.append(DeviceInfo(iter.device(), iter.x(), iter.y()));
+ iter.next();
+ }
+
+ // Create a temporary canvas for the compositing into the destination.
+ SkBitmap* destBmp = const_cast<SkBitmap*>(&bitmapForContext(destContext));
+ SkCanvas destCanvas(*destBmp);
+ destCanvas.setMatrix(matrix);
+
+ for (int i = devices.size() - 1; i >= 0; i--) {
+ const SkBitmap& srcBmp = devices[i].device->accessBitmap(false);
+
+ SkRect destRect;
+ destRect.fLeft = devices[i].x;
+ destRect.fTop = devices[i].y;
+ destRect.fRight = destRect.fLeft + srcBmp.width();
+ destRect.fBottom = destRect.fTop + srcBmp.height();
+
+ destCanvas.drawBitmapRect(srcBmp, 0, destRect);
+ }
+}
+
+} // namespace
+
+// If either of these pointers is non-null, both must be valid and point to
+// bitmaps of the same size.
+class TransparencyWin::OwnedBuffers {
+public:
+ OwnedBuffers(const IntSize& size, bool needReferenceBuffer)
+ {
+ m_destBitmap.adopt(ImageBuffer::create(size, false));
+
+ if (needReferenceBuffer) {
+ m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
+ m_referenceBitmap.allocPixels();
+ m_referenceBitmap.eraseARGB(0, 0, 0, 0);
+ }
+ }
+
+ ImageBuffer* destBitmap() { return m_destBitmap.get(); }
+
+ // This bitmap will be empty if you don't specify needReferenceBuffer to the
+ // constructor.
+ SkBitmap* referenceBitmap() { return &m_referenceBitmap; }
+
+ // Returns whether the current layer will fix a buffer of the given size.
+ bool canHandleSize(const IntSize& size) const
+ {
+ return m_destBitmap->size().width() >= size.width() && m_destBitmap->size().height() >= size.height();
+ }
+
+private:
+ // The destination bitmap we're drawing into.
+ OwnPtr<ImageBuffer> m_destBitmap;
+
+ // This could be an ImageBuffer but this is an optimization. Since this is
+ // only ever used as a reference, we don't need to make a full
+ // PlatformCanvas using Skia on Windows. Just allocating a regular SkBitmap
+ // is much faster since it's just a Malloc rather than a GDI call.
+ SkBitmap m_referenceBitmap;
+};
+
+TransparencyWin::OwnedBuffers* TransparencyWin::m_cachedBuffers = 0;
+
+TransparencyWin::TransparencyWin()
+ : m_destContext(0)
+ , m_orgTransform()
+ , m_layerMode(NoLayer)
+ , m_transformMode(KeepTransform)
+ , m_drawContext(0)
+ , m_savedOnDrawContext(false)
+ , m_layerBuffer(0)
+ , m_referenceBitmap(0)
+{
+}
+
+TransparencyWin::~TransparencyWin()
+{
+ // This should be false, since calling composite() is mandatory.
+ ASSERT(!m_savedOnDrawContext);
+}
+
+void TransparencyWin::composite()
+{
+ // Matches the save() in initializeNewTextContext (or the constructor for
+ // SCALE) to put the context back into the same state we found it.
+ if (m_savedOnDrawContext) {
+ m_drawContext->restore();
+ m_savedOnDrawContext = false;
+ }
+
+ switch (m_layerMode) {
+ case NoLayer:
+ break;
+ case OpaqueCompositeLayer:
+ case WhiteLayer:
+ compositeOpaqueComposite();
+ break;
+ case TextComposite:
+ compositeTextComposite();
+ break;
+ }
+}
+
+void TransparencyWin::init(GraphicsContext* dest,
+ LayerMode layerMode,
+ TransformMode transformMode,
+ const IntRect& region)
+{
+ m_destContext = dest;
+ m_orgTransform = dest->getCTM();
+ m_layerMode = layerMode;
+ m_transformMode = transformMode;
+ m_sourceRect = region;
+
+ computeLayerSize();
+ setupLayer();
+ setupTransform(region);
+}
+
+void TransparencyWin::computeLayerSize()
+{
+ if (m_transformMode == Untransform) {
+ // The meaning of the "transformed" source rect is a little ambigous
+ // here. The rest of the code doesn't care about it in the Untransform
+ // case since we're using our own happy coordinate system. So we set it
+ // to be the source rect since that matches how the code below actually
+ // uses the variable: to determine how to translate things to account
+ // for the offset of the layer.
+ m_transformedSourceRect = m_sourceRect;
+ m_layerSize = IntSize(m_sourceRect.width(), m_sourceRect.height());
+ } else {
+ m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect);
+ m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRect.height());
+ }
+}
+
+void TransparencyWin::setupLayer()
+{
+ switch (m_layerMode) {
+ case NoLayer:
+ setupLayerForNoLayer();
+ break;
+ case OpaqueCompositeLayer:
+ setupLayerForOpaqueCompositeLayer();
+ break;
+ case TextComposite:
+ setupLayerForTextComposite();
+ break;
+ case WhiteLayer:
+ setupLayerForWhiteLayer();
+ break;
+ }
+}
+
+void TransparencyWin::setupLayerForNoLayer()
+{
+ m_drawContext = m_destContext; // Draw to the source context.
+}
+
+void TransparencyWin::setupLayerForOpaqueCompositeLayer()
+{
+ initializeNewContext();
+
+ TransformationMatrix mapping;
+ mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
+ if (m_transformMode == Untransform){
+ // Compute the inverse mapping from the canvas space to the
+ // coordinate space of our bitmap.
+ mapping = m_orgTransform.inverse() * mapping;
+ }
+ compositeToCopy(*m_destContext, *m_drawContext, mapping);
+
+ // Save the reference layer so we can tell what changed.
+ SkCanvas referenceCanvas(*m_referenceBitmap);
+ referenceCanvas.drawBitmap(bitmapForContext(*m_drawContext), 0, 0);
+ // Layer rect represents the part of the original layer.
+}
+
+void TransparencyWin::setupLayerForTextComposite()
+{
+ ASSERT(m_transformMode == KeepTransform);
+ // Fall through to filling with white.
+ setupLayerForWhiteLayer();
+}
+
+void TransparencyWin::setupLayerForWhiteLayer()
+{
+ initializeNewContext();
+ m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white);
+ // Layer rect represents the part of the original layer.
+}
+
+void TransparencyWin::setupTransform(const IntRect& region)
+{
+ switch (m_transformMode) {
+ case KeepTransform:
+ setupTransformForKeepTransform(region);
+ break;
+ case Untransform:
+ setupTransformForUntransform();
+ break;
+ case ScaleTransform:
+ setupTransformForScaleTransform();
+ break;
+ }
+}
+
+void TransparencyWin::setupTransformForKeepTransform(const IntRect& region)
+{
+ if (m_layerMode != NoLayer) {
+ // Need to save things since we're modifying the transform.
+ m_drawContext->save();
+ m_savedOnDrawContext = true;
+
+ // Account for the fact that the layer may be offset from the
+ // original. This only happens when we create a layer that has the
+ // same coordinate space as the parent.
+ TransformationMatrix xform;
+ xform.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
+
+ // We're making a layer, so apply the old transform to the new one
+ // so it's maintained. We know the new layer has the identity
+ // transform now, we we can just multiply it.
+ xform = m_orgTransform * xform;
+ m_drawContext->concatCTM(xform);
+ }
+ m_drawRect = m_sourceRect;
+}
+
+void TransparencyWin::setupTransformForUntransform()
+{
+ ASSERT(m_layerMode != NoLayer);
+ // We now have a new layer with the identity transform, which is the
+ // Untransformed space we'll use for drawing.
+ m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
+}
+
+void TransparencyWin::setupTransformForScaleTransform()
+{
+ if (m_layerMode == NoLayer) {
+ // Need to save things since we're modifying the layer.
+ m_drawContext->save();
+ m_savedOnDrawContext = true;
+
+ // Undo the transform on the current layer when we're re-using the
+ // current one.
+ m_drawContext->concatCTM(m_drawContext->getCTM().inverse());
+
+ // We're drawing to the original layer with just a different size.
+ m_drawRect = m_transformedSourceRect;
+ } else {
+ // Just go ahead and use the layer's coordinate space to draw into.
+ // It will have the scaled size, and an identity transform loaded.
+ m_drawRect = IntRect(IntPoint(0, 0), m_layerSize);
+ }
+}
+
+void TransparencyWin::setTextCompositeColor(Color color)
+{
+ m_textCompositeColor = color;
+}
+
+void TransparencyWin::initializeNewContext()
+{
+ int pixelSize = m_layerSize.width() * m_layerSize.height();
+ if (pixelSize > maxCachedBufferPixelSize) {
+ // Create a 1-off buffer for drawing into. We only need the reference
+ // buffer if we're making an OpaqueCompositeLayer.
+ bool needReferenceBitmap = m_layerMode == OpaqueCompositeLayer;
+ m_ownedBuffers.set(new OwnedBuffers(m_layerSize, needReferenceBitmap));
+
+ m_layerBuffer = m_ownedBuffers->destBitmap();
+ m_drawContext = m_layerBuffer->context();
+ if (needReferenceBitmap)
+ m_referenceBitmap = m_ownedBuffers->referenceBitmap();
+ return;
+ }
+
+ if (m_cachedBuffers && m_cachedBuffers->canHandleSize(m_layerSize)) {
+ // We can re-use the existing buffer. We don't need to clear it since
+ // all layer modes will clear it in their initialization.
+ m_layerBuffer = m_cachedBuffers->destBitmap();
+ m_drawContext = m_cachedBuffers->destBitmap()->context();
+ bitmapForContext(*m_drawContext).eraseARGB(0, 0, 0, 0);
+ m_referenceBitmap = m_cachedBuffers->referenceBitmap();
+ m_referenceBitmap->eraseARGB(0, 0, 0, 0);
+ return;
+ }
+
+ // Create a new cached buffer.
+ if (m_cachedBuffers)
+ delete m_cachedBuffers;
+ m_cachedBuffers = new OwnedBuffers(m_layerSize, true);
+
+ m_layerBuffer = m_cachedBuffers->destBitmap();
+ m_drawContext = m_cachedBuffers->destBitmap()->context();
+ m_referenceBitmap = m_cachedBuffers->referenceBitmap();
+}
+
+void TransparencyWin::compositeOpaqueComposite()
+{
+ SkCanvas* destCanvas = canvasForContext(*m_destContext);
+ destCanvas->save();
+
+ SkBitmap* bitmap = const_cast<SkBitmap*>(
+ &bitmapForContext(*m_layerBuffer->context()));
+
+ // This function will be called for WhiteLayer as well, which we don't want
+ // to change.
+ if (m_layerMode == OpaqueCompositeLayer) {
+ // Fix up our bitmap, making it contain only the pixels which changed
+ // and transparent everywhere else.
+ SkAutoLockPixels sourceLock(*m_referenceBitmap);
+ SkAutoLockPixels lock(*bitmap);
+ for (int y = 0; y < bitmap->height(); y++) {
+ uint32_t* source = m_referenceBitmap->getAddr32(0, y);
+ uint32_t* dest = bitmap->getAddr32(0, y);
+ for (int x = 0; x < bitmap->width(); x++) {
+ // Clear out any pixels that were untouched.
+ if (dest[x] == source[x])
+ dest[x] = 0;
+ else
+ dest[x] |= (0xFF << SK_A32_SHIFT);
+ }
+ }
+ } else
+ makeLayerOpaque();
+
+ SkRect destRect;
+ if (m_transformMode != Untransform) {
+ // We want to use Untransformed space.
+ //
+ // Note that we DON'T call m_layerBuffer->image() here. This actually
+ // makes a copy of the image, which is unnecessary and slow. Instead, we
+ // just draw the image from inside the destination context.
+ SkMatrix identity;
+ identity.reset();
+ destCanvas->setMatrix(identity);
+
+ destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom());
+ } else
+ destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.right(), m_sourceRect.bottom());
+
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+ paint.setAntiAlias(true);
+
+ // Note that we need to specify the source layer subset, since the bitmap
+ // may have been cached and it could be larger than what we're using.
+ SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
+ destCanvas->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint);
+ destCanvas->restore();
+}
+
+void TransparencyWin::compositeTextComposite()
+{
+ const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopPlatformDevice().accessBitmap(true);
+ SkColor textColor = m_textCompositeColor.rgb();
+ for (int y = 0; y < m_layerSize.height(); y++) {
+ uint32_t* row = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_layerSize.width(); x++) {
+ // The alpha is the average of the R, G, and B channels.
+ int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) + SkGetPackedB32(row[x])) / 3;
+
+ // Apply that alpha to the text color and write the result.
+ row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha));
+ }
+ }
+
+ // Now the layer has text with the proper color and opacity.
+ SkCanvas* destCanvas = canvasForContext(*m_destContext);
+
+ // We want to use Untransformed space (see above)
+ SkMatrix identity;
+ identity.reset();
+ destCanvas->setMatrix(identity);
+ SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.right(), m_transformedSourceRect.bottom() };
+
+ // Note that we need to specify the source layer subset, since the bitmap
+ // may have been cached and it could be larger than what we're using.
+ SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
+ destCanvas->drawBitmapRect(bitmap, &sourceRect, destRect, 0);
+ destCanvas->restore();
+}
+
+void TransparencyWin::makeLayerOpaque()
+{
+ SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()->
+ canvas()->getTopPlatformDevice().accessBitmap(true));
+ for (int y = 0; y < m_layerSize.height(); y++) {
+ uint32_t* row = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_layerSize.width(); x++)
+ row[x] |= 0xFF000000;
+ }
+}
+
+} // namespace WebCore
+
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.h b/WebCore/platform/graphics/chromium/TransparencyWin.h
new file mode 100644
index 0000000..e1963b3
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TransparencyWin_h
+#define TransparencyWin_h
+
+#include <windows.h>
+
+#include "ImageBuffer.h"
+#include "Noncopyable.h"
+#include "TransformationMatrix.h"
+#include "wtf/OwnPtr.h"
+
+class SkBitmap;
+class SkCanvas;
+
+namespace WebCore {
+
+class GraphicsContext;
+class TransparencyWin_NoLayer_Test;
+class TransparencyWin_WhiteLayer_Test;
+class TransparencyWin_TextComposite_Test;
+class TransparencyWin_OpaqueCompositeLayer_Test;
+
+// Helper class that abstracts away drawing ClearType text and Windows form
+// controls either to the original context directly, or to an offscreen context
+// that is composited later manually. This is to get around Windows' inability
+// to handle the alpha channel, semitransparent text, and transformed form
+// controls.
+class TransparencyWin : public Noncopyable {
+public:
+ enum LayerMode {
+ // No extra layer is created. Drawing will happen to the source.
+ // Valid only with KeepTransform and ScaleTransform. The region being
+ // drawn onto must be opaque, since the modified region will be forced
+ // to opaque when drawing is complete.
+ NoLayer,
+
+ // Makes a temporary layer consisting of the composited layers below
+ // it. This result must be opaque. When complete, the result will be
+ // compared to the original, and the difference will be added to a thee
+ // destination layer.
+ //
+ // This mode only works if the lower layers are opque (normally the
+ // case for a web page) and layers are only drawn in the stack order,
+ // meaning you can never draw underneath a layer.
+ //
+ // This doesn't technically produce the correct answer in all cases. If
+ // you have an opaque base, a transparency layer, than a semitransparent
+ // drawing on top, the result will actually be blended in twice. But
+ // this isn't a very important case. This mode is used for form
+ // controls which are always opaque except for occationally some
+ // antialiasing. It means form control antialiasing will be too light in
+ // some cases, but only if you have extra layers.
+ OpaqueCompositeLayer,
+
+ // Allows semitransparent text to be drawn on any background (even if it
+ // is itself semitransparent), but disables ClearType.
+ //
+ // It makes a trmporary layer filled with white. This is composited with
+ // the lower layer with a custom color applied to produce the result.
+ // The caller must draw the text in black, and set the desired final
+ // text color by calling setTextCompositeColor().
+ //
+ // Only valid with KeepTransform, which is the only mode where drawing
+ // text in this fashion makes sense.
+ TextComposite,
+
+ // Makes a temporary layer filled with white. When complete, the layer
+ // will be forced to be opqaue (since Windows may have messed up the
+ // alpha channel) and composited down. Any areas not drawn into will
+ // remain white.
+ //
+ // This is the mode of last resort. If the opacity of the final image
+ // is unknown and we can't do the text trick (since we know its color),
+ // then we have to live with potential white halos. This is used for
+ // form control drawing, for example.
+ WhiteLayer,
+ };
+
+ enum TransformMode {
+ // There are no changes to the transform. Use this when drawing
+ // horizontal text. The current transform must not have rotation.
+ KeepTransform,
+
+ // Drawing happens in an Untransformed space, and then that bitmap is
+ // transformed according to the current context when it is copied down.
+ // Requires that a layer be created (layer mode is not NoLayer).
+ Untransform,
+
+ // When the current transform only has a scaling factor applied and
+ // you're drawing form elements, use this parameter. This will unscale
+ // the coordinate space, so the OS will just draw the form controls
+ // larger or smaller depending on the destination size.
+ ScaleTransform,
+ };
+
+ // You MUST call init() below.
+ // |region| is expressed relative to the current transformation.
+ TransparencyWin();
+ ~TransparencyWin();
+
+ // Initializes the members if you use the 0-argument constructor. Don't call
+ // this if you use the multiple-argument constructor.
+ void init(GraphicsContext* dest,
+ LayerMode layerMode,
+ TransformMode transformMode,
+ const IntRect& region);
+
+ // Combines the source and destination bitmaps using the given mode.
+ void composite();
+
+ // Returns the context for drawing into, which may be the destination
+ // context, or a temporary one.
+ GraphicsContext* context() const { return m_drawContext; }
+
+ PlatformGraphicsContext* platformContext() const { return m_drawContext->platformContext(); }
+
+ // When the mode is TextComposite, this sets the color that the text will
+ // get. See the enum above for more.
+ void setTextCompositeColor(Color color);
+
+ // Returns the input bounds translated into the destination space. This is
+ // not necessary for KeepTransform since the rectangle will be unchanged.
+ const IntRect& drawRect() { return m_drawRect; }
+
+private:
+ friend TransparencyWin_NoLayer_Test;
+ friend TransparencyWin_WhiteLayer_Test;
+ friend TransparencyWin_TextComposite_Test;
+ friend TransparencyWin_OpaqueCompositeLayer_Test;
+
+ class OwnedBuffers;
+
+ void computeLayerSize();
+
+ // Sets up a new layer, if any. setupLayer() will call the appopriate layer-
+ // specific helper. Must be called after computeLayerSize();
+ void setupLayer();
+ void setupLayerForNoLayer();
+ void setupLayerForOpaqueCompositeLayer();
+ void setupLayerForTextComposite();
+ void setupLayerForWhiteLayer();
+
+ // Sets up the transformation on the newly created layer. setupTransform()
+ // will call the appropriate transform-specific helper. Must be called after
+ // setupLayer().
+ void setupTransform(const IntRect& region);
+ void setupTransformForKeepTransform(const IntRect& region);
+ void setupTransformForUntransform();
+ void setupTransformForScaleTransform();
+
+ void initializeNewContext();
+
+ void compositeOpaqueComposite();
+ void compositeTextComposite();
+
+ // Fixes the alpha channel to make the region inside m_transformedRect
+ // opaque.
+ void makeLayerOpaque();
+
+ // The context our drawing will eventually end up in.
+ GraphicsContext* m_destContext;
+
+ // The original transform from the destination context.
+ TransformationMatrix m_orgTransform;
+
+ LayerMode m_layerMode;
+ TransformMode m_transformMode;
+
+ // The rectangle we're drawing in the destination's coordinate space
+ IntRect m_sourceRect;
+
+ // The source rectangle transformed into pixels in the final image. For
+ // Untransform this has no meaning, since the destination might not be a
+ // rectangle.
+ IntRect m_transformedSourceRect;
+
+ // The size of the layer we created. If there's no layer, this is the size
+ // of the region we're using in the source.
+ IntSize m_layerSize;
+
+ // The rectangle we're drawing to in the draw context's coordinate space.
+ // This will be the same as the source rectangle except for ScaleTransform
+ // where we create a new virtual coordinate space for the layer.
+ IntRect m_drawRect;
+
+ // Points to the graphics context to draw text to, which will either be
+ // the original context or the copy, depending on our mode.
+ GraphicsContext* m_drawContext;
+
+ // This flag is set when we call save() on the draw context during
+ // initialization. It allows us to avoid doing an extra save()/restore()
+ // when one is unnecessary.
+ bool m_savedOnDrawContext;
+
+ // Used only when m_mode = TextComposite, this is the color that the text
+ // will end up being once we figure out the transparency.
+ Color m_textCompositeColor;
+
+ // Layer we're drawing to.
+ ImageBuffer* m_layerBuffer;
+
+ // When the layer type is OpaqueCompositeLayer, this will contain a copy
+ // of the original contents of the m_layerBuffer before Windows drew on it.
+ // It allows us to re-create what Windows did to the layer. It is an
+ // SkBitmap instead of an ImageBuffer because an SkBitmap is lighter-weight
+ // (ImageBuffers are also GDI surfaces, which we don't need here).
+ SkBitmap* m_referenceBitmap;
+
+ // If the given size of bitmap can be cached, they will be stored here. Both
+ // the bitmap and the reference are guaranteed to be allocated if this
+ // member is non-null.
+ static OwnedBuffers* m_cachedBuffers;
+
+ // If a buffer was too big to be cached, it will be created temporarily, and
+ // this member tracks its scope to make sure it gets deleted. Always use
+ // m_layerBuffer, which will either point to this object, or the statically
+ // cached one. Don't access directly.
+ OwnPtr<OwnedBuffers> m_ownedBuffers;
+};
+
+} // namespace WebCore
+
+#endif // TransaprencyWin_h
diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
index caeb959..39b0847 100644
--- a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
+++ b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
@@ -34,6 +34,9 @@
#include <windows.h>
#include "FontUtilsChromiumWin.h"
+#include "PlatformContextSkia.h"
+#include "SkiaFontWin.h"
+#include "SkPoint.h"
#include <wtf/Assertions.h>
namespace WebCore {
@@ -58,7 +61,7 @@ static bool containsMissingGlyphs(WORD *glyphs,
SCRIPT_FONTPROPERTIES* properties)
{
for (int i = 0; i < length; ++i) {
- if (glyphs[i] == properties->wgDefault
+ if (glyphs[i] == properties->wgDefault
|| (glyphs[i] == properties->wgInvalid
&& glyphs[i] != properties->wgBlank))
return true;
@@ -112,6 +115,8 @@ UniscribeHelper::UniscribeHelper(const UChar* input,
, m_spaceWidth(0)
, m_wordSpacing(0)
, m_ascent(0)
+ , m_disableFontFallback(false)
+
{
m_logfont.lfFaceName[0] = 0;
}
@@ -285,11 +290,13 @@ int UniscribeHelper::xToCharacter(int x) const
return 0;
}
-void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to)
+void UniscribeHelper::draw(GraphicsContext* graphicsContext,
+ HDC dc, int x, int y, int from, int to)
{
HGDIOBJ oldFont = 0;
int curX = x;
bool firstRun = true;
+ bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);
for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
int itemIndex = m_screenOrder[screenIndex];
@@ -360,7 +367,7 @@ void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to)
// Actually draw the glyphs we found.
int glyphCount = afterGlyph - fromGlyph;
if (fromGlyph >= 0 && glyphCount > 0) {
- // Account for the preceeding space we need to add to this run. We
+ // Account for the preceding space we need to add to this run. We
// don't need to count for the following space because that will be
// counted in advanceForItem below when we move to the next run.
innerOffset += shaping.m_prePadding;
@@ -377,30 +384,44 @@ void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to)
// Fonts with different ascents can be used to render different
// runs. 'Across-runs' y-coordinate correction needs to be
// adjusted for each font.
- HRESULT hr = S_FALSE;
+ bool textOutOk = false;
for (int executions = 0; executions < 2; ++executions) {
- hr = ScriptTextOut(dc, shaping.m_scriptCache,
- curX + innerOffset,
- y - shaping.m_ascentOffset,
- 0, 0, &item.a, 0, 0,
- &shaping.m_glyphs[fromGlyph],
- glyphCount,
- &shaping.m_advance[fromGlyph],
- justify,
- &shaping.m_offsets[fromGlyph]);
- if (S_OK != hr && 0 == executions) {
- // If this ScriptTextOut is called from the renderer it
- // might fail because the sandbox is preventing it from
- // opening the font files. If we are running in the
- // renderer, TryToPreloadFont is overridden to ask the
- // browser to preload the font for us so we can access it.
+ if (useWindowsDrawing) {
+ HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache,
+ curX + innerOffset,
+ y - shaping.m_ascentOffset,
+ 0, 0, &item.a, 0, 0,
+ &shaping.m_glyphs[fromGlyph],
+ glyphCount,
+ &shaping.m_advance[fromGlyph],
+ justify,
+ &shaping.m_offsets[fromGlyph]);
+ ASSERT(S_OK == hr);
+ textOutOk = (hr == S_OK);
+ } else {
+ SkPoint origin;
+ origin.fX = curX + + innerOffset;
+ origin.fY = y + m_ascent - shaping.m_ascentOffset;
+ textOutOk = paintSkiaText(graphicsContext,
+ shaping.m_hfont,
+ glyphCount,
+ &shaping.m_glyphs[fromGlyph],
+ &shaping.m_advance[fromGlyph],
+ &shaping.m_offsets[fromGlyph],
+ &origin);
+ }
+
+ if (!textOutOk && 0 == executions) {
+ // If TextOut is called from the renderer it might fail
+ // because the sandbox is preventing it from opening the
+ // font files. If we are running in the renderer,
+ // TryToPreloadFont is overridden to ask the browser to
+ // preload the font for us so we can access it.
tryToPreloadFont(shaping.m_hfont);
continue;
}
break;
}
-
- ASSERT(S_OK == hr);
}
curX += advanceForItem(itemIndex);
@@ -527,7 +548,10 @@ bool UniscribeHelper::shape(const UChar* input,
HDC tempDC = 0;
HGDIOBJ oldFont = 0;
HRESULT hr;
- bool lastFallbackTried = false;
+ // When used to fill up glyph pages for simple scripts in non-BMP,
+ // we don't want any font fallback in this class. The simple script
+ // font path can take care of font fallback.
+ bool lastFallbackTried = m_disableFontFallback;
bool result;
int generatedGlyphs = 0;
@@ -557,7 +581,7 @@ bool UniscribeHelper::shape(const UChar* input,
// PurifyMarkAsInitialized(
// &shaping.m_glyphs[0],
// sizeof(shaping.m_glyphs[0] * generatedGlyphs);
-
+
ZeroMemory(&shaping.m_glyphs[0],
sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());
#endif
@@ -587,7 +611,8 @@ bool UniscribeHelper::shape(const UChar* input,
tempDC = 0;
}
- if (nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
+ if (!m_disableFontFallback &&
+ nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
// The primary font does not support this run. Try next font.
// In case of web page rendering, they come from fonts specified in
// CSS stylesheets.
@@ -702,6 +727,13 @@ void UniscribeHelper::fillShapes()
if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping))
continue;
+ // At the moment, the only time m_disableFontFallback is set is
+ // when we look up glyph indices for non-BMP code ranges. So,
+ // we can skip the glyph placement. When that becomes not the case
+ // any more, we have to add a new flag to control glyph placement.
+ if (m_disableFontFallback)
+ continue;
+
// Compute placements. Note that offsets is documented incorrectly
// and is actually an array.
@@ -779,9 +811,6 @@ void UniscribeHelper::adjustSpaceAdvances()
int glyphIndex = shaping.m_logs[i];
int currentAdvance = shaping.m_advance[glyphIndex];
- // Don't give zero-width spaces a width.
- if (!currentAdvance)
- continue;
// currentAdvance does not include additional letter-spacing, but
// space_width does. Here we find out how off we are from the
diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.h b/WebCore/platform/graphics/chromium/UniscribeHelper.h
index d291105..ffd57db 100644
--- a/WebCore/platform/graphics/chromium/UniscribeHelper.h
+++ b/WebCore/platform/graphics/chromium/UniscribeHelper.h
@@ -44,6 +44,8 @@ class UniscribeTest_TooBig_Test; // A gunit test for UniscribeHelper.
namespace WebCore {
+class GraphicsContext;
+
#define UNISCRIBE_HELPER_STACK_RUNS 8
#define UNISCRIBE_HELPER_STACK_CHARS 32
@@ -145,6 +147,16 @@ public:
m_ascent = ascent;
}
+ // When set to true, this class is used only to look up glyph
+ // indices for a range of Unicode characters without glyph placement.
+ // By default, it's false. This should be set to true when this
+ // class is used for glyph index look-up for non-BMP characters
+ // in GlyphPageNodeChromiumWin.cpp.
+ void setDisableFontFallback(bool disableFontFallback)
+ {
+ m_disableFontFallback = true;
+ }
+
// You must call this after setting any options but before doing any
// other calls like asking for widths or drawing.
void init()
@@ -177,7 +189,8 @@ public:
// be pre-set.
//
// The y position is the upper left corner, NOT the baseline.
- void draw(HDC, int x, int y, int from, int to);
+ void draw(GraphicsContext* graphicsContext, HDC dc, int x, int y, int from,
+ int to);
// Returns the first glyph assigned to the character at the given offset.
// This function is used to retrieve glyph information when Uniscribe is
@@ -378,6 +391,7 @@ private:
int m_letterSpacing;
int m_spaceWidth;
int m_wordSpacing;
+ bool m_disableFontFallback;
// Uniscribe breaks the text into Runs. These are one length of text that is
// in one script and one direction. This array is in reading order.
diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h
index efa5dd5..20c52e5 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformData.h
+++ b/WebCore/platform/graphics/gtk/FontPlatformData.h
@@ -74,6 +74,7 @@ public:
FontPlatformData(float size, bool bold, bool italic);
FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic);
+ FontPlatformData(const FontPlatformData&);
~FontPlatformData();
@@ -95,6 +96,7 @@ public:
}
bool operator==(const FontPlatformData&) const;
+ FontPlatformData& operator=(const FontPlatformData&);
bool isHashTableDeletedValue() const {
#if defined(USE_FREETYPE)
return m_pattern == hashTableDeletedFontValue();
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
index 17d789b..68685e9 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
@@ -3,6 +3,7 @@
* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
* Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
* Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Igalia S.L.
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -161,6 +162,45 @@ FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool b
m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
}
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+
+ if (other.m_scaledFont)
+ cairo_scaled_font_reference(other.m_scaledFont);
+ if (m_scaledFont)
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = other.m_scaledFont;
+
+ if (other.m_pattern)
+ FcPatternReference(other.m_pattern);
+ if (m_pattern)
+ FcPatternDestroy(m_pattern);
+ m_pattern = other.m_pattern;
+
+ if (m_fallbacks) {
+ FcFontSetDestroy(m_fallbacks);
+ // This will be re-created on demand.
+ m_fallbacks = 0;
+ }
+
+ return *this;
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& other)
+ : m_pattern(0)
+ , m_fallbacks(0)
+ , m_scaledFont(0)
+{
+ *this = other;
+}
+
bool FontPlatformData::init()
{
static bool initialized = false;
@@ -176,6 +216,20 @@ bool FontPlatformData::init()
FontPlatformData::~FontPlatformData()
{
+ if (m_pattern && ((FcPattern*)-1 != m_pattern)) {
+ FcPatternDestroy(m_pattern);
+ m_pattern = 0;
+ }
+
+ if (m_fallbacks) {
+ FcFontSetDestroy(m_fallbacks);
+ m_fallbacks = 0;
+ }
+
+ if (m_scaledFont) {
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = 0;
+ }
}
bool FontPlatformData::isFixedPitch()
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
index be3fd43..88bf427 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
@@ -4,6 +4,7 @@
* Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
* Copyright (C) 2007 Holger Hans Peter Freyther
* Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * Copyright (C) 2009 Igalia S.L.
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
@@ -46,8 +47,8 @@
namespace WebCore {
- PangoFontMap* FontPlatformData::m_fontMap = 0;
- GHashTable* FontPlatformData::m_hashTable = 0;
+PangoFontMap* FontPlatformData::m_fontMap = 0;
+GHashTable* FontPlatformData::m_hashTable = 0;
FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
: m_context(0)
@@ -193,7 +194,20 @@ bool FontPlatformData::init()
FontPlatformData::~FontPlatformData()
{
- // Destroy takes place in FontData::platformDestroy().
+ if (m_font && m_font != reinterpret_cast<PangoFont*>(-1)) {
+ g_object_unref(m_font);
+ m_font = 0;
+ }
+
+ if (m_context) {
+ g_object_unref(m_context);
+ m_context = 0;
+ }
+
+ if (m_scaledFont) {
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = 0;
+ }
}
bool FontPlatformData::isFixedPitch()
@@ -211,6 +225,45 @@ void FontPlatformData::setFont(cairo_t* cr) const
cairo_set_scaled_font(cr, m_scaledFont);
}
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+
+ if (other.m_scaledFont)
+ cairo_scaled_font_reference(other.m_scaledFont);
+ if (m_scaledFont)
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = other.m_scaledFont;
+
+ if (other.m_font)
+ g_object_ref(other.m_font);
+ if (m_font)
+ g_object_unref(m_font);
+ m_font = other.m_font;
+
+ if (other.m_context)
+ g_object_ref(other.m_context);
+ if (m_context)
+ g_object_unref(m_context);
+ m_context = other.m_context;
+
+ return *this;
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& other)
+ : m_context(0)
+ , m_font(0)
+ , m_scaledFont(0)
+{
+ *this = other;
+}
+
bool FontPlatformData::operator==(const FontPlatformData& other) const
{
if (m_font == other.m_font)
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index 1f0cac6..8dd1333 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2007 Collabora Ltd. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
*
@@ -101,6 +101,22 @@ gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, g
return true;
}
+static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, MediaPlayerPrivate* playerPrivate)
+{
+ playerPrivate->repaint();
+}
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_playBin(0)
@@ -111,10 +127,10 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_isEndReached(false)
, m_volume(0.5f)
, m_networkState(MediaPlayer::Empty)
- , m_readyState(MediaPlayer::DataUnavailable)
+ , m_readyState(MediaPlayer::HaveNothing)
, m_startedPlaying(false)
, m_isStreaming(false)
- , m_rect(IntRect())
+ , m_size(IntSize())
, m_visible(true)
{
@@ -140,15 +156,15 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
}
}
-void MediaPlayerPrivate::load(String url)
+void MediaPlayerPrivate::load(const String& url)
{
LOG_VERBOSE(Media, "Load %s", url.utf8().data());
if (m_networkState != MediaPlayer::Loading) {
m_networkState = MediaPlayer::Loading;
m_player->networkStateChanged();
}
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
@@ -175,24 +191,28 @@ void MediaPlayerPrivate::pause()
m_startedPlaying = false;
}
-float MediaPlayerPrivate::duration()
+float MediaPlayerPrivate::duration() const
{
if (!m_playBin)
return 0.0;
- GstFormat fmt = GST_FORMAT_TIME;
- gint64 len = 0;
-
- if (gst_element_query_duration(m_playBin, &fmt, &len))
- LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(len));
- else
- LOG_VERBOSE(Media, "Duration query failed ");
+ GstFormat timeFormat = GST_FORMAT_TIME;
+ gint64 timeLength = 0;
- if ((GstClockTime)len == GST_CLOCK_TIME_NONE) {
+ // FIXME: We try to get the duration, but we do not trust the
+ // return value of the query function only; the problem we are
+ // trying to work-around here is that pipelines in stream mode may
+ // not be able to figure out the duration, but still return true!
+ // See https://bugs.webkit.org/show_bug.cgi?id=24639.
+ if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeLength <= 0) {
+ LOG_VERBOSE(Media, "Time duration query failed.");
m_isStreaming = true;
return numeric_limits<float>::infinity();
}
- return (float) (len / 1000000000.0);
+
+ LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
+
+ return (float) (timeLength / 1000000000.0);
// FIXME: handle 3.14.9.5 properly
}
@@ -288,7 +308,7 @@ bool MediaPlayerPrivate::seeking() const
}
// Returns the size of the video
-IntSize MediaPlayerPrivate::naturalSize()
+IntSize MediaPlayerPrivate::naturalSize() const
{
if (!hasVideo())
return IntSize();
@@ -302,7 +322,7 @@ IntSize MediaPlayerPrivate::naturalSize()
return IntSize(x, y);
}
-bool MediaPlayerPrivate::hasVideo()
+bool MediaPlayerPrivate::hasVideo() const
{
gint currentVideo = -1;
if (m_playBin)
@@ -355,17 +375,17 @@ int MediaPlayerPrivate::dataRate() const
return 1;
}
-MediaPlayer::NetworkState MediaPlayerPrivate::networkState()
+MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
{
return m_networkState;
}
-MediaPlayer::ReadyState MediaPlayerPrivate::readyState()
+MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
{
return m_readyState;
}
-float MediaPlayerPrivate::maxTimeBuffered()
+float MediaPlayerPrivate::maxTimeBuffered() const
{
notImplemented();
LOG_VERBOSE(Media, "maxTimeBuffered");
@@ -373,7 +393,7 @@ float MediaPlayerPrivate::maxTimeBuffered()
return m_isStreaming ? 0 : maxTimeLoaded();
}
-float MediaPlayerPrivate::maxTimeSeekable()
+float MediaPlayerPrivate::maxTimeSeekable() const
{
// TODO
LOG_VERBOSE(Media, "maxTimeSeekable");
@@ -383,7 +403,7 @@ float MediaPlayerPrivate::maxTimeSeekable()
return maxTimeLoaded();
}
-float MediaPlayerPrivate::maxTimeLoaded()
+float MediaPlayerPrivate::maxTimeLoaded() const
{
// TODO
LOG_VERBOSE(Media, "maxTimeLoaded");
@@ -391,7 +411,7 @@ float MediaPlayerPrivate::maxTimeLoaded()
return duration();
}
-unsigned MediaPlayerPrivate::bytesLoaded()
+unsigned MediaPlayerPrivate::bytesLoaded() const
{
notImplemented();
LOG_VERBOSE(Media, "bytesLoaded");
@@ -404,14 +424,14 @@ unsigned MediaPlayerPrivate::bytesLoaded()
return 1;//totalBytes() * maxTime / dur;
}
-bool MediaPlayerPrivate::totalBytesKnown()
+bool MediaPlayerPrivate::totalBytesKnown() const
{
notImplemented();
LOG_VERBOSE(Media, "totalBytesKnown");
return totalBytes() > 0;
}
-unsigned MediaPlayerPrivate::totalBytes()
+unsigned MediaPlayerPrivate::totalBytes() const
{
notImplemented();
LOG_VERBOSE(Media, "totalBytes");
@@ -455,12 +475,11 @@ void MediaPlayerPrivate::updateStates()
gst_element_state_get_name(pending));
if (state == GST_STATE_READY) {
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (state == GST_STATE_PAUSED) {
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveEnoughData;
}
- if (m_networkState < MediaPlayer::Loaded)
- m_networkState = MediaPlayer::Loaded;
+ m_networkState = MediaPlayer::Loaded;
g_object_get(m_playBin, "source", &m_source, NULL);
if (!m_source)
@@ -478,12 +497,11 @@ void MediaPlayerPrivate::updateStates()
gst_element_state_get_name(state),
gst_element_state_get_name(pending));
if (state == GST_STATE_READY) {
- m_readyState = MediaPlayer::CanPlay;
+ m_readyState = MediaPlayer::HaveFutureData;
} else if (state == GST_STATE_PAUSED) {
- m_readyState = MediaPlayer::CanPlay;
+ m_readyState = MediaPlayer::HaveCurrentData;
}
- if (m_networkState < MediaPlayer::LoadedMetaData)
- m_networkState = MediaPlayer::LoadedMetaData;
+ m_networkState = MediaPlayer::Loading;
break;
default:
LOG_VERBOSE(Media, "Else : %d", ret);
@@ -491,7 +509,7 @@ void MediaPlayerPrivate::updateStates()
}
if (seeking())
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveNothing;
if (m_networkState != oldNetworkState) {
LOG_VERBOSE(Media, "Network State Changed from %u to %u",
@@ -540,19 +558,19 @@ void MediaPlayerPrivate::didEnd()
void MediaPlayerPrivate::loadingFailed()
{
- if (m_networkState != MediaPlayer::LoadFailed) {
- m_networkState = MediaPlayer::LoadFailed;
+ if (m_networkState != MediaPlayer::NetworkError) {
+ m_networkState = MediaPlayer::NetworkError;
m_player->networkStateChanged();
}
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
}
-void MediaPlayerPrivate::setRect(const IntRect& rect)
+void MediaPlayerPrivate::setSize(const IntSize& size)
{
- m_rect = rect;
+ m_size = size;
}
void MediaPlayerPrivate::setVisible(bool visible)
@@ -573,7 +591,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
if (!m_visible)
return;
- //TODO: m_rect vs rect?
+ //TODO: m_size vs rect?
cairo_t* cr = context->platformContext();
cairo_save(cr);
@@ -587,11 +605,18 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
{
- // FIXME: do the real thing
+ // FIXME: query the engine to see what types are supported
notImplemented();
types.add(String("video/x-theora+ogg"));
}
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // FIXME: query the engine to see what types are supported
+ notImplemented();
+ return type == "video/x-theora+ogg" ? (!codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
void MediaPlayerPrivate::createGSTPlayBin(String url)
{
ASSERT(!m_playBin);
@@ -613,6 +638,8 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
g_object_set(m_playBin, "audio-sink", audioSink, NULL);
g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
+ g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
+
setVolume(m_volume);
}
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
index 3f08bc0..628f0ac 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2007 Collabora Ltd. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
*
@@ -24,7 +24,7 @@
#if ENABLE(VIDEO)
-#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
#include "Timer.h"
#include <gtk/gtk.h>
@@ -44,20 +44,21 @@ namespace WebCore {
gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
- class MediaPlayerPrivate : Noncopyable
+ class MediaPlayerPrivate : public MediaPlayerPrivateInterface
{
friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data);
friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
public:
- MediaPlayerPrivate(MediaPlayer*);
+
+ static void registerMediaEngine(MediaEngineRegistrar);
~MediaPlayerPrivate();
- IntSize naturalSize();
- bool hasVideo();
+ IntSize naturalSize() const;
+ bool hasVideo() const;
- void load(String url);
+ void load(const String &url);
void cancelLoad();
void play();
@@ -66,7 +67,7 @@ namespace WebCore {
bool paused() const;
bool seeking() const;
- float duration();
+ float duration() const;
float currentTime() const;
void seek(float);
void setEndTime(float);
@@ -77,17 +78,17 @@ namespace WebCore {
int dataRate() const;
- MediaPlayer::NetworkState networkState();
- MediaPlayer::ReadyState readyState();
+ MediaPlayer::NetworkState networkState() const;
+ MediaPlayer::ReadyState readyState() const;
- float maxTimeBuffered();
- float maxTimeSeekable();
- unsigned bytesLoaded();
- bool totalBytesKnown();
- unsigned totalBytes();
+ float maxTimeBuffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ bool totalBytesKnown() const;
+ unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect&);
+ void setSize(const IntSize&);
void loadStateChanged();
void rateChanged();
@@ -99,15 +100,20 @@ namespace WebCore {
void repaint();
void paint(GraphicsContext*, const IntRect&);
- static void getSupportedTypes(HashSet<String>&);
- static bool isAvailable() { return true; }
private:
+ MediaPlayerPrivate(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable() { return true; }
+
void updateStates();
void cancelSeek();
void endPointTimerFired(Timer<MediaPlayerPrivate>*);
- float maxTimeLoaded();
+ float maxTimeLoaded() const;
void startEndPointTimerIfNeeded();
void createGSTPlayBin(String url);
@@ -124,8 +130,8 @@ namespace WebCore {
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
bool m_startedPlaying;
- bool m_isStreaming;
- IntRect m_rect;
+ mutable bool m_isStreaming;
+ IntSize m_size;
bool m_visible;
cairo_surface_t* m_surface;
};
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
index d076cb6..4203a3c 100644
--- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
@@ -53,6 +53,13 @@ void SimpleFontData::platformInit()
m_ascent = static_cast<int>(font_extents.ascent);
m_descent = static_cast<int>(font_extents.descent);
m_lineSpacing = static_cast<int>(font_extents.height);
+ // There seems to be some rounding error in cairo (or in how we
+ // use cairo) with some fonts, like DejaVu Sans Mono, which makes
+ // cairo report a height smaller than ascent + descent, which is
+ // wrong and confuses WebCore's layout system. Workaround this
+ // while we figure out what's going on.
+ if (m_lineSpacing < m_ascent + m_descent)
+ m_lineSpacing = m_ascent + m_descent;
cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents);
m_xHeight = text_extents.height;
cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents);
@@ -64,31 +71,13 @@ void SimpleFontData::platformDestroy()
{
delete m_smallCapsFontData;
m_smallCapsFontData = 0;
-
- if (isCustomFont())
- return;
-
- if (m_font.m_pattern && ((FcPattern*)-1 != m_font.m_pattern)) {
- FcPatternDestroy(m_font.m_pattern);
- m_font.m_pattern = 0;
- }
-
- if (m_font.m_fallbacks) {
- FcFontSetDestroy(m_font.m_fallbacks);
- m_font.m_fallbacks = 0;
- }
-
- if (m_font.m_scaledFont) {
- cairo_scaled_font_destroy(m_font.m_scaledFont);
- m_font.m_scaledFont = 0;
- }
}
SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
{
if (!m_smallCapsFontData) {
FontDescription desc = FontDescription(fontDescription);
- desc.setSpecifiedSize(0.70f*fontDescription.computedSize());
+ desc.setComputedSize(0.70f*fontDescription.computedSize());
const FontPlatformData* pdata = new FontPlatformData(desc, desc.family().family());
m_smallCapsFontData = new SimpleFontData(*pdata);
}
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
index db8dd3b..e345a8c 100644
--- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
@@ -52,6 +52,13 @@ void SimpleFontData::platformInit()
m_ascent = static_cast<int>(font_extents.ascent);
m_descent = static_cast<int>(font_extents.descent);
m_lineSpacing = static_cast<int>(font_extents.height);
+ // There seems to be some rounding error in cairo (or in how we
+ // use cairo) with some fonts, like DejaVu Sans Mono, which makes
+ // cairo report a height smaller than ascent + descent, which is
+ // wrong and confuses WebCore's layout system. Workaround this
+ // while we figure out what's going on.
+ if (m_lineSpacing < m_ascent + m_descent)
+ m_lineSpacing = m_ascent + m_descent;
cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents);
m_xHeight = text_extents.height;
cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents);
@@ -61,24 +68,6 @@ void SimpleFontData::platformInit()
void SimpleFontData::platformDestroy()
{
- if (!isCustomFont()) {
-
- if (m_font.m_font && m_font.m_font != reinterpret_cast<PangoFont*>(-1)) {
- g_object_unref(m_font.m_font);
- m_font.m_font = 0;
- }
-
- if (m_font.m_context) {
- g_object_unref (m_font.m_context);
- m_font.m_context = 0;
- }
-
- if (m_font.m_scaledFont) {
- cairo_scaled_font_destroy(m_font.m_scaledFont);
- m_font.m_scaledFont = 0;
- }
- }
-
delete m_smallCapsFontData;
m_smallCapsFontData = 0;
}
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
index 04df7ac..436841c 100644
--- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
@@ -46,10 +46,17 @@ static GstElementDetails webkit_video_sink_details =
(gchar*) "Alp Toker <alp@atoker.com>");
enum {
+ REPAINT_REQUESTED,
+ LAST_SIGNAL
+};
+
+enum {
PROP_0,
PROP_SURFACE
};
+static guint webkit_video_sink_signals[LAST_SIGNAL] = { 0, };
+
struct _WebKitVideoSinkPrivate {
cairo_surface_t* surface;
GAsyncQueue* async_queue;
@@ -95,11 +102,10 @@ webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass)
static gboolean
webkit_video_sink_idle_func(gpointer data)
{
- WebKitVideoSinkPrivate* priv;
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(data);
+ WebKitVideoSinkPrivate* priv = sink->priv;
GstBuffer* buffer;
- priv = (WebKitVideoSinkPrivate*)data;
-
if (!priv->async_queue)
return FALSE;
@@ -121,6 +127,8 @@ webkit_video_sink_idle_func(gpointer data)
gst_buffer_unref(buffer);
+ g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0);
+
return FALSE;
}
@@ -131,7 +139,7 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
WebKitVideoSinkPrivate* priv = sink->priv;
g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer));
- g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, priv, NULL);
+ g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, NULL);
return GST_FLOW_OK;
}
@@ -279,6 +287,15 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
gstbase_sink_class->stop = webkit_video_sink_stop;
gstbase_sink_class->set_caps = webkit_video_sink_set_caps;
+ webkit_video_sink_signals[REPAINT_REQUESTED] = g_signal_new("repaint-requested",
+ G_TYPE_FROM_CLASS(klass),
+ (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
g_object_class_install_property(
gobject_class, PROP_SURFACE,
g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*",
diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm
index 9b0f770..1c4350c 100644
--- a/WebCore/platform/graphics/mac/ColorMac.mm
+++ b/WebCore/platform/graphics/mac/ColorMac.mm
@@ -27,6 +27,7 @@
#import "Color.h"
#import "ColorMac.h"
+#import <AppKit/AppKit.h>
#import <wtf/Assertions.h>
#import <wtf/StdLibExtras.h>
#import <wtf/RetainPtr.h>
@@ -110,7 +111,7 @@ static CGColorRef CGColorFromNSColor(NSColor* color)
return cgColor;
}
-CGColorRef cgColor(const Color& c)
+CGColorRef createCGColor(const Color& c)
{
// We could directly create a CGColor here, but that would
// skip any RGB caching the nsColor method does. A direct
diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm
index 26d84cc..2202459 100644
--- a/WebCore/platform/graphics/mac/FontCacheMac.mm
+++ b/WebCore/platform/graphics/mac/FontCacheMac.mm
@@ -35,7 +35,8 @@
#import "FontPlatformData.h"
#import "WebCoreSystemInterface.h"
#import "WebFontCache.h"
-#include <wtf/StdLibExtras.h>
+#import <AppKit/AppKit.h>
+#import <wtf/StdLibExtras.h>
#ifdef BUILDING_ON_TIGER
typedef int NSInteger;
@@ -191,13 +192,11 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
actualTraits = [fontManager traitsOfFont:nsFont];
NSInteger actualWeight = [fontManager weightOfFont:nsFont];
- FontPlatformData* result = new FontPlatformData;
+ NSFont *platformFont = fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont];
+ bool syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight);
+ bool syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait);
- // Use the correct font for print vs. screen.
- result->setFont(fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont]);
- result->m_syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight);
- result->m_syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait);
- return result;
+ return new FontPlatformData(platformFont, syntheticBold, syntheticOblique);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
index 9aa4997..e40bbab 100644
--- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
@@ -29,7 +29,8 @@ namespace WebCore {
FontCustomPlatformData::~FontCustomPlatformData()
{
- ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault);
+ if (m_atsContainer)
+ ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault);
CGFontRelease(m_cgFont);
}
@@ -42,8 +43,18 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
{
ASSERT_ARG(buffer, buffer);
- // Use ATS to activate the font.
ATSFontContainerRef containerRef = 0;
+ ATSFontRef fontRef = 0;
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ RetainPtr<CFDataRef> bufferData(AdoptCF, buffer->createCFData());
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(bufferData.get()));
+
+ CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider.get());
+ if (!cgFontRef)
+ return 0;
+#else
+ // Use ATS to activate the font.
// The value "3" means that the font is private and can't be seen by anyone else.
ATSFontActivateFromMemory((void*)buffer->data(), buffer->size(), 3, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &containerRef);
@@ -58,7 +69,6 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
return 0;
}
- ATSFontRef fontRef = 0;
ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, &fontRef, NULL);
if (!fontRef) {
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
@@ -77,6 +87,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
return 0;
}
+#endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
return new FontCustomPlatformData(containerRef, fontRef, cgFontRef);
}
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/WebCore/platform/graphics/mac/FontCustomPlatformData.h
index 1e73ae0..2c1222f 100644
--- a/WebCore/platform/graphics/mac/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.h
@@ -22,6 +22,7 @@
#define FontCustomPlatformData_h
#include "FontRenderingMode.h"
+#include <CoreFoundation/CFBase.h>
#include <wtf/Noncopyable.h>
typedef struct CGFont* CGFontRef;
diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm
index bef18d0..dc86c4b 100644
--- a/WebCore/platform/graphics/mac/FontMac.mm
+++ b/WebCore/platform/graphics/mac/FontMac.mm
@@ -29,6 +29,7 @@
#import "SimpleFontData.h"
#import "WebCoreSystemInterface.h"
#import "WebCoreTextRenderer.h"
+#import <AppKit/AppKit.h>
#define SYNTHETIC_OBLIQUE_ANGLE 14
diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm
index 52493e7..3794149 100644
--- a/WebCore/platform/graphics/mac/FontMacATSUI.mm
+++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm
@@ -30,6 +30,7 @@
#import "Logging.h"
#import "ShapeArabic.h"
#import "SimpleFontData.h"
+#import <AppKit/NSGraphicsContext.h>
#import <wtf/OwnArrayPtr.h>
#define SYNTHETIC_OBLIQUE_ANGLE 14
diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h
index 40a2dbd..e911867 100644
--- a/WebCore/platform/graphics/mac/FontPlatformData.h
+++ b/WebCore/platform/graphics/mac/FontPlatformData.h
@@ -1,8 +1,8 @@
/*
* This file is part of the internal font implementation.
- * It should not be included by source files outside it.
+ * It should not be included by source files outside of it.
*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -33,7 +33,6 @@ class NSFont;
#endif
typedef struct CGFont* CGFontRef;
-typedef UInt32 ATSUFontID;
#ifndef BUILDING_ON_TIGER
typedef const struct __CTFont* CTFontRef;
#endif
@@ -42,6 +41,8 @@ typedef const struct __CTFont* CTFontRef;
#include <objc/objc-auto.h>
#include <wtf/RetainPtr.h>
+typedef UInt32 ATSUFontID;
+
namespace WebCore {
#ifndef BUILDING_ON_TIGER
@@ -61,10 +62,15 @@ struct FontPlatformData {
{
}
- FontPlatformData(NSFont * = 0, bool syntheticBold = false, bool syntheticOblique = false);
+ FontPlatformData(NSFont *nsFont, bool syntheticBold = false, bool syntheticOblique = false);
- FontPlatformData(CGFontRef f, ATSUFontID fontID, float s, bool b , bool o)
- : m_syntheticBold(b), m_syntheticOblique(o), m_atsuFontID(fontID), m_size(s), m_font(0), m_cgFont(f)
+ FontPlatformData(CGFontRef cgFont, ATSUFontID fontID, float size, bool syntheticBold, bool syntheticOblique)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
+ , m_atsuFontID(fontID)
+ , m_size(size)
+ , m_font(0)
+ , m_cgFont(cgFont)
{
}
diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
index 7cd9ab6..83da4a9 100644
--- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
+++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
@@ -1,7 +1,7 @@
/*
* This file is part of the internal font implementation.
*
- * Copyright (C) 2006-7 Apple Computer, Inc.
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,21 +24,24 @@
#import "FontPlatformData.h"
#import "WebCoreSystemInterface.h"
+#import <AppKit/NSFont.h>
namespace WebCore {
-FontPlatformData::FontPlatformData(NSFont *f, bool b , bool o)
-: m_syntheticBold(b), m_syntheticOblique(o), m_font(f)
+FontPlatformData::FontPlatformData(NSFont *nsFont, bool syntheticBold, bool syntheticOblique)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
+ , m_font(nsFont)
{
- if (f)
- CFRetain(f);
- m_size = f ? [f pointSize] : 0.0f;
+ if (nsFont)
+ CFRetain(nsFont);
+ m_size = nsFont ? [nsFont pointSize] : 0.0f;
#ifndef BUILDING_ON_TIGER
- m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(f), 0));
- m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(f), 0);
+ m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(nsFont), 0));
+ m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(nsFont), 0);
#else
- m_cgFont = wkGetCGFontFromNSFont(f);
- m_atsuFontID = wkGetNSFontATSUFontId(f);
+ m_cgFont = wkGetCGFontFromNSFont(nsFont);
+ m_atsuFontID = wkGetNSFontATSUFontId(nsFont);
#endif
}
diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
index ae829e2..4e11602 100644
--- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm
+++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
@@ -27,10 +27,13 @@
#import "GraphicsContext.h"
#import "../cg/GraphicsContextPlatformPrivateCG.h"
+#import <AppKit/AppKit.h>
#import <wtf/StdLibExtras.h>
#import "WebCoreSystemInterface.h"
+@class NSColor;
+
// FIXME: More of this should use CoreGraphics instead of AppKit.
// FIXME: More of this should move into GraphicsContextCG.cpp.
@@ -47,7 +50,7 @@ void GraphicsContext::drawFocusRing(const Color& color)
int radius = (focusRingWidth() - 1) / 2;
int offset = radius + focusRingOffset();
- CGColorRef colorRef = color.isValid() ? cgColor(color) : 0;
+ CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0;
CGMutablePathRef focusRingPath = CGPathCreateMutable();
const Vector<IntRect>& rects = focusRingRects();
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
new file mode 100644
index 0000000..3a692d3
--- /dev/null
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsLayerCA_h
+#define GraphicsLayerCA_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GraphicsLayer.h"
+#include <wtf/RetainPtr.h>
+
+@class WebAnimationDelegate;
+@class WebLayer;
+
+namespace WebCore {
+
+class GraphicsLayerCA : public GraphicsLayer {
+public:
+
+ GraphicsLayerCA(GraphicsLayerClient*);
+ virtual ~GraphicsLayerCA();
+
+ virtual void setName(const String&);
+
+ // for hosting this GraphicsLayer in a native layer hierarchy
+ virtual NativeLayer nativeLayer() const;
+
+ 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 setPosition(const FloatPoint&);
+ virtual void setAnchorPoint(const FloatPoint3D&);
+ virtual void setSize(const FloatSize&);
+
+ virtual void setTransform(const TransformationMatrix&);
+
+ virtual void setChildrenTransform(const TransformationMatrix&);
+
+ virtual void setPreserves3D(bool);
+ virtual void setMasksToBounds(bool);
+ virtual void setDrawsContent(bool);
+
+ virtual void setBackgroundColor(const Color&, const Animation* anim = 0, double beginTime = 0);
+ virtual void clearBackgroundColor();
+
+ virtual void setContentsOpaque(bool);
+ virtual void setBackfaceVisibility(bool);
+
+ // return true if we started an animation
+ virtual bool setOpacity(float, const Animation* anim = 0, double beginTime = 0);
+
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+
+ virtual void suspendAnimations();
+ virtual void resumeAnimations();
+
+ virtual bool animateTransform(const TransformValueList&, const IntSize&, const Animation*, double beginTime, bool isTransition);
+ virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&, const Animation*, double beginTime);
+
+ virtual void setContentsToImage(Image*);
+ virtual void setContentsToVideo(PlatformLayer*);
+ virtual void clearContents();
+
+ virtual void updateContentsRect();
+
+ virtual PlatformLayer* platformLayer() const;
+
+#ifndef NDEBUG
+ virtual void setDebugBackgroundColor(const Color&);
+ virtual void setDebugBorder(const Color&, float borderWidth);
+ virtual void setZPosition(float);
+#endif
+
+private:
+ WebLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
+ WebLayer* hostLayerForSublayers() const;
+ WebLayer* layerForSuperlayer() const;
+
+ WebLayer* animatedLayer(AnimatedPropertyID property) const
+ {
+ return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
+ }
+
+ void setBasicAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation*, double time);
+ void setKeyframeAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* keys, void* values, void* timingFunctions, bool isTransition, const Animation*, double time);
+
+ virtual void removeAnimation(int index, bool reset);
+
+ bool requiresTiledLayer(const FloatSize&) const;
+ void swapFromOrToTiledLayer(bool useTiledLayer);
+
+ void setHasContentsLayer(bool);
+ void setContentsLayer(WebLayer*);
+ void setContentsLayerFlipped(bool);
+
+ RetainPtr<WebLayer> m_layer;
+ RetainPtr<WebLayer> m_transformLayer;
+ RetainPtr<WebLayer> m_contentsLayer;
+
+ RetainPtr<WebAnimationDelegate> m_animationDelegate;
+
+ bool m_contentLayerForImageOrVideo;
+};
+
+} // namespace WebCore
+
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // GraphicsLayerCA_h
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
new file mode 100644
index 0000000..f3f2d7f
--- /dev/null
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
@@ -0,0 +1,1540 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "GraphicsLayerCA.h"
+
+#import "Animation.h"
+#import "BlockExceptions.h"
+#import "CString.h"
+#import "FloatConversion.h"
+#import "FloatRect.h"
+#import "Image.h"
+#import "PlatformString.h"
+#import <QuartzCore/QuartzCore.h>
+#import "RotateTransformOperation.h"
+#import "ScaleTransformOperation.h"
+#import "SystemTime.h"
+#import "TranslateTransformOperation.h"
+#import "WebLayer.h"
+#import "WebTiledLayer.h"
+#import <wtf/CurrentTime.h>
+#import <wtf/UnusedParam.h>
+
+using namespace std;
+
+#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
+
+namespace WebCore {
+
+// The threshold width or height above which a tiled layer will be used. This should be
+// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL
+// texture size limit on all supported hardware.
+static const int cMaxPixelDimension = 2000;
+
+// The width and height of a single tile in a tiled layer. Should be large enough to
+// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough
+// to keep the overall tile cost low.
+static const int cTiledLayerTileSize = 512;
+
+// If we send a duration of 0 to CA, then it will use the default duration
+// of 250ms. So send a very small value instead.
+static const float cAnimationAlmostZeroDuration = 1e-3f;
+
+// CACurrentMediaTime() is a time since boot. These methods convert between that and
+// WebCore time, which is system time (UTC).
+static CFTimeInterval currentTimeToMediaTime(double t)
+{
+ return CACurrentMediaTime() + t - WTF::currentTime();
+}
+
+static double mediaTimeToCurrentTime(CFTimeInterval t)
+{
+ return WTF::currentTime() + t - CACurrentMediaTime();
+}
+
+} // namespace WebCore
+
+static NSString* const WebAnimationCSSPropertyKey = @"GraphicsLayerCA_property";
+
+@interface WebAnimationDelegate : NSObject {
+ WebCore::GraphicsLayerCA* m_graphicsLayer;
+}
+
+- (void)animationDidStart:(CAAnimation *)anim;
+- (WebCore::GraphicsLayerCA*)graphicsLayer;
+- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer;
+
+@end
+
+@implementation WebAnimationDelegate
+
+- (void)animationDidStart:(CAAnimation *)animation
+{
+ if (!m_graphicsLayer)
+ return;
+
+ double startTime = WebCore::mediaTimeToCurrentTime([animation beginTime]);
+ m_graphicsLayer->client()->notifyAnimationStarted(m_graphicsLayer, startTime);
+}
+
+- (WebCore::GraphicsLayerCA*)graphicsLayer
+{
+ return m_graphicsLayer;
+}
+
+- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer
+{
+ m_graphicsLayer = graphicsLayer;
+}
+
+@end
+
+namespace WebCore {
+
+static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t)
+{
+ toT3D.m11 = narrowPrecisionToFloat(t.m11());
+ toT3D.m12 = narrowPrecisionToFloat(t.m12());
+ toT3D.m13 = narrowPrecisionToFloat(t.m13());
+ toT3D.m14 = narrowPrecisionToFloat(t.m14());
+ toT3D.m21 = narrowPrecisionToFloat(t.m21());
+ toT3D.m22 = narrowPrecisionToFloat(t.m22());
+ toT3D.m23 = narrowPrecisionToFloat(t.m23());
+ toT3D.m24 = narrowPrecisionToFloat(t.m24());
+ toT3D.m31 = narrowPrecisionToFloat(t.m31());
+ toT3D.m32 = narrowPrecisionToFloat(t.m32());
+ toT3D.m33 = narrowPrecisionToFloat(t.m33());
+ toT3D.m34 = narrowPrecisionToFloat(t.m34());
+ toT3D.m41 = narrowPrecisionToFloat(t.m41());
+ toT3D.m42 = narrowPrecisionToFloat(t.m42());
+ toT3D.m43 = narrowPrecisionToFloat(t.m43());
+ toT3D.m44 = narrowPrecisionToFloat(t.m44());
+}
+
+static NSValue* getTransformFunctionValue(const GraphicsLayer::TransformValue& transformValue, size_t index, const IntSize& size, TransformOperation::OperationType transformType)
+{
+ TransformOperation* op = (index >= transformValue.value()->operations().size()) ? 0 : transformValue.value()->operations()[index].get();
+
+ switch (transformType) {
+ case TransformOperation::ROTATE:
+ case TransformOperation::ROTATE_X:
+ case TransformOperation::ROTATE_Y:
+ return [NSNumber numberWithDouble:op ? deg2rad(static_cast<RotateTransformOperation*>(op)->angle()) : 0];
+ case TransformOperation::SCALE_X:
+ return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->x() : 0];
+ case TransformOperation::SCALE_Y:
+ return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->y() : 0];
+ case TransformOperation::SCALE_Z:
+ return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->z() : 0];
+ case TransformOperation::TRANSLATE_X:
+ return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->x(size) : 0];
+ case TransformOperation::TRANSLATE_Y:
+ return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->y(size) : 0];
+ case TransformOperation::TRANSLATE_Z:
+ return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->z(size) : 0];
+ case TransformOperation::SCALE:
+ case TransformOperation::TRANSLATE:
+ case TransformOperation::SKEW_X:
+ case TransformOperation::SKEW_Y:
+ case TransformOperation::SKEW:
+ case TransformOperation::MATRIX:
+ case TransformOperation::SCALE_3D:
+ case TransformOperation::TRANSLATE_3D:
+ case TransformOperation::ROTATE_3D:
+ case TransformOperation::MATRIX_3D:
+ case TransformOperation::PERSPECTIVE:
+ case TransformOperation::IDENTITY:
+ case TransformOperation::NONE: {
+ TransformationMatrix t;
+ if (op)
+ op->apply(t, size);
+ CATransform3D cat;
+ copyTransform(cat, t);
+ return [NSValue valueWithCATransform3D:cat];
+ }
+ }
+
+ return 0;
+}
+
+#if HAVE_MODERN_QUARTZCORE
+static NSString* getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType)
+{
+ // Use literal strings to avoid link-time dependency on those symbols.
+ switch (transformType) {
+ case TransformOperation::ROTATE_X:
+ return @"rotateX"; // kCAValueFunctionRotateX;
+ case TransformOperation::ROTATE_Y:
+ return @"rotateY"; // kCAValueFunctionRotateY;
+ case TransformOperation::ROTATE:
+ return @"rotateZ"; // kCAValueFunctionRotateZ;
+ case TransformOperation::SCALE_X:
+ return @"scaleX"; // kCAValueFunctionScaleX;
+ case TransformOperation::SCALE_Y:
+ return @"scaleY"; // kCAValueFunctionScaleY;
+ case TransformOperation::SCALE_Z:
+ return @"scaleZ"; // kCAValueFunctionScaleZ;
+ case TransformOperation::TRANSLATE_X:
+ return @"translateX"; // kCAValueFunctionTranslateX;
+ case TransformOperation::TRANSLATE_Y:
+ return @"translateY"; // kCAValueFunctionTranslateY;
+ case TransformOperation::TRANSLATE_Z:
+ return @"translateZ"; // kCAValueFunctionTranslateZ;
+ default:
+ return nil;
+ }
+}
+#endif
+
+static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& timingFunction)
+{
+ switch (timingFunction.type()) {
+ case LinearTimingFunction:
+ return [CAMediaTimingFunction functionWithName:@"linear"];
+ case CubicBezierTimingFunction:
+ return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(timingFunction.x1()) :static_cast<float>(timingFunction.y1())
+ :static_cast<float>(timingFunction.x2()) :static_cast<float>(timingFunction.y2())];
+ }
+ return 0;
+}
+
+#ifndef NDEBUG
+static void setLayerBorderColor(PlatformLayer* layer, const Color& color)
+{
+ CGColorRef borderColor = createCGColor(color);
+ [layer setBorderColor:borderColor];
+ CGColorRelease(borderColor);
+}
+
+static void clearBorderColor(PlatformLayer* layer)
+{
+ [layer setBorderColor:nil];
+}
+#endif
+
+static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color)
+{
+ CGColorRef bgColor = createCGColor(color);
+ [layer setBackgroundColor:bgColor];
+ CGColorRelease(bgColor);
+}
+
+static void clearLayerBackgroundColor(PlatformLayer* layer)
+{
+ [layer setBackgroundColor:0];
+}
+
+static CALayer* getPresentationLayer(CALayer* layer)
+{
+ CALayer* presLayer = [layer presentationLayer];
+ if (!presLayer)
+ presLayer = layer;
+
+ return presLayer;
+}
+
+static bool caValueFunctionSupported()
+{
+ static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)];
+ return sHaveValueFunction;
+}
+
+static bool forceSoftwareAnimation()
+{
+ static bool forceSoftwareAnimation = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreForceSoftwareAnimation"];
+ return forceSoftwareAnimation;
+}
+
+bool GraphicsLayer::graphicsContextsFlipped()
+{
+ return true;
+}
+
+#ifndef NDEBUG
+bool GraphicsLayer::showDebugBorders()
+{
+ static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"];
+ return showDebugBorders;
+}
+
+bool GraphicsLayer::showRepaintCounter()
+{
+ static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"];
+ return showRepaintCounter;
+}
+#endif
+
+static NSDictionary* nullActionsDictionary()
+{
+ NSNull* nullValue = [NSNull null];
+ NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys:
+ nullValue, @"anchorPoint",
+ nullValue, @"bounds",
+ nullValue, @"contents",
+ nullValue, @"contentsRect",
+ nullValue, @"opacity",
+ nullValue, @"position",
+ nullValue, @"shadowColor",
+ nullValue, @"sublayerTransform",
+ nullValue, @"sublayers",
+ nullValue, @"transform",
+#ifndef NDEBUG
+ nullValue, @"zPosition",
+#endif
+ nil];
+ return actions;
+}
+
+GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerCA(client);
+}
+
+GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
+: GraphicsLayer(client)
+, m_contentLayerForImageOrVideo(false)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ m_layer.adoptNS([[WebLayer alloc] init]);
+ [m_layer.get() setLayerOwner:this];
+
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+
+ m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]);
+ [m_animationDelegate.get() setLayer:this];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+GraphicsLayerCA::~GraphicsLayerCA()
+{
+ // Remove a inner layer if there is one.
+ clearContents();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ // Clean up the WK layer.
+ if (m_layer) {
+ WebLayer* layer = m_layer.get();
+ [layer setLayerOwner:nil];
+ [layer removeFromSuperlayer];
+ }
+
+ if (m_transformLayer)
+ [m_transformLayer.get() removeFromSuperlayer];
+
+ // animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
+ [m_animationDelegate.get() setLayer:0];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setName(const String& name)
+{
+ String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
+ GraphicsLayer::setName(longName);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setName:name];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+NativeLayer GraphicsLayerCA::nativeLayer() const
+{
+ return m_layer.get();
+}
+
+void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
+{
+ GraphicsLayer::addChild(childLayer);
+
+ GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
+{
+ GraphicsLayer::addChildAtIndex(childLayer, index);
+
+ GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() atIndex:index];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ // FIXME: share code with base class
+ ASSERT(childLayer != this);
+ childLayer->removeFromParent();
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i, childLayer);
+ found = true;
+ break;
+ }
+ }
+ childLayer->setParent(this);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
+ GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
+ if (found)
+ [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() below:siblingLayerCA->layerForSuperlayer()];
+ else {
+ m_children.append(childLayer);
+ [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ // FIXME: share code with base class
+ ASSERT(childLayer != this);
+ childLayer->removeFromParent();
+
+ unsigned i;
+ bool found = false;
+ for (i = 0; i < m_children.size(); i++) {
+ if (sibling == m_children[i]) {
+ m_children.insert(i+1, childLayer);
+ found = true;
+ break;
+ }
+ }
+ childLayer->setParent(this);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
+ GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
+ if (found) {
+ [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() above:siblingLayerCA->layerForSuperlayer()];
+ } else {
+ m_children.append(childLayer);
+ [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ // FIXME: share code with base class
+ ASSERT(!newChild->parent());
+
+ bool found = false;
+ for (unsigned i = 0; i < m_children.size(); i++) {
+ if (oldChild == m_children[i]) {
+ m_children[i] = newChild;
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ oldChild->setParent(0);
+
+ newChild->removeFromParent();
+ newChild->setParent(this);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ GraphicsLayerCA* oldChildCA = static_cast<GraphicsLayerCA*>(oldChild);
+ GraphicsLayerCA* newChildCA = static_cast<GraphicsLayerCA*>(newChild);
+ [hostLayerForSublayers() replaceSublayer:oldChildCA->layerForSuperlayer() with:newChildCA->layerForSuperlayer()];
+ END_BLOCK_OBJC_EXCEPTIONS
+ return true;
+ }
+ return false;
+}
+
+void GraphicsLayerCA::removeFromParent()
+{
+ GraphicsLayer::removeFromParent();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [layerForSuperlayer() removeFromSuperlayer];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setPosition(const FloatPoint& point)
+{
+ // Don't short-circuit here, because position and anchor point are inter-dependent.
+ GraphicsLayer::setPosition(point);
+
+ // Position is offset on the layer by the layer anchor point.
+ CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
+ m_position.y() + m_anchorPoint.y() * m_size.height());
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [primaryLayer() setPosition:posPoint];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
+{
+ // Don't short-circuit here, because position and anchor point are inter-dependent.
+ bool zChanged = (point.z() != m_anchorPoint.z());
+ GraphicsLayer::setAnchorPoint(point);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ // set the value on the layer to the new transform.
+ [primaryLayer() setAnchorPoint:FloatPoint(point.x(), point.y())];
+
+ if (zChanged) {
+#if HAVE_MODERN_QUARTZCORE
+ [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
+#endif
+ }
+
+ // Position depends on anchor point, so update it now.
+ setPosition(m_position);
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setSize(const FloatSize& size)
+{
+ GraphicsLayer::setSize(size);
+
+ CGRect rect = CGRectMake(0.0f,
+ 0.0f,
+ m_size.width(),
+ m_size.height());
+
+ CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (m_transformLayer) {
+ [m_transformLayer.get() setBounds:rect];
+
+ // the anchor of the contents layer is always at 0.5, 0.5, so the position
+ // is center-relative
+ [m_layer.get() setPosition:centerPoint];
+ }
+
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ [m_layer.get() setBounds:rect];
+
+ // Note that we don't resize m_contentsLayer. It's up the caller to do that.
+
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ // if we've changed the bounds, we need to recalculate the position
+ // of the layer, taking anchor point into account
+ setPosition(m_position);
+}
+
+void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
+{
+ GraphicsLayer::setTransform(t);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ CATransform3D transform;
+ copyTransform(transform, t);
+ [primaryLayer() setTransform:transform];
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ // Remove any old transition entries for transform.
+ removeAllAnimationsForProperty(AnimatedPropertyWebkitTransform);
+
+ // Even if we don't have a transition in the list, the layer may still have one.
+ // This happens when we are setting the final transform value after an animation or
+ // transition has ended. In removeAnimation we toss the entry from the list but don't
+ // remove it from the list. That way we aren't in danger of displaying a stale transform
+ // in the time between removing the animation and setting the new unanimated value. We
+ // can't do this in removeAnimation because we don't know the new transform value there.
+ String keyPath = propertyIdToString(AnimatedPropertyWebkitTransform);
+ CALayer* layer = animatedLayer(AnimatedPropertyWebkitTransform);
+
+ for (int i = 0; ; ++i) {
+ String animName = keyPath + "_" + String::number(i);
+ if (![layer animationForKey: animName])
+ break;
+ [layer removeAnimationForKey:animName];
+ }
+}
+
+void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
+{
+ if (t == m_childrenTransform)
+ return;
+
+ GraphicsLayer::setChildrenTransform(t);
+
+ CATransform3D transform;
+ copyTransform(transform, t);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ // Set the value on the layer to the new transform.
+ [primaryLayer() setSublayerTransform:transform];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
+{
+ String keyPath = GraphicsLayer::propertyIdToString(property);
+ for (short index = 0; ; ++index) {
+ String animName = keyPath + "_" + String::number(index);
+ CAAnimation* anim = [fromLayer animationForKey:animName];
+ if (!anim)
+ break;
+
+ [anim retain];
+ [fromLayer removeAnimationForKey:animName];
+ [toLayer addAnimation:anim forKey:animName];
+ [anim release];
+ }
+}
+
+static void moveSublayers(CALayer* fromLayer, CALayer* toLayer)
+{
+ NSArray* sublayersCopy = [[fromLayer sublayers] copy]; // Avoid mutation while enumerating, and keep the sublayers alive.
+ NSEnumerator* childrenEnumerator = [sublayersCopy objectEnumerator];
+
+ CALayer* layer;
+ while ((layer = [childrenEnumerator nextObject]) != nil) {
+ [layer removeFromSuperlayer];
+ [toLayer addSublayer:layer];
+ }
+ [sublayersCopy release];
+}
+
+void GraphicsLayerCA::setPreserves3D(bool preserves3D)
+{
+ GraphicsLayer::setPreserves3D(preserves3D);
+
+ CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ Class transformLayerClass = NSClassFromString(@"CATransformLayer");
+ if (preserves3D && !m_transformLayer && transformLayerClass) {
+ // Create the transform layer.
+ m_transformLayer.adoptNS([[transformLayerClass alloc] init]);
+
+ // Turn off default animations.
+ [m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+
+#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.
+ [m_transformLayer.get() setBounds:[m_layer.get() bounds]];
+ [m_transformLayer.get() setPosition:[m_layer.get() position]];
+ [m_transformLayer.get() setAnchorPoint:[m_layer.get() anchorPoint]];
+#if HAVE_MODERN_QUARTZCORE
+ [m_transformLayer.get() setAnchorPointZ:[m_layer.get() anchorPointZ]];
+#endif
+ [m_transformLayer.get() setContentsRect:[m_layer.get() contentsRect]];
+#ifndef NDEBUG
+ [m_transformLayer.get() setZPosition:[m_layer.get() zPosition]];
+#endif
+
+ // The contents layer is positioned at (0,0) relative to the transformLayer.
+ [m_layer.get() setPosition:point];
+ [m_layer.get() setAnchorPoint:centerPoint];
+#ifndef NDEBUG
+ [m_layer.get() setZPosition:0.0f];
+#endif
+
+ // Transfer the transform over.
+ [m_transformLayer.get() setTransform:[m_layer.get() transform]];
+ [m_layer.get() setTransform:CATransform3DIdentity];
+
+ // Transfer the opacity from the old layer to the transform layer.
+ [m_transformLayer.get() setOpacity:m_opacity];
+ [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_transformLayer.get()];
+ [m_transformLayer.get() addSublayer:m_layer.get()];
+
+ moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get());
+ moveSublayers(m_layer.get(), m_transformLayer.get());
+
+ } else if (!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());
+ moveSublayers(m_transformLayer.get(), m_layer.get());
+
+ // Reset the layer position and transform.
+ [m_layer.get() setPosition:[m_transformLayer.get() position]];
+ [m_layer.get() setAnchorPoint:[m_transformLayer.get() anchorPoint]];
+#if HAVE_MODERN_QUARTZCORE
+ [m_layer.get() setAnchorPointZ:[m_transformLayer.get() anchorPointZ]];
+#endif
+ [m_layer.get() setContentsRect:[m_transformLayer.get() contentsRect]];
+ [m_layer.get() setTransform:[m_transformLayer.get() transform]];
+ [m_layer.get() setOpacity:[m_transformLayer.get() opacity]];
+#ifndef NDEBUG
+ [m_layer.get() setZPosition:[m_transformLayer.get() zPosition]];
+#endif
+
+ // Release the transform layer.
+ m_transformLayer = 0;
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
+{
+ if (masksToBounds == m_masksToBounds)
+ return;
+
+ GraphicsLayer::setMasksToBounds(masksToBounds);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setMasksToBounds:masksToBounds];
+ END_BLOCK_OBJC_EXCEPTIONS
+
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+}
+
+void GraphicsLayerCA::setDrawsContent(bool drawsContent)
+{
+ if (drawsContent != m_drawsContent) {
+ GraphicsLayer::setDrawsContent(drawsContent);
+
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ // Clobber any existing content. If necessary, CA will create backing store on the next display.
+ [m_layer.get() setContents:nil];
+
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+ END_BLOCK_OBJC_EXCEPTIONS
+ }
+}
+
+void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* transition, double beginTime)
+{
+ GraphicsLayer::setBackgroundColor(color, transition, beginTime);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ setHasContentsLayer(true);
+
+ if (transition && !transition->isEmptyOrZeroDuration()) {
+ CALayer* presLayer = [m_contentsLayer.get() presentationLayer];
+ // If we don't have a presentationLayer, just use the CALayer
+ if (!presLayer)
+ presLayer = m_contentsLayer.get();
+
+ // Get the current value of the background color from the layer
+ CGColorRef fromBackgroundColor = [presLayer backgroundColor];
+
+ CGColorRef bgColor = createCGColor(color);
+ setBasicAnimation(AnimatedPropertyBackgroundColor, TransformOperation::NONE, 0, fromBackgroundColor, bgColor, true, transition, beginTime);
+ CGColorRelease(bgColor);
+ } else {
+ removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor);
+ setHasContentsLayer(true);
+ setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::clearBackgroundColor()
+{
+ if (!m_contentLayerForImageOrVideo)
+ setHasContentsLayer(false);
+ else
+ clearLayerBackgroundColor(m_contentsLayer.get());
+}
+
+void GraphicsLayerCA::setContentsOpaque(bool opaque)
+{
+ GraphicsLayer::setContentsOpaque(opaque);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setOpaque:m_contentsOpaque];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setBackfaceVisibility(bool visible)
+{
+ if (m_backfaceVisibility == visible)
+ return;
+
+ GraphicsLayer::setBackfaceVisibility(visible);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setDoubleSided:visible];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+bool GraphicsLayerCA::setOpacity(float opacity, const Animation* transition, double beginTime)
+{
+ if (forceSoftwareAnimation())
+ return false;
+
+ float clampedOpacity = max(0.0f, min(opacity, 1.0f));
+
+ bool opacitiesDiffer = (m_opacity != clampedOpacity);
+
+ GraphicsLayer::setOpacity(clampedOpacity, transition, beginTime);
+
+ int animIndex = findAnimationEntry(AnimatedPropertyOpacity, 0);
+
+ // If we don't have a transition just set the opacity
+ if (!transition || transition->isEmptyOrZeroDuration()) {
+ // Three cases:
+ // 1) no existing animation or transition: just set opacity
+ // 2) existing transition: clear it and set opacity
+ // 3) existing animation: just return
+ //
+ if (animIndex < 0 || m_animations[animIndex].isTransition()) {
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [primaryLayer() setOpacity:opacity];
+ if (animIndex >= 0) {
+ removeAllAnimationsForProperty(AnimatedPropertyOpacity);
+ animIndex = -1;
+ } else {
+ String keyPath = propertyIdToString(AnimatedPropertyOpacity);
+
+ // FIXME: using hardcoded '0' here. We should be clearing all animations. For now there is only 1.
+ String animName = keyPath + "_0";
+ [animatedLayer(AnimatedPropertyOpacity) removeAnimationForKey:animName];
+ }
+ END_BLOCK_OBJC_EXCEPTIONS
+ } else {
+ // We have an animation, so don't set the opacity directly.
+ return false;
+ }
+ } else {
+ // At this point, we know we have a transition. But if it is the same and
+ // the opacity value has not changed, don't do anything.
+ if (!opacitiesDiffer &&
+ ((animIndex == -1) ||
+ (m_animations[animIndex].isTransition() && *(m_animations[animIndex].animation()) == *transition))) {
+ return false;
+ }
+ }
+
+ // If an animation is running, ignore this transition, but still save the value.
+ if (animIndex >= 0 && !m_animations[animIndex].isTransition())
+ return false;
+
+ bool didAnimate = false;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ NSNumber* fromOpacityValue = nil;
+ NSNumber* toOpacityValue = [NSNumber numberWithFloat:opacity];
+
+ if (transition && !transition->isEmptyOrZeroDuration()) {
+ CALayer* presLayer = getPresentationLayer(primaryLayer());
+ float fromOpacity = [presLayer opacity];
+ fromOpacityValue = [NSNumber numberWithFloat:fromOpacity];
+ setBasicAnimation(AnimatedPropertyOpacity, TransformOperation::NONE, 0, fromOpacityValue, toOpacityValue, true, transition, beginTime);
+ didAnimate = true;
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ return didAnimate;
+}
+
+void GraphicsLayerCA::setNeedsDisplay()
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (drawsContent())
+ [m_layer.get() setNeedsDisplay];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (drawsContent())
+ [m_layer.get() setNeedsDisplayInRect:rect];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+
+bool GraphicsLayerCA::animateTransform(const TransformValueList& valueList, const IntSize& size, const Animation* anim, double beginTime, bool isTransition)
+{
+ if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
+ return false;
+
+ TransformValueList::FunctionList functionList;
+ bool isValid, hasBigRotation;
+ valueList.makeFunctionList(functionList, isValid, hasBigRotation);
+
+ // We need to fall back to software animation if we don't have setValueFunction:, and
+ // we would need to animate each incoming transform function separately. This is the
+ // case if we have a rotation >= 180 or we have more than one transform function.
+ if ((hasBigRotation || functionList.size() > 1) && !caValueFunctionSupported())
+ return false;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ // Rules for animation:
+ //
+ // 1) If functionList is empty or we don't have a big rotation, we do a matrix animation. We could
+ // use component animation for lists without a big rotation, but there is no need to, and this
+ // is more efficient.
+ //
+ // 2) Otherwise we do a component hardware animation.
+ bool isMatrixAnimation = !isValid || !hasBigRotation;
+
+ // Set transform to identity since we are animating components and we need the base
+ // to be the identity transform.
+ TransformationMatrix t;
+ CATransform3D toT3D;
+ copyTransform(toT3D, t);
+ [primaryLayer() setTransform:toT3D];
+
+ bool isKeyframe = valueList.size() > 2;
+
+ // Iterate through the transform functions, sending an animation for each one.
+ for (int functionIndex = 0; ; ++functionIndex) {
+ if (functionIndex >= static_cast<int>(functionList.size()) && !isMatrixAnimation)
+ break;
+
+ TransformOperation::OperationType opType = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[functionIndex];
+
+ if (isKeyframe) {
+ NSMutableArray* timesArray = [[NSMutableArray alloc] init];
+ NSMutableArray* valArray = [[NSMutableArray alloc] init];
+ NSMutableArray* tfArray = [[NSMutableArray alloc] init];
+
+ // Iterate through the keyframes, building arrays for the animation.
+ for (Vector<TransformValue>::const_iterator it = valueList.values().begin(); it != valueList.values().end(); ++it) {
+ const TransformValue& curValue = (*it);
+
+ // fill in the key time and timing function
+ [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
+
+ const TimingFunction* tf = 0;
+ if (curValue.timingFunction())
+ tf = curValue.timingFunction();
+ else if (anim->isTimingFunctionSet())
+ tf = &anim->timingFunction();
+
+ CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction(LinearTimingFunction));
+ [tfArray addObject:timingFunction];
+
+ // fill in the function
+ if (isMatrixAnimation) {
+ TransformationMatrix t;
+ curValue.value()->apply(size, t);
+ CATransform3D cat;
+ copyTransform(cat, t);
+ [valArray addObject:[NSValue valueWithCATransform3D:cat]];
+ } else
+ [valArray addObject:getTransformFunctionValue(curValue, functionIndex, size, opType)];
+ }
+
+ // We toss the last tfArray value because it has to one shorter than the others.
+ [tfArray removeLastObject];
+
+ setKeyframeAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, timesArray, valArray, tfArray, isTransition, anim, beginTime);
+
+ [timesArray release];
+ [valArray release];
+ [tfArray release];
+ } else {
+ // Is a transition
+ id fromValue, toValue;
+
+ if (isMatrixAnimation) {
+ TransformationMatrix fromt, tot;
+ valueList.at(0).value()->apply(size, fromt);
+ valueList.at(1).value()->apply(size, tot);
+
+ CATransform3D cat;
+ copyTransform(cat, fromt);
+ fromValue = [NSValue valueWithCATransform3D:cat];
+ copyTransform(cat, tot);
+ toValue = [NSValue valueWithCATransform3D:cat];
+ } else {
+ fromValue = getTransformFunctionValue(valueList.at(0), functionIndex, size, opType);
+ toValue = getTransformFunctionValue(valueList.at(1), functionIndex, size, opType);
+ }
+
+ setBasicAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, fromValue, toValue, isTransition, anim, beginTime);
+ }
+
+ if (isMatrixAnimation)
+ break;
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+ return true;
+}
+
+bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValueList& valueList, const Animation* animation, double beginTime)
+{
+ if (forceSoftwareAnimation() || valueList.size() < 2)
+ return false;
+
+ // if there is already is an animation for this property and it hasn't changed, ignore it.
+ int i = findAnimationEntry(property, 0);
+ if (i >= 0 && *m_animations[i].animation() == *animation) {
+ m_animations[i].setIsCurrent();
+ return false;
+ }
+
+ if (valueList.size() == 2) {
+ float fromVal = valueList.at(0).value();
+ float toVal = valueList.at(1).value();
+ if (isnan(toVal) && isnan(fromVal))
+ return false;
+
+ // initialize the property to 0
+ [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
+ setBasicAnimation(property, TransformOperation::NONE, 0, isnan(fromVal) ? nil : [NSNumber numberWithFloat:fromVal], isnan(toVal) ? nil : [NSNumber numberWithFloat:toVal], false, animation, beginTime);
+ return true;
+ }
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ NSMutableArray* timesArray = [[NSMutableArray alloc] init];
+ NSMutableArray* valArray = [[NSMutableArray alloc] init];
+ NSMutableArray* tfArray = [[NSMutableArray alloc] init];
+
+ for (unsigned i = 0; i < valueList.values().size(); ++i) {
+ const FloatValue& curValue = valueList.values()[i];
+ [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
+ [valArray addObject:[NSNumber numberWithFloat:curValue.value()]];
+
+ const TimingFunction* tf = 0;
+ if (curValue.timingFunction())
+ tf = curValue.timingFunction();
+ else if (animation->isTimingFunctionSet())
+ tf = &animation->timingFunction();
+
+ CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
+ [tfArray addObject:timingFunction];
+ }
+
+ // We toss the last tfArray value because it has to one shorter than the others.
+ [tfArray removeLastObject];
+
+ // Initialize the property to 0.
+ [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
+ // Then set the animation.
+ setKeyframeAnimation(property, TransformOperation::NONE, 0, timesArray, valArray, tfArray, false, animation, beginTime);
+
+ [timesArray release];
+ [valArray release];
+ [tfArray release];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+ return true;
+}
+
+void GraphicsLayerCA::setContentsToImage(Image* image)
+{
+ if (image) {
+ setHasContentsLayer(true);
+
+ // FIXME: is image flipping really a property of the graphics context?
+ bool needToFlip = GraphicsLayer::graphicsContextsFlipped();
+ CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ {
+ CGImageRef theImage = image->nativeImageForCurrentFrame();
+ // FIXME: maybe only do trilinear if the image is being scaled down,
+ // but then what if the layer size changes?
+#if HAVE_MODERN_QUARTZCORE
+ [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
+#endif
+ if (needToFlip) {
+ CATransform3D flipper = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f};
+ [m_contentsLayer.get() setTransform:flipper];
+ }
+
+ [m_contentsLayer.get() setAnchorPoint:anchorPoint];
+ [m_contentsLayer.get() setContents:(id)theImage];
+ }
+ END_BLOCK_OBJC_EXCEPTIONS
+ } else
+ setHasContentsLayer(false);
+
+ m_contentLayerForImageOrVideo = (image != 0);
+}
+
+void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
+{
+ setContentsLayer(videoLayer);
+ m_contentLayerForImageOrVideo = (videoLayer != 0);
+}
+
+void GraphicsLayerCA::clearContents()
+{
+ if (m_contentLayerForImageOrVideo) {
+ setHasContentsLayer(false);
+ m_contentLayerForImageOrVideo = false;
+ }
+}
+
+void GraphicsLayerCA::updateContentsRect()
+{
+ if (m_client && m_contentsLayer) {
+ IntRect contentRect = m_client->contentsBox(this);
+
+ CGPoint point = CGPointMake(contentRect.x(),
+ contentRect.y());
+ CGRect rect = CGRectMake(0.0f,
+ 0.0f,
+ contentRect.width(),
+ contentRect.height());
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_contentsLayer.get() setPosition:point];
+ [m_contentsLayer.get() setBounds:rect];
+ END_BLOCK_OBJC_EXCEPTIONS
+ }
+}
+
+void GraphicsLayerCA::setBasicAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation* transition, double beginTime)
+{
+ ASSERT(fromVal || toVal);
+
+ WebLayer* layer = animatedLayer(property);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ // add an entry for this animation
+ addAnimationEntry(property, index, isTransition, transition);
+
+ String keyPath = propertyIdToString(property);
+ String animName = keyPath + "_" + String::number(index);
+
+ CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:keyPath];
+
+ double duration = transition->duration();
+ if (duration <= 0)
+ duration = cAnimationAlmostZeroDuration;
+
+ float repeatCount = transition->iterationCount();
+ if (repeatCount == Animation::IterationCountInfinite)
+ repeatCount = FLT_MAX;
+ else if (transition->direction() == Animation::AnimationDirectionAlternate)
+ repeatCount /= 2;
+
+ [basicAnim setDuration:duration];
+ [basicAnim setRepeatCount:repeatCount];
+ [basicAnim setAutoreverses:transition->direction()];
+ [basicAnim setRemovedOnCompletion:NO];
+
+ // Note that currently transform is the only property which has animations
+ // with an index > 0.
+ [basicAnim setAdditive:property == AnimatedPropertyWebkitTransform];
+ [basicAnim setFillMode:@"extended"];
+#if HAVE_MODERN_QUARTZCORE
+ if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType))
+ [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
+#else
+ UNUSED_PARAM(operationType);
+#endif
+
+ // Set the delegate (and property value).
+ int prop = isTransition ? property : AnimatedPropertyInvalid;
+ [basicAnim setValue:[NSNumber numberWithInt:prop] forKey:WebAnimationCSSPropertyKey];
+ [basicAnim setDelegate:m_animationDelegate.get()];
+
+ NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
+ [basicAnim setBeginTime:bt];
+
+ if (fromVal)
+ [basicAnim setFromValue:reinterpret_cast<id>(fromVal)];
+ if (toVal)
+ [basicAnim setToValue:reinterpret_cast<id>(toVal)];
+
+ const TimingFunction* tf = 0;
+ if (transition->isTimingFunctionSet())
+ tf = &transition->timingFunction();
+
+ CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
+ [basicAnim setTimingFunction:timingFunction];
+
+ // Send over the animation.
+ [layer removeAnimationForKey:animName];
+ [layer addAnimation:basicAnim forKey:animName];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setKeyframeAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* keys, void* values, void* timingFunctions,
+ bool isTransition, const Animation* anim, double beginTime)
+{
+ PlatformLayer* layer = animatedLayer(property);
+
+ // Add an entry for this animation (which may change beginTime).
+ addAnimationEntry(property, index, isTransition, anim);
+
+ String keyPath = propertyIdToString(property);
+ String animName = keyPath + "_" + String::number(index);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:keyPath];
+
+ double duration = anim->duration();
+ if (duration <= 0)
+ duration = cAnimationAlmostZeroDuration;
+
+ float repeatCount = anim->iterationCount();
+ if (repeatCount == Animation::IterationCountInfinite)
+ repeatCount = FLT_MAX;
+ else if (anim->direction() == Animation::AnimationDirectionAlternate)
+ repeatCount /= 2;
+
+ [keyframeAnim setDuration:duration];
+ [keyframeAnim setRepeatCount:repeatCount];
+ [keyframeAnim setAutoreverses:anim->direction()];
+ [keyframeAnim setRemovedOnCompletion:NO];
+
+ // The first animation is non-additive, all the rest are additive.
+ // Note that currently transform is the only property which has animations
+ // with an index > 0.
+ [keyframeAnim setAdditive:(property == AnimatedPropertyWebkitTransform) ? YES : NO];
+ [keyframeAnim setFillMode:@"extended"];
+#if HAVE_MODERN_QUARTZCORE
+ if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType))
+ [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
+#else
+ UNUSED_PARAM(operationType);
+#endif
+
+ [keyframeAnim setKeyTimes:reinterpret_cast<id>(keys)];
+ [keyframeAnim setValues:reinterpret_cast<id>(values)];
+
+ // Set the delegate (and property value).
+ int prop = isTransition ? property : AnimatedPropertyInvalid;
+ [keyframeAnim setValue:[NSNumber numberWithInt: prop] forKey:WebAnimationCSSPropertyKey];
+ [keyframeAnim setDelegate:m_animationDelegate.get()];
+
+ NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
+ [keyframeAnim setBeginTime:bt];
+
+ // Set the timing functions, if any.
+ if (timingFunctions != nil)
+ [keyframeAnim setTimingFunctions:(id)timingFunctions];
+
+ // Send over the animation.
+ [layer removeAnimationForKey:animName];
+ [layer addAnimation:keyframeAnim forKey:animName];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::suspendAnimations()
+{
+ double t = currentTimeToMediaTime(currentTime());
+ [primaryLayer() setSpeed:0];
+ [primaryLayer() setTimeOffset:t];
+}
+
+void GraphicsLayerCA::resumeAnimations()
+{
+ [primaryLayer() setSpeed:1];
+ [primaryLayer() setTimeOffset:0];
+}
+
+void GraphicsLayerCA::removeAnimation(int index, bool reset)
+{
+ ASSERT(index >= 0);
+
+ AnimatedPropertyID property = m_animations[index].property();
+
+ // Set the value of the property and remove the animation.
+ String keyPath = propertyIdToString(property);
+ String animName = keyPath + "_" + String::number(m_animations[index].index());
+ CALayer* layer = animatedLayer(property);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ // If we are not resetting, it means we are pausing. So we need to get the current presentation
+ // value into the property before we remove the animation.
+ if (!reset) {
+ // Put the current value into the property.
+ CALayer* presLayer = [layer presentationLayer];
+ if (presLayer)
+ [layer setValue:[presLayer valueForKeyPath:keyPath] forKeyPath:keyPath];
+
+ // Make sure the saved values accurately reflect the value in the layer.
+ id val = [layer valueForKeyPath:keyPath];
+ switch (property) {
+ case AnimatedPropertyWebkitTransform:
+ // FIXME: needs comment explaining why the m_transform is not obtained from the layer
+ break;
+ case AnimatedPropertyBackgroundColor:
+ m_backgroundColor = Color(reinterpret_cast<CGColorRef>(val));
+ break;
+ case AnimatedPropertyOpacity:
+ m_opacity = [val floatValue];
+ break;
+ case AnimatedPropertyInvalid:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ // If we have reached the end of an animation, we don't want to actually remove the
+ // animation from the CALayer. At some point we will be setting the property to its
+ // unanimated value and at that point we will remove the animation. That will avoid
+ // any flashing between the time the animation is removed and the property is set.
+ if (!reset || m_animations[index].isTransition())
+ [layer removeAnimationForKey:animName];
+
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ // Remove the animation entry.
+ m_animations.remove(index);
+}
+
+PlatformLayer* GraphicsLayerCA::hostLayerForSublayers() const
+{
+ return m_transformLayer ? m_transformLayer.get() : m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerCA::layerForSuperlayer() const
+{
+ if (m_transformLayer)
+ return m_transformLayer.get();
+
+ return m_layer.get();
+}
+
+PlatformLayer* GraphicsLayerCA::platformLayer() const
+{
+ return primaryLayer();
+}
+
+#ifndef NDEBUG
+void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (color.isValid())
+ setLayerBackgroundColor(m_layer.get(), color);
+ else
+ clearLayerBackgroundColor(m_layer.get());
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (color.isValid()) {
+ setLayerBorderColor(m_layer.get(), color);
+ [m_layer.get() setBorderWidth:borderWidth];
+ } else {
+ clearBorderColor(m_layer.get());
+ [m_layer.get() setBorderWidth:0];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setZPosition(float position)
+{
+ GraphicsLayer::setZPosition(position);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [primaryLayer() setZPosition:position];
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+#endif
+
+bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
+{
+ if (!m_drawsContent)
+ return false;
+
+ // FIXME: catch zero-size height or width here (or earlier)?
+ return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
+}
+
+void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer)
+{
+ if (userTiledLayer == m_usingTiledLayer)
+ return;
+
+ CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ RetainPtr<CALayer> oldLayer = m_layer.get();
+
+ Class layerClass = userTiledLayer ? [WebTiledLayer self] : [WebLayer self];
+ m_layer.adoptNS([[layerClass alloc] init]);
+
+ if (userTiledLayer) {
+ WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get();
+ [tiledLayer setTileSize:tileSize];
+ [tiledLayer setLevelsOfDetail:1];
+ [tiledLayer setLevelsOfDetailBias:0];
+
+ if (GraphicsLayer::graphicsContextsFlipped())
+ [tiledLayer setContentsGravity:@"bottomLeft"];
+ else
+ [tiledLayer setContentsGravity:@"topLeft"];
+ }
+
+ [m_layer.get() setLayerOwner:this];
+ [m_layer.get() setSublayers:[oldLayer.get() sublayers]];
+
+ [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()];
+
+ [m_layer.get() setBounds:[oldLayer.get() bounds]];
+ [m_layer.get() setPosition:[oldLayer.get() position]];
+ [m_layer.get() setAnchorPoint:[oldLayer.get() anchorPoint]];
+ [m_layer.get() setOpaque:[oldLayer.get() isOpaque]];
+ [m_layer.get() setOpacity:[oldLayer.get() opacity]];
+ [m_layer.get() setTransform:[oldLayer.get() transform]];
+ [m_layer.get() setSublayerTransform:[oldLayer.get() sublayerTransform]];
+ [m_layer.get() setDoubleSided:[oldLayer.get() isDoubleSided]];
+#ifndef NDEBUG
+ [m_layer.get() setZPosition:[oldLayer.get() zPosition]];
+#endif
+
+#ifndef NDEBUG
+ String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name;
+ [m_layer.get() setName:name];
+#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());
+
+ // need to tell new layer to draw itself
+ setNeedsDisplay();
+
+ END_BLOCK_OBJC_EXCEPTIONS
+
+ m_usingTiledLayer = userTiledLayer;
+
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+}
+
+void GraphicsLayerCA::setHasContentsLayer(bool hasLayer)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (hasLayer && !m_contentsLayer) {
+ // create the inner layer
+ WebLayer* contentsLayer = [WebLayer layer];
+#ifndef NDEBUG
+ [contentsLayer setName:@"Contents Layer"];
+#endif
+ setContentsLayer(contentsLayer);
+
+ } else if (!hasLayer && m_contentsLayer)
+ setContentsLayer(0);
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer)
+{
+ if (contentsLayer == m_contentsLayer)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS
+
+ if (m_contentsLayer) {
+ [m_contentsLayer.get() removeFromSuperlayer];
+ m_contentsLayer = 0;
+ }
+
+ if (contentsLayer) {
+ // Turn off implicit animations on the inner layer.
+ [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
+
+ m_contentsLayer.adoptNS([contentsLayer retain]);
+ [m_contentsLayer.get() setAnchorPoint:CGPointZero];
+ [m_layer.get() addSublayer:m_contentsLayer.get()];
+
+ updateContentsRect();
+
+ // Set contents to nil if the layer does not draw its own content.
+ if (m_client && !drawsContent())
+ [m_layer.get() setContents:nil];
+
+#ifndef NDEBUG
+ if (showDebugBorders()) {
+ setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180));
+ [m_contentsLayer.get() setBorderWidth:1.0f];
+ }
+#endif
+ }
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
+
+ END_BLOCK_OBJC_EXCEPTIONS
+}
+
+} // namespace WebCore
+
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index 3f18ab4..677c31a 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
#if ENABLE(VIDEO)
-#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
#include "Timer.h"
#include <wtf/RetainPtr.h>
@@ -52,11 +52,28 @@ class WebCoreMovieObserver;
namespace WebCore {
-class MediaPlayerPrivate : Noncopyable {
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
public:
- MediaPlayerPrivate(MediaPlayer*);
+ static void registerMediaEngine(MediaEngineRegistrar);
+
~MediaPlayerPrivate();
-
+
+ void repaint();
+ void loadStateChanged();
+ void rateChanged();
+ void sizeChanged();
+ void timeChanged();
+ void didEnd();
+
+private:
+ MediaPlayerPrivate(MediaPlayer*);
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
IntSize naturalSize() const;
bool hasVideo() const;
@@ -72,11 +89,12 @@ public:
float duration() const;
float currentTime() const;
void seek(float time);
- void setEndTime(float time);
void setRate(float);
void setVolume(float);
-
+
+ void setEndTime(float time);
+
int dataRate() const;
MediaPlayer::NetworkState networkState() const { return m_networkState; }
@@ -89,21 +107,10 @@ public:
unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect& r);
-
- void loadStateChanged();
- void rateChanged();
- void sizeChanged();
- void timeChanged();
- void didEnd();
+ void setSize(const IntSize&);
- void repaint();
void paint(GraphicsContext*, const IntRect&);
-
- static void getSupportedTypes(HashSet<String>& types);
- static bool isAvailable();
-
-private:
+
void createQTMovie(const String& url);
void setUpVideoRendering();
void tearDownVideoRendering();
@@ -117,10 +124,10 @@ private:
void doSeek();
void cancelSeek();
void seekTimerFired(Timer<MediaPlayerPrivate>*);
- void endPointTimerFired(Timer<MediaPlayerPrivate>*);
float maxTimeLoaded() const;
- void startEndPointTimerIfNeeded();
- void disableUnsupportedTracks(unsigned& enabledTrackCount);
+ void disableUnsupportedTracks();
+
+ bool metaDataAvailable() const { return m_qtMovie && m_readyState >= MediaPlayer::HaveMetadata; }
MediaPlayer* m_player;
RetainPtr<QTMovie> m_qtMovie;
@@ -128,14 +135,15 @@ private:
RetainPtr<QTVideoRendererWebKitOnly> m_qtVideoRenderer;
RetainPtr<WebCoreMovieObserver> m_objcObserver;
float m_seekTo;
- float m_endTime;
Timer<MediaPlayerPrivate> m_seekTimer;
- Timer<MediaPlayerPrivate> m_endPointTimer;
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
bool m_startedPlaying;
bool m_isStreaming;
bool m_visible;
+ IntRect m_rect;
+ unsigned m_enabledTrackCount;
+ float m_duration;
#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 a33c8d2..74a9ff9 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -69,6 +69,7 @@ SOFT_LINK_CLASS(QTKit, QTMovieView)
SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeMPEG, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeSound, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeText, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeVideo, NSString *)
@@ -95,6 +96,7 @@ SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification,
#define QTMediaTypeAttribute getQTMediaTypeAttribute()
#define QTMediaTypeBase getQTMediaTypeBase()
+#define QTMediaTypeMPEG getQTMediaTypeMPEG()
#define QTMediaTypeSound getQTMediaTypeSound()
#define QTMediaTypeText getQTMediaTypeText()
#define QTMediaTypeVideo getQTMediaTypeVideo()
@@ -155,24 +157,35 @@ using namespace std;
namespace WebCore {
-static const float endPointTimerInterval = 0.020f;
-
#ifdef BUILDING_ON_TIGER
static const long minimumQuickTimeVersion = 0x07300000; // 7.3
#endif
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_objcObserver(AdoptNS, [[WebCoreMovieObserver alloc] initWithCallback:this])
, m_seekTo(-1)
- , m_endTime(numeric_limits<float>::infinity())
, m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
- , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired)
, m_networkState(MediaPlayer::Empty)
- , m_readyState(MediaPlayer::DataUnavailable)
+ , m_readyState(MediaPlayer::HaveNothing)
, m_startedPlaying(false)
, m_isStreaming(false)
, m_visible(false)
+ , m_rect()
+ , m_enabledTrackCount(0)
+ , m_duration(-1.0f)
#if DRAW_FRAME_RATE
, m_frameCountWhilePlaying(0)
, m_timeStartedPlaying(0)
@@ -270,7 +283,7 @@ void MediaPlayerPrivate::createQTMovieView()
detachQTMovieView();
static bool addedCustomMethods = false;
- if (!addedCustomMethods) {
+ if (!m_player->inMediaDocument() && !addedCustomMethods) {
Class QTMovieContentViewClass = NSClassFromString(@"QTMovieContentView");
ASSERT(QTMovieContentViewClass);
@@ -281,9 +294,12 @@ void MediaPlayerPrivate::createQTMovieView()
addedCustomMethods = true;
}
+ // delay callbacks as we *will* get notifications during setup
+ [m_objcObserver.get() setDelayCallbacks:YES];
+
m_qtMovieView.adoptNS([[QTMovieView alloc] init]);
- setRect(m_player->rect());
- NSView* parentView = m_player->m_frameView->documentView();
+ setSize(m_player->size());
+ NSView* parentView = m_player->frameView()->documentView();
[parentView addSubview:m_qtMovieView.get()];
#ifdef BUILDING_ON_TIGER
// setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy
@@ -303,6 +319,8 @@ void MediaPlayerPrivate::createQTMovieView()
// Note that we expect mainThreadSetNeedsDisplay to be invoked only when synchronous drawing is requested.
if (!m_player->inMediaDocument())
wkQTMovieViewSetDrawSynchronously(m_qtMovieView.get(), YES);
+
+ [m_objcObserver.get() setDelayCallbacks:NO];
}
void MediaPlayerPrivate::detachQTMovieView()
@@ -356,7 +374,7 @@ void MediaPlayerPrivate::destroyQTVideoRenderer()
void MediaPlayerPrivate::setUpVideoRendering()
{
- if (!m_player->m_frameView || !m_qtMovie)
+ if (!m_player->frameView() || !m_qtMovie)
return;
if (m_player->inMediaDocument() || !QTVideoRendererClass() )
@@ -375,7 +393,7 @@ void MediaPlayerPrivate::tearDownVideoRendering()
QTTime MediaPlayerPrivate::createQTTime(float time) const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return QTMakeTime(0, 600);
long timeScale = [[m_qtMovie.get() attributeForKey:QTMovieTimeScaleAttribute] longValue];
return QTMakeTime(time * timeScale, timeScale);
@@ -387,12 +405,11 @@ void MediaPlayerPrivate::load(const String& url)
m_networkState = MediaPlayer::Loading;
m_player->networkStateChanged();
}
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
cancelSeek();
- m_endPointTimer.stop();
[m_objcObserver.get() setDelayCallbacks:YES];
@@ -404,7 +421,7 @@ void MediaPlayerPrivate::load(const String& url)
void MediaPlayerPrivate::play()
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
m_startedPlaying = true;
#if DRAW_FRAME_RATE
@@ -413,12 +430,11 @@ void MediaPlayerPrivate::play()
[m_objcObserver.get() setDelayCallbacks:YES];
[m_qtMovie.get() setRate:m_player->rate()];
[m_objcObserver.get() setDelayCallbacks:NO];
- startEndPointTimerIfNeeded();
}
void MediaPlayerPrivate::pause()
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
m_startedPlaying = false;
#if DRAW_FRAME_RATE
@@ -427,12 +443,11 @@ void MediaPlayerPrivate::pause()
[m_objcObserver.get() setDelayCallbacks:YES];
[m_qtMovie.get() stop];
[m_objcObserver.get() setDelayCallbacks:NO];
- m_endPointTimer.stop();
}
float MediaPlayerPrivate::duration() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
QTTime time = [m_qtMovie.get() duration];
if (time.flags == kQTTimeIsIndefinite)
@@ -442,22 +457,22 @@ float MediaPlayerPrivate::duration() const
float MediaPlayerPrivate::currentTime() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
QTTime time = [m_qtMovie.get() currentTime];
- return min(static_cast<float>(time.timeValue) / time.timeScale, m_endTime);
+ return static_cast<float>(time.timeValue) / time.timeScale;
}
void MediaPlayerPrivate::seek(float time)
{
cancelSeek();
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
if (time > duration())
time = duration();
-
+
m_seekTo = time;
if (maxTimeLoaded() >= m_seekTo)
doSeek();
@@ -475,7 +490,7 @@ void MediaPlayerPrivate::doSeek()
[m_qtMovie.get() setCurrentTime:qttime];
float timeAfterSeek = currentTime();
// restore playback only if not at end, othewise QTMovie will loop
- if (timeAfterSeek < duration() && timeAfterSeek < m_endTime)
+ if (oldRate && timeAfterSeek < duration())
[m_qtMovie.get() setRate:oldRate];
cancelSeek();
[m_objcObserver.get() setDelayCallbacks:NO];
@@ -489,7 +504,7 @@ void MediaPlayerPrivate::cancelSeek()
void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
{
- if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) {
+ if (!metaDataAvailable()|| !seeking() || currentTime() == m_seekTo) {
cancelSeek();
updateStates();
m_player->timeChanged();
@@ -508,67 +523,48 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
}
}
-void MediaPlayerPrivate::setEndTime(float time)
+void MediaPlayerPrivate::setEndTime(float)
{
- m_endTime = time;
- startEndPointTimerIfNeeded();
-}
-
-void MediaPlayerPrivate::startEndPointTimerIfNeeded()
-{
- if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive())
- m_endPointTimer.startRepeating(endPointTimerInterval);
-}
-
-void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
-{
- float time = currentTime();
-
- // just do end for now
- if (time >= m_endTime) {
- pause();
- didEnd();
- }
}
bool MediaPlayerPrivate::paused() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return true;
return [m_qtMovie.get() rate] == 0;
}
bool MediaPlayerPrivate::seeking() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return false;
return m_seekTo >= 0;
}
IntSize MediaPlayerPrivate::naturalSize() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return IntSize();
return IntSize([[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]);
}
bool MediaPlayerPrivate::hasVideo() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return false;
return [[m_qtMovie.get() attributeForKey:QTMovieHasVideoAttribute] boolValue];
}
void MediaPlayerPrivate::setVolume(float volume)
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
[m_qtMovie.get() setVolume:volume];
}
void MediaPlayerPrivate::setRate(float rate)
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return;
if (!paused())
[m_qtMovie.get() setRate:rate];
@@ -576,7 +572,7 @@ void MediaPlayerPrivate::setRate(float rate)
int MediaPlayerPrivate::dataRate() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
return wkQTMovieDataRate(m_qtMovie.get());
}
@@ -596,7 +592,7 @@ float MediaPlayerPrivate::maxTimeSeekable() const
float MediaPlayerPrivate::maxTimeLoaded() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
return wkQTMovieMaxTimeLoaded(m_qtMovie.get());
}
@@ -616,7 +612,7 @@ bool MediaPlayerPrivate::totalBytesKnown() const
unsigned MediaPlayerPrivate::totalBytes() const
{
- if (!m_qtMovie)
+ if (!metaDataAvailable())
return 0;
return [[m_qtMovie.get() attributeForKey:QTMovieDataSizeAttribute] intValue];
}
@@ -639,52 +635,66 @@ void MediaPlayerPrivate::updateStates()
MediaPlayer::ReadyState oldReadyState = m_readyState;
long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError);
-
- if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData && !m_player->inMediaDocument()) {
- unsigned enabledTrackCount;
- disableUnsupportedTracks(enabledTrackCount);
- // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>
- if (!enabledTrackCount)
+
+ if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) {
+ disableUnsupportedTracks();
+ if (!m_enabledTrackCount)
loadState = QTMovieLoadStateError;
}
- // "Loaded" is reserved for fully buffered movies, never the case when streaming
if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
- if (m_networkState < MediaPlayer::Loaded)
- m_networkState = MediaPlayer::Loaded;
- m_readyState = MediaPlayer::CanPlayThrough;
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (loadState >= QTMovieLoadStatePlaythroughOK) {
- if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
- m_networkState = MediaPlayer::LoadedFirstFrame;
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveFutureData;
+ m_networkState = MediaPlayer::Loading;
} else if (loadState >= QTMovieLoadStatePlayable) {
- if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
- m_networkState = MediaPlayer::LoadedFirstFrame;
// FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
- m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable;
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+ m_networkState = MediaPlayer::Loading;
} else if (loadState >= QTMovieLoadStateLoaded) {
- if (m_networkState < MediaPlayer::LoadedMetaData)
- m_networkState = MediaPlayer::LoadedMetaData;
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveMetadata;
+ m_networkState = MediaPlayer::Loading;
} else if (loadState > QTMovieLoadStateError) {
- if (m_networkState < MediaPlayer::Loading)
- m_networkState = MediaPlayer::Loading;
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveNothing;
+ m_networkState = MediaPlayer::Loading;
} else {
- m_networkState = MediaPlayer::LoadFailed;
- m_readyState = MediaPlayer::DataUnavailable;
+ float loaded = maxTimeLoaded();
+
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
}
if (seeking())
- m_readyState = MediaPlayer::DataUnavailable;
-
+ m_readyState = MediaPlayer::HaveNothing;
+
if (m_networkState != oldNetworkState)
m_player->networkStateChanged();
if (m_readyState != oldReadyState)
m_player->readyStateChanged();
- if (loadState >= QTMovieLoadStateLoaded && oldNetworkState < MediaPlayer::LoadedMetaData && m_player->visible())
+ if (loadState >= QTMovieLoadStateLoaded && oldReadyState < MediaPlayer::HaveMetadata && m_player->visible())
setUpVideoRendering();
+
+ if (loadState >= QTMovieLoadStateLoaded) {
+ float dur = duration();
+ if (dur != m_duration) {
+ if (m_duration != -1.0f)
+ m_player->durationChanged();
+ m_duration = dur;
+ }
+ }
}
void MediaPlayerPrivate::loadStateChanged()
@@ -695,10 +705,12 @@ void MediaPlayerPrivate::loadStateChanged()
void MediaPlayerPrivate::rateChanged()
{
updateStates();
+ m_player->rateChanged();
}
void MediaPlayerPrivate::sizeChanged()
{
+ m_player->sizeChanged();
}
void MediaPlayerPrivate::timeChanged()
@@ -709,7 +721,6 @@ void MediaPlayerPrivate::timeChanged()
void MediaPlayerPrivate::didEnd()
{
- m_endPointTimer.stop();
m_startedPlaying = false;
#if DRAW_FRAME_RATE
m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate];
@@ -718,18 +729,19 @@ void MediaPlayerPrivate::didEnd()
m_player->timeChanged();
}
-void MediaPlayerPrivate::setRect(const IntRect& r)
+void MediaPlayerPrivate::setSize(const IntSize& size)
{
if (!m_qtMovieView)
return;
+ m_rect.setSize(size);
if (m_player->inMediaDocument())
// We need the QTMovieView to be placed in the proper location for document mode.
- [m_qtMovieView.get() setFrame:r];
+ [m_qtMovieView.get() setFrame:m_rect];
else {
// We don't really need the QTMovieView in any specific location so let's just get it out of the way
// where it won't intercept events or try to bring up the context menu.
- IntRect farAwayButCorrectSize(r);
+ IntRect farAwayButCorrectSize(m_rect);
farAwayButCorrectSize.move(-1000000, -1000000);
[m_qtMovieView.get() setFrame:farAwayButCorrectSize];
}
@@ -740,7 +752,7 @@ void MediaPlayerPrivate::setVisible(bool b)
if (m_visible != b) {
m_visible = b;
if (b) {
- if (m_networkState >= MediaPlayer::LoadedMetaData)
+ if (m_readyState >= MediaPlayer::HaveMetadata)
setUpVideoRendering();
} else
tearDownVideoRendering();
@@ -789,13 +801,19 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
[NSGraphicsContext setCurrentContext:newContext];
[(id<WebKitVideoRenderingDetails>)qtVideoRenderer drawInRect:paintRect];
[NSGraphicsContext restoreGraphicsState];
- } else
+ } else {
+ if (m_player->inMediaDocument() && r != m_rect) {
+ // the QTMovieView needs to be placed in the proper location for document mode
+ m_rect = r;
+ [view setFrame:m_rect];
+ }
[view displayRectIgnoringOpacity:paintRect inContext:newContext];
+ }
#if DRAW_FRAME_RATE
// Draw the frame rate only after having played more than 10 frames.
if (m_frameCountWhilePlaying > 10) {
- Frame* frame = m_player->m_frameView ? m_player->m_frameView->frame() : NULL;
+ 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;
@@ -821,22 +839,42 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
[m_objcObserver.get() setDelayCallbacks:NO];
}
-void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+static HashSet<String> mimeTypeCache()
{
- NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes];
- int count = [fileTypes count];
- for (int n = 0; n < count; n++) {
- CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]);
- RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL));
- if (!uti)
- continue;
- RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType));
- if (!mime)
- continue;
- types.add(mime.get());
+ DEFINE_STATIC_LOCAL(HashSet<String>, cache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes];
+ int count = [fileTypes count];
+ for (int n = 0; n < count; n++) {
+ CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]);
+ RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL));
+ if (!uti)
+ continue;
+ RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType));
+ if (!mime)
+ continue;
+ cache.add(mime.get());
+ }
+ typeListInitialized = true;
}
-}
+ return cache;
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type yet
+ return mimeTypeCache().contains(type) ? (codecs && !codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
bool MediaPlayerPrivate::isAvailable()
{
#ifdef BUILDING_ON_TIGER
@@ -858,10 +896,10 @@ bool MediaPlayerPrivate::isAvailable()
#endif
}
-void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
+void MediaPlayerPrivate::disableUnsupportedTracks()
{
if (!m_qtMovie) {
- enabledTrackCount = 0;
+ m_enabledTrackCount = 0;
return;
}
@@ -872,6 +910,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
allowedTrackTypes->add(QTMediaTypeSound);
allowedTrackTypes->add(QTMediaTypeText);
allowedTrackTypes->add(QTMediaTypeBase);
+ allowedTrackTypes->add(QTMediaTypeMPEG);
allowedTrackTypes->add("clcp");
allowedTrackTypes->add("sbtl");
}
@@ -879,7 +918,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
NSArray *tracks = [m_qtMovie.get() tracks];
unsigned trackCount = [tracks count];
- enabledTrackCount = trackCount;
+ m_enabledTrackCount = trackCount;
for (unsigned trackIndex = 0; trackIndex < trackCount; trackIndex++) {
// Grab the track at the current index. If there isn't one there, then
// we can move onto the next one.
@@ -907,7 +946,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
if (!allowedTrackTypes->contains(mediaType)) {
// If this track type is not allowed, then we need to disable it.
[track setEnabled:NO];
- --enabledTrackCount;
+ --m_enabledTrackCount;
}
// Disable chapter tracks. These are most likely to lead to trouble, as
@@ -939,7 +978,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
// Disable the evil, evil track.
[chapterTrack setEnabled:NO];
- --enabledTrackCount;
+ --m_enabledTrackCount;
}
}
@@ -947,7 +986,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
@implementation WebCoreMovieObserver
-- (id)initWithCallback:(MediaPlayerPrivate *)callback
+- (id)initWithCallback:(MediaPlayerPrivate*)callback
{
m_callback = callback;
return [super init];
diff --git a/WebCore/platform/graphics/mac/MediaPlayerProxy.h b/WebCore/platform/graphics/mac/MediaPlayerProxy.h
new file mode 100644
index 0000000..6060484
--- /dev/null
+++ b/WebCore/platform/graphics/mac/MediaPlayerProxy.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaPlayerProxy_h
+#define MediaPlayerProxy_h
+
+#ifdef __OBJC__
+@class WebMediaPlayerProxy;
+#else
+class WebMediaPlayerProxy;
+#endif
+
+enum MediaPlayerProxyNotificationType {
+
+ MediaPlayerNotificationMediaValidated = 1,
+ MediaPlayerNotificationMediaFailedToValidate,
+
+ MediaPlayerNotificationStartUsingNetwork,
+ MediaPlayerNotificationStopUsingNetwork,
+
+ MediaPlayerNotificationEnteredFullScreen,
+ MediaPlayerNotificationExitedFullScreen,
+
+ MediaPlayerNotificationReadyForInspection,
+ MediaPlayerNotificationReadyForPlayback,
+ MediaPlayerNotificationDidPlayToTheEnd,
+
+ MediaPlayerNotificationPlaybackFailed,
+
+ MediaPlayerNotificationStreamLikelyToKeepUp,
+ MediaPlayerNotificationStreamUnlikelyToKeepUp,
+ MediaPlayerNotificationStreamBufferFull,
+ MediaPlayerNotificationStreamRanDry,
+ MediaPlayerNotificationFileLoaded,
+
+ MediaPlayerNotificationSizeDidChange,
+ MediaPlayerNotificationVolumeDidChange,
+ MediaPlayerNotificationMutedDidChange,
+ MediaPlayerNotificationTimeJumped,
+
+ MediaPlayerNotificationPlayPauseButtonPressed,
+};
+
+#ifdef __OBJC__
+@interface NSObject (WebMediaPlayerProxy)
+
+- (int)_interfaceVersion;
+
+- (void)_disconnect;
+
+- (void)_load:(NSURL *)url;
+- (void)_cancelLoad;
+
+- (void)_setPoster:(NSURL *)url;
+
+- (void)_play;
+- (void)_pause;
+
+- (NSSize)_naturalSize;
+
+- (BOOL)_hasVideo;
+- (BOOL)_hasAudio;
+
+- (NSTimeInterval)_duration;
+
+- (double)_currentTime;
+- (void)_setCurrentTime:(double)time;
+- (BOOL)_seeking;
+
+- (void)_setEndTime:(double)time;
+
+- (float)_rate;
+- (void)_setRate:(float)rate;
+
+- (float)_volume;
+- (void)_setVolume:(float)newVolume;
+
+- (BOOL)_muted;
+- (void)_setMuted:(BOOL)muted;
+
+- (float)_maxTimeBuffered;
+- (float)_maxTimeSeekable;
+- (NSArray *)_bufferedTimeRanges;
+
+- (int)_dataRate;
+
+- (BOOL)_totalBytesKnown;
+- (unsigned)_totalBytes;
+- (unsigned)_bytesLoaded;
+
+- (NSArray *)_mimeTypes;
+
+@end
+#endif
+
+#endif
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
index 30dbf97..a3c10fa 100644
--- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -38,6 +38,7 @@
#import "FontDescription.h"
#import "SharedBuffer.h"
#import "WebCoreSystemInterface.h"
+#import <AppKit/AppKit.h>
#import <ApplicationServices/ApplicationServices.h>
#import <float.h>
#import <unicode/uchar.h>
diff --git a/WebCore/platform/graphics/mac/WebLayer.h b/WebCore/platform/graphics/mac/WebLayer.h
new file mode 100644
index 0000000..b8b46ed
--- /dev/null
+++ b/WebCore/platform/graphics/mac/WebLayer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebLayer_h
+#define WebLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import <QuartzCore/QuartzCore.h>
+
+namespace WebCore {
+ class GraphicsLayer;
+}
+
+// Category implemented by WebLayer and WebTiledLayer.
+@interface CALayer(WebLayerAdditions)
+
+- (void)setLayerOwner:(WebCore::GraphicsLayer*)layer;
+- (WebCore::GraphicsLayer*)layerOwner;
+
+@end
+
+@interface WebLayer : CALayer
+{
+ WebCore::GraphicsLayer* m_layerOwner;
+}
+
+// Class method allows us to share implementation across TiledLayerMac and WebLayer
++ (void)drawContents:(WebCore::GraphicsLayer*)layerContents ofLayer:(CALayer*)layer intoContext:(CGContextRef)context;
+
+@end
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebLayer_h
diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm
new file mode 100644
index 0000000..267b5bc
--- /dev/null
+++ b/WebCore/platform/graphics/mac/WebLayer.mm
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebLayer.h"
+
+#import "GraphicsContext.h"
+#import "GraphicsLayer.h"
+#import <QuartzCore/QuartzCore.h>
+#import "WebCoreTextRenderer.h"
+#import <wtf/UnusedParam.h>
+
+using namespace WebCore;
+
+@implementation WebLayer
+
++ (void)drawContents:(WebCore::GraphicsLayer*)layerContents ofLayer:(CALayer*)layer intoContext:(CGContextRef)context
+{
+ UNUSED_PARAM(layer);
+ CGContextSaveGState(context);
+
+ if (layerContents && layerContents->client()) {
+ [NSGraphicsContext saveGraphicsState];
+
+ // Set up an NSGraphicsContext for the context, so that parts of AppKit that rely on
+ // the current NSGraphicsContext (e.g. NSCell drawing) get the right one.
+ NSGraphicsContext* layerContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES];
+ [NSGraphicsContext setCurrentContext:layerContext];
+
+ GraphicsContext graphicsContext(context);
+
+ // It's important to get the clip from the context, because it may be significantly
+ // smaller than the layer bounds (e.g. tiled layers)
+ CGRect clipBounds = CGContextGetClipBoundingBox(context);
+ IntRect clip(enclosingIntRect(clipBounds));
+ layerContents->paintGraphicsLayerContents(graphicsContext, clip);
+
+ [NSGraphicsContext restoreGraphicsState];
+ }
+#ifndef NDEBUG
+ else {
+ ASSERT_NOT_REACHED();
+
+ // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
+ // so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
+ CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
+ CGRect aBounds = [layer bounds];
+ CGContextFillRect(context, aBounds);
+ }
+#endif
+
+ CGContextRestoreGState(context);
+
+#ifndef NDEBUG
+ if (layerContents && layerContents->showRepaintCounter()) {
+ bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]];
+
+ char text[16]; // that's a lot of repaints
+ snprintf(text, sizeof(text), "%d", layerContents->incrementRepaintCount());
+
+ CGAffineTransform a = CGContextGetCTM(context);
+
+ CGContextSaveGState(context);
+ if (isTiledLayer)
+ CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 0.8f);
+ else
+ CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
+
+ CGRect aBounds = [layer bounds];
+
+ aBounds.size.width = 10 + 12 * strlen(text);
+ aBounds.size.height = 25;
+ CGContextFillRect(context, aBounds);
+
+ CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f);
+
+ CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));
+ CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman);
+ CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text));
+
+ CGContextRestoreGState(context);
+ }
+#endif
+}
+
+// Disable default animations
+- (id<CAAction>)actionForKey:(NSString *)key
+{
+ UNUSED_PARAM(key);
+ return nil;
+}
+
+// Implement this so presentationLayer can get our custom attributes
+- (id)initWithLayer:(id)layer
+{
+ if ((self = [super initWithLayer:layer]))
+ m_layerOwner = [(WebLayer*)layer layerOwner];
+
+ return self;
+}
+
+- (void)setNeedsDisplay
+{
+ if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent())
+ [super setNeedsDisplay];
+}
+
+- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
+{
+ if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) {
+ [super setNeedsDisplayInRect:dirtyRect];
+
+#ifndef NDEBUG
+ if (m_layerOwner->showRepaintCounter()) {
+ CGRect bounds = [self bounds];
+ [super setNeedsDisplayInRect:CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25)];
+ }
+#endif
+ }
+}
+
+- (void)drawInContext:(CGContextRef)context
+{
+ [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:context];
+}
+
+@end // implementation WebLayer
+
+#pragma mark -
+
+@implementation WebLayer(WebLayerAdditions)
+
+- (void)setLayerOwner:(GraphicsLayer*)aLayer
+{
+ m_layerOwner = aLayer;
+}
+
+- (GraphicsLayer*)layerOwner
+{
+ return m_layerOwner;
+}
+
+@end
+
+#pragma mark -
+
+#ifndef NDEBUG
+
+@implementation CALayer(ExtendedDescription)
+
+- (NSString*)_descriptionWithPrefix:(NSString*)inPrefix
+{
+ CGRect aBounds = [self bounds];
+ CGPoint aPos = [self position];
+ CATransform3D t = [self transform];
+
+ NSString* selfString = [NSString stringWithFormat:@"%@<%@ 0x%08x> \"%@\" bounds(%.1f, %.1f, %.1f, %.1f) pos(%.1f, %.1f), sublayers=%d masking=%d",
+ inPrefix,
+ [self class],
+ self,
+ [self name],
+ aBounds.origin.x, aBounds.origin.y, aBounds.size.width, aBounds.size.height,
+ aPos.x, aPos.y,
+ [[self sublayers] count],
+ [self masksToBounds]];
+
+ NSMutableString* curDesc = [NSMutableString stringWithString:selfString];
+
+ if ([[self sublayers] count] > 0)
+ [curDesc appendString:@"\n"];
+
+ NSString* sublayerPrefix = [inPrefix stringByAppendingString:@"\t"];
+
+ NSEnumerator* sublayersEnum = [[self sublayers] objectEnumerator];
+ CALayer* curLayer;
+ while ((curLayer = [sublayersEnum nextObject]))
+ [curDesc appendString:[curLayer _descriptionWithPrefix:sublayerPrefix]];
+
+ if ([[self sublayers] count] == 0)
+ [curDesc appendString:@"\n"];
+
+ return curDesc;
+}
+
+- (NSString*)extendedDescription
+{
+ return [self _descriptionWithPrefix:@""];
+}
+
+@end // implementation WebLayer(ExtendedDescription)
+
+#endif // NDEBUG
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.h b/WebCore/platform/graphics/mac/WebTiledLayer.h
new file mode 100644
index 0000000..1c9144d
--- /dev/null
+++ b/WebCore/platform/graphics/mac/WebTiledLayer.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebTiledLayer_h
+#define WebTiledLayer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebLayer.h"
+
+@interface WebTiledLayer : CATiledLayer
+{
+ WebCore::GraphicsLayer* m_layerOwner;
+}
+
+// implements WebLayerAdditions
+
+@end
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif // WebTiledLayer_h
+
diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.mm b/WebCore/platform/graphics/mac/WebTiledLayer.mm
new file mode 100644
index 0000000..1dd00ba
--- /dev/null
+++ b/WebCore/platform/graphics/mac/WebTiledLayer.mm
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#import "WebTiledLayer.h"
+
+#import "GraphicsContext.h"
+#import "GraphicsLayer.h"
+#import <wtf/UnusedParam.h>
+
+using namespace WebCore;
+
+@implementation WebTiledLayer
+
+// Set a zero duration for the fade in of tiles
++ (CFTimeInterval)fadeDuration
+{
+ return 0;
+}
+
+// Make sure that tiles are drawn on the main thread
++ (BOOL)shouldDrawOnMainThread
+{
+ return YES;
+}
+
+// Disable default animations
+- (id<CAAction>)actionForKey:(NSString *)key
+{
+ UNUSED_PARAM(key);
+ return nil;
+}
+
+// Implement this so presentationLayer can get our custom attributes
+- (id)initWithLayer:(id)layer
+{
+ if ((self = [super initWithLayer:layer]))
+ m_layerOwner = [(WebLayer*)layer layerOwner];
+
+ return self;
+}
+
+- (void)setNeedsDisplay
+{
+ if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent())
+ [super setNeedsDisplay];
+}
+
+- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
+{
+ if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) {
+ [super setNeedsDisplayInRect:dirtyRect];
+
+#ifndef NDEBUG
+ if (m_layerOwner->showRepaintCounter()) {
+ CGRect bounds = [self bounds];
+ [super setNeedsDisplayInRect:CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25)];
+ }
+#endif
+ }
+}
+
+- (void)drawInContext:(CGContextRef)ctx
+{
+ [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:ctx];
+}
+
+@end // implementation WebTiledLayer
+
+#pragma mark -
+
+@implementation WebTiledLayer(LayerMacAdditions)
+
+- (void)setLayerOwner:(GraphicsLayer*)aLayer
+{
+ m_layerOwner = aLayer;
+}
+
+- (GraphicsLayer*)layerOwner
+{
+ return m_layerOwner;
+}
+
+@end
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/win/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
index 1951320..16c3c00 100644
--- a/WebCore/platform/graphics/win/OpenTypeUtilities.cpp
+++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp
@@ -49,9 +49,9 @@ struct EOTPrefix {
unsigned fontDataSize;
unsigned version;
unsigned flags;
- UInt8 fontPANOSE[10];
- UInt8 charset;
- UInt8 italic;
+ uint8_t fontPANOSE[10];
+ uint8_t charset;
+ uint8_t italic;
unsigned weight;
unsigned short fsType;
unsigned short magicNumber;
@@ -69,6 +69,15 @@ struct TableDirectoryEntry {
BigEndianULong length;
};
+#if !PLATFORM(CG)
+// Fixed type is not defined on non-CG platforms. |version| in sfntHeader
+// and headTable and |fontRevision| in headTable are of Fixed, but they're
+// not actually refered to anywhere. Therefore, we just have to match
+// the size (4 bytes). For the definition of Fixed type, see
+// http://developer.apple.com/documentation/mac/Legacy/GXEnvironment/GXEnvironment-356.html#HEADING356-6.
+typedef int32_t Fixed;
+#endif
+
struct sfntHeader {
Fixed version;
BigEndianUShort numTables;
@@ -95,9 +104,9 @@ struct OS2Table {
BigEndianUShort strikeoutSize;
BigEndianUShort strikeoutPosition;
BigEndianUShort familyClass;
- UInt8 panose[10];
+ uint8_t panose[10];
BigEndianULong unicodeRange[4];
- UInt8 vendID[4];
+ uint8_t vendID[4];
BigEndianUShort fsSelection;
BigEndianUShort firstCharIndex;
BigEndianUShort lastCharIndex;
@@ -152,7 +161,7 @@ struct nameTable {
#pragma pack()
-static void appendBigEndianStringToEOTHeader(Vector<UInt8, 512>& eotHeader, const BigEndianUShort* string, unsigned short length)
+static void appendBigEndianStringToEOTHeader(Vector<uint8_t, 512>& eotHeader, const BigEndianUShort* string, unsigned short length)
{
size_t size = eotHeader.size();
eotHeader.resize(size + length + 2 * sizeof(unsigned short));
@@ -165,7 +174,7 @@ static void appendBigEndianStringToEOTHeader(Vector<UInt8, 512>& eotHeader, cons
dst[i] = 0;
}
-bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
+bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
{
overlayDst = 0;
overlaySrc = 0;
@@ -311,7 +320,7 @@ bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t&
appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength);
unsigned short padding = 0;
- eotHeader.append(reinterpret_cast<UInt8*>(&padding), sizeof(padding));
+ eotHeader.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding));
prefix->eotSize = eotHeader.size() + fontData->size();
diff --git a/WebCore/platform/graphics/win/OpenTypeUtilities.h b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
index ab35551..a67ffc7 100644
--- a/WebCore/platform/graphics/win/OpenTypeUtilities.h
+++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h
@@ -33,7 +33,7 @@ namespace WebCore {
class SharedBuffer;
-bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength);
+bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength);
HANDLE renameAndActivateFont(SharedBuffer*, const String&);
} // namespace WebCore
diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
index ea51fe8..f0dd3ea 100644
--- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
+++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
@@ -61,12 +61,14 @@ FontPlatformData::FontPlatformData(const QFont& font, bool bold)
{
}
+#if ENABLE(SVG_FONTS)
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
: m_size(size)
, m_bold(bold)
, m_oblique(oblique)
{
}
+#endif
FontPlatformData::FontPlatformData()
: m_size(0.0f)
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index deeea99..9ed5915 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -1,6 +1,7 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -24,11 +25,18 @@
#include "FontFallbackList.h"
#include "FontSelector.h"
+#include "Gradient.h"
#include "GraphicsContext.h"
-#include <QTextLayout>
-#include <QPainter>
-#include <QFontMetrics>
+#include "Pattern.h"
+#include "TransformationMatrix.h"
+
+#include <QBrush>
#include <QFontInfo>
+#include <QFontMetrics>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPen>
+#include <QTextLayout>
#include <qalgorithms.h>
#include <qdebug.h>
@@ -37,20 +45,27 @@
#if QT_VERSION >= 0x040400
namespace WebCore {
-static QString qstring(const TextRun& run)
+static const QString qstring(const TextRun& run)
+{
+ //We don't detach
+ return QString::fromRawData((const QChar *)run.characters(), run.length());
+}
+
+static const QString fixSpacing(const QString &string)
{
- QString string((QChar *)run.characters(), run.length());
- QChar *uc = string.data();
+ //Only detach if we're actually changing something
+ QString possiblyDetached = string;
for (int i = 0; i < string.length(); ++i) {
- if (Font::treatAsSpace(uc[i].unicode()))
- uc[i] = 0x20;
- else if (Font::treatAsZeroWidthSpace(uc[i].unicode()))
- uc[i] = 0x200c;
+ 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 string;
+ return possiblyDetached;
}
-
static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
{
int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
@@ -72,10 +87,32 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float
to = run.length();
QPainter *p = ctx->platformContext();
- Color color = ctx->fillColor();
- p->setPen(QColor(color));
- QString string = qstring(run);
+ if (ctx->textDrawingMode() & cTextFill) {
+ if (ctx->fillGradient()) {
+ QBrush brush(*ctx->fillGradient()->platformGradient());
+ brush.setTransform(ctx->fillGradient()->gradientSpaceTransform());
+ p->setPen(QPen(brush, 0));
+ } else if (ctx->fillPattern()) {
+ TransformationMatrix affine;
+ p->setPen(QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0));
+ } else
+ p->setPen(QColor(ctx->fillColor()));
+ }
+
+ if (ctx->textDrawingMode() & cTextStroke) {
+ if (ctx->strokeGradient()) {
+ QBrush brush(*ctx->strokeGradient()->platformGradient());
+ brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform());
+ p->setPen(QPen(brush, ctx->strokeThickness()));
+ } else if (ctx->strokePattern()) {
+ TransformationMatrix affine;
+ p->setPen(QPen(QBrush(ctx->strokePattern()->createPlatformPattern(affine)), ctx->strokeThickness()));
+ } else
+ p->setPen(QPen(QColor(ctx->strokeColor()), ctx->strokeThickness()));
+ }
+
+ const QString string = fixSpacing(qstring(run));
// text shadow
IntSize shadowSize;
@@ -137,14 +174,20 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float
p->drawText(pt, string, flags, run.padding());
p->restore();
}
- p->drawText(pt, string, flags, run.padding());
+ if (ctx->textDrawingMode() & cTextStroke) {
+ QPainterPath path;
+ path.addText(pt, font(), string);
+ p->strokePath(path, p->pen());
+ }
+ if (ctx->textDrawingMode() & cTextFill)
+ p->drawText(pt, string, flags, run.padding());
}
float Font::floatWidthForComplexText(const TextRun& run) const
{
if (!run.length())
return 0;
- QString string = qstring(run);
+ const QString string = fixSpacing(qstring(run));
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
int w = int(line.naturalTextWidth());
@@ -157,7 +200,7 @@ float Font::floatWidthForComplexText(const TextRun& run) const
int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const
{
- QString string = qstring(run);
+ const QString string = fixSpacing(qstring(run));
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
return line.xToCursor(position);
@@ -165,7 +208,7 @@ 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
{
- QString string = qstring(run);
+ const QString string = fixSpacing(qstring(run));
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp
index a0edf8d..1e71f58 100644
--- a/WebCore/platform/graphics/qt/GradientQt.cpp
+++ b/WebCore/platform/graphics/qt/GradientQt.cpp
@@ -28,9 +28,10 @@
#include "Gradient.h"
#include "CSSParser.h"
-#include "NotImplemented.h"
+#include "GraphicsContext.h"
#include <QGradient>
+#include <QPainter>
namespace WebCore {
@@ -66,12 +67,24 @@ QGradient* Gradient::platformGradient()
++stopIterator;
}
+ switch(m_spreadMethod) {
+ case SpreadMethodPad:
+ m_gradient->setSpread(QGradient::PadSpread);
+ break;
+ case SpreadMethodReflect:
+ m_gradient->setSpread(QGradient::ReflectSpread);
+ break;
+ case SpreadMethodRepeat:
+ m_gradient->setSpread(QGradient::RepeatSpread);
+ break;
+ }
+
return m_gradient;
}
void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
{
- notImplemented();
+ context->platformContext()->fillRect(rect, *platformGradient());
}
} //namespace
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 2e7cdcb..ccf4b06 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -51,6 +51,7 @@
#include "Pen.h"
#include "NotImplemented.h"
+#include <QBrush>
#include <QDebug>
#include <QGradient>
#include <QPainter>
@@ -152,22 +153,6 @@ static Qt::PenStyle toQPenStyle(StrokeStyle style)
return Qt::NoPen;
}
-static inline QGradient applySpreadMethod(QGradient gradient, GradientSpreadMethod spreadMethod)
-{
- switch (spreadMethod) {
- case SpreadMethodPad:
- gradient.setSpread(QGradient::PadSpread);
- break;
- case SpreadMethodReflect:
- gradient.setSpread(QGradient::ReflectSpread);
- break;
- case SpreadMethodRepeat:
- gradient.setSpread(QGradient::RepeatSpread);
- break;
- }
- return gradient;
-}
-
struct TransparencyLayer
{
TransparencyLayer(const QPainter* p, const QRect &rect)
@@ -282,7 +267,11 @@ PlatformGraphicsContext* GraphicsContext::platformContext() const
TransformationMatrix GraphicsContext::getCTM() const
{
- return platformContext()->combinedMatrix();
+ QTransform matrix(platformContext()->combinedTransform());
+ return TransformationMatrix(matrix.m11(), matrix.m12(), 0, matrix.m13(),
+ matrix.m21(), matrix.m22(), 0, matrix.m23(),
+ 0, 0, 1, 0,
+ matrix.m31(), matrix.m32(), 0, matrix.m33());
}
void GraphicsContext::savePlatformState()
@@ -295,7 +284,7 @@ void GraphicsContext::restorePlatformState()
m_data->p()->restore();
if (!m_data->currentPath.isEmpty() && m_common->state.pathTransform.isInvertible()) {
- QMatrix matrix = m_common->state.pathTransform;
+ QTransform matrix = m_common->state.pathTransform;
m_data->currentPath = m_data->currentPath * matrix;
}
}
@@ -458,13 +447,21 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
if (paintingDisabled())
return;
+ StrokeStyle style = strokeStyle();
+ Color color = strokeColor();
+ if (style == NoStroke || !color.alpha())
+ return;
+
+ float width = strokeThickness();
+
FloatPoint p1 = point1;
FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
QPainter *p = m_data->p();
const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
- adjustLineToPixelBoundaries(p1, p2, strokeThickness(), strokeStyle());
+ adjustLineToPixelBoundaries(p1, p2, width, style);
IntSize shadowSize;
int shadowBlur;
@@ -477,8 +474,76 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
p->restore();
}
+ int patWidth = 0;
+ switch (style) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = (int)width;
+ break;
+ case DashedStroke:
+ patWidth = 3 * (int)width;
+ break;
+ }
+
+ if (patWidth) {
+ p->save();
+
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+ if (isVerticalLine) {
+ p->fillRect(FloatRect(p1.x() - width / 2, p1.y() - width, width, width), QColor(color));
+ p->fillRect(FloatRect(p2.x() - width / 2, p2.y(), width, width), QColor(color));
+ } else {
+ p->fillRect(FloatRect(p1.x() - width, p1.y() - width / 2, width, width), QColor(color));
+ p->fillRect(FloatRect(p2.x(), p2.y() - width / 2, width, width), QColor(color));
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width;
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0f;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0f;
+ else {
+ bool evenNumberOfSegments = numSegments % 2 == 0;
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2;
+ } else
+ patternOffset = patWidth / 2;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder)/2;
+ }
+ }
+
+ QVector<qreal> dashes;
+ dashes << qreal(patWidth) / width << qreal(patWidth) / width;
+
+ QPen pen = p->pen();
+ pen.setWidthF(width);
+ pen.setCapStyle(Qt::FlatCap);
+ pen.setDashPattern(dashes);
+ pen.setDashOffset(patternOffset / width);
+ p->setPen(pen);
+ }
+
p->drawLine(p1, p2);
+ if (patWidth)
+ p->restore();
+
p->setRenderHint(QPainter::Antialiasing, antiAlias);
}
@@ -553,9 +618,9 @@ void GraphicsContext::fillPath()
break;
}
case GradientColorSpace:
- QGradient* gradient = m_common->state.fillGradient->platformGradient();
- *gradient = applySpreadMethod(*gradient, spreadMethod());
- p->fillPath(path, QBrush(*gradient));
+ QBrush brush(*m_common->state.fillGradient->platformGradient());
+ brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
+ p->fillPath(path, brush);
break;
}
m_data->currentPath = QPainterPath();
@@ -583,9 +648,9 @@ void GraphicsContext::strokePath()
break;
}
case GradientColorSpace: {
- QGradient* gradient = m_common->state.strokeGradient->platformGradient();
- *gradient = applySpreadMethod(*gradient, spreadMethod());
- pen.setBrush(QBrush(*gradient));
+ QBrush brush(*m_common->state.strokeGradient->platformGradient());
+ brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform());
+ pen.setBrush(brush);
p->setPen(pen);
p->strokePath(path, pen);
break;
@@ -612,7 +677,9 @@ void GraphicsContext::fillRect(const FloatRect& rect)
break;
}
case GradientColorSpace:
- p->fillRect(rect, QBrush(*(m_common->state.fillGradient.get()->platformGradient())));
+ QBrush brush(*m_common->state.fillGradient->platformGradient());
+ brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
+ p->fillRect(rect, brush);
break;
}
m_data->currentPath = QPainterPath();
@@ -663,10 +730,7 @@ void GraphicsContext::clip(const FloatRect& rect)
if (paintingDisabled())
return;
- QPainter *p = m_data->p();
- if (p->clipRegion().isEmpty())
- p->setClipRect(rect);
- else p->setClipRect(rect, Qt::IntersectClip);
+ m_data->p()->setClipRect(rect, Qt::IntersectClip);
}
void GraphicsContext::clipPath(WindRule clipRule)
@@ -818,7 +882,7 @@ void GraphicsContext::clearRect(const FloatRect& rect)
QPainter::CompositionMode currentCompositionMode = p->compositionMode();
if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
p->setCompositionMode(QPainter::CompositionMode_Source);
- p->eraseRect(rect);
+ p->fillRect(rect, Qt::transparent);
if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
p->setCompositionMode(currentCompositionMode);
}
@@ -939,7 +1003,7 @@ void GraphicsContext::translate(float x, float y)
m_data->p()->translate(x, y);
if (!m_data->currentPath.isEmpty()) {
- QMatrix matrix;
+ QTransform matrix;
m_data->currentPath = m_data->currentPath * matrix.translate(-x, -y);
m_common->state.pathTransform.translate(x, y);
}
@@ -961,7 +1025,7 @@ void GraphicsContext::rotate(float radians)
m_data->p()->rotate(180/M_PI*radians);
if (!m_data->currentPath.isEmpty()) {
- QMatrix matrix;
+ QTransform matrix;
m_data->currentPath = m_data->currentPath * matrix.rotate(-180/M_PI*radians);
m_common->state.pathTransform.rotate(radians);
}
@@ -975,9 +1039,9 @@ void GraphicsContext::scale(const FloatSize& s)
m_data->p()->scale(s.width(), s.height());
if (!m_data->currentPath.isEmpty()) {
- QMatrix matrix;
+ QTransform matrix;
m_data->currentPath = m_data->currentPath * matrix.scale(1 / s.width(), 1 / s.height());
- m_common->state.pathTransform.scale(s.width(), s.height());
+ m_common->state.pathTransform.scaleNonUniform(s.width(), s.height());
}
}
@@ -1041,12 +1105,12 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform)
if (paintingDisabled())
return;
- m_data->p()->setMatrix(transform, true);
+ m_data->p()->setWorldTransform(transform, true);
// Transformations to the context shouldn't transform the currentPath.
// We have to undo every change made to the context from the currentPath to avoid wrong drawings.
if (!m_data->currentPath.isEmpty() && transform.isInvertible()) {
- QMatrix matrix = transform.inverse();
+ QTransform matrix = transform.inverse();
m_data->currentPath = m_data->currentPath * matrix;
m_common->state.pathTransform.multiply(transform);
}
diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
index d4ab59f..d748305 100644
--- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2008 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,10 +32,11 @@
#include "GraphicsContext.h"
#include "ImageData.h"
#include "MIMETypeRegistry.h"
-#include "NotImplemented.h"
#include "StillImageQt.h"
#include <QBuffer>
+#include <QColor>
+#include <QImage>
#include <QImageWriter>
#include <QPainter>
#include <QPixmap>
@@ -79,15 +81,108 @@ Image* ImageBuffer::image() const
return m_image.get();
}
-PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
{
- notImplemented();
- return 0;
+ PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
+ unsigned char* data = result->data()->data()->data();
+
+ if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
+ memset(data, 0, result->data()->length());
+
+ int originx = rect.x();
+ int destx = 0;
+ if (originx < 0) {
+ destx = -originx;
+ originx = 0;
+ }
+ int endx = rect.x() + rect.width();
+ if (endx > m_size.width())
+ endx = m_size.width();
+ int numColumns = endx - originx;
+
+ int originy = rect.y();
+ int desty = 0;
+ if (originy < 0) {
+ desty = -originy;
+ originy = 0;
+ }
+ int endy = rect.y() + rect.height();
+ if (endy > m_size.height())
+ endy = m_size.height();
+ int numRows = endy - originy;
+
+ QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ ASSERT(!image.isNull());
+
+ unsigned destBytesPerRow = 4 * rect.width();
+ unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ QRgb value = image.pixel(x + originx, y + originy);
+ int basex = x * 4;
+
+ destRows[basex] = qRed(value);
+ destRows[basex + 1] = qGreen(value);
+ destRows[basex + 2] = qBlue(value);
+ destRows[basex + 3] = qAlpha(value);
+ }
+ destRows += destBytesPerRow;
+ }
+
+ return result;
}
-void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&)
+void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
{
- notImplemented();
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originx = sourceRect.x();
+ int destx = destPoint.x() + sourceRect.x();
+ ASSERT(destx >= 0);
+ ASSERT(destx < m_size.width());
+ ASSERT(originx >= 0);
+ ASSERT(originx <= sourceRect.right());
+
+ int endx = destPoint.x() + sourceRect.right();
+ ASSERT(endx <= m_size.width());
+
+ int numColumns = endx - destx;
+
+ int originy = sourceRect.y();
+ int desty = destPoint.y() + sourceRect.y();
+ ASSERT(desty >= 0);
+ ASSERT(desty < m_size.height());
+ ASSERT(originy >= 0);
+ ASSERT(originy <= sourceRect.bottom());
+
+ int endy = destPoint.y() + sourceRect.bottom();
+ ASSERT(endy <= m_size.height());
+ int numRows = endy - desty;
+
+ unsigned srcBytesPerRow = 4 * source->width();
+
+ bool isPainting = m_data.m_painter->isActive();
+ if (isPainting)
+ m_data.m_painter->end();
+
+ QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+
+ unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ quint32* scanLine = reinterpret_cast<quint32*>(image.scanLine(y + desty));
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ scanLine[x + destx] = reinterpret_cast<quint32*>(srcRows + basex)[0];
+ }
+
+ srcRows += srcBytesPerRow;
+ }
+
+ m_data.m_pixmap = QPixmap::fromImage(image);
+
+ if (isPainting)
+ m_data.m_painter->begin(&m_data.m_pixmap);
}
// We get a mimeType here but QImageWriter does not support mimetypes but
diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp
index 99062f9..3bc67ae 100644
--- a/WebCore/platform/graphics/qt/ImageQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -2,6 +2,7 @@
* Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
* Copyright (C) 2006 Zack Rusin <zack@kde.org>
* Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
*
* All rights reserved.
*
@@ -96,7 +97,26 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name)
void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
{
- notImplemented();
+ QPixmap* framePixmap = nativeImageForCurrentFrame();
+ if (!framePixmap) // If it's too early we won't have an image yet.
+ return;
+
+ QPixmap pixmap = *framePixmap;
+ QRect tr = QRectF(tileRect).toRect();
+ if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) {
+ pixmap = pixmap.copy(tr);
+ }
+
+ QBrush b(pixmap);
+ b.setTransform(patternTransform);
+ ctxt->save();
+ ctxt->setCompositeOperation(op);
+ QPainter* p = ctxt->platformContext();
+ if (!pixmap.hasAlpha() && p->compositionMode() == QPainter::CompositionMode_SourceOver)
+ p->setCompositionMode(QPainter::CompositionMode_Source);
+ p->setBrushOrigin(phase);
+ p->fillRect(destRect, b);
+ ctxt->restore();
}
void BitmapImage::initPlatformData()
@@ -131,6 +151,9 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
QPainter* painter(ctxt->platformContext());
+ if (!image->hasAlpha() && painter->compositionMode() == QPainter::CompositionMode_SourceOver)
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+
// Test using example site at
// http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
painter->drawPixmap(dst, *image, src);
@@ -138,33 +161,20 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
ctxt->restore();
}
-void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
- const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
+void BitmapImage::checkForSolidColor()
{
- QPixmap* framePixmap = nativeImageForCurrentFrame();
- if (!framePixmap) // If it's too early we won't have an image yet.
- return;
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
- QPixmap pixmap = *framePixmap;
- QRect tr = QRectF(tileRect).toRect();
- if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) {
- pixmap = pixmap.copy(tr);
- }
+ if (frameCount() > 1)
+ return;
- QBrush b(pixmap);
- b.setMatrix(patternTransform);
- ctxt->save();
- ctxt->setCompositeOperation(op);
- QPainter* p = ctxt->platformContext();
- p->setBrushOrigin(phase);
- p->fillRect(destRect, b);
- ctxt->restore();
-}
+ QPixmap* framePixmap = frameAtIndex(0);
+ if (!framePixmap || framePixmap->width() != 1 || framePixmap->height() != 1)
+ return;
-void BitmapImage::checkForSolidColor()
-{
- // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1.
- m_isSolidColor = false;
+ m_isSolidColor = true;
+ m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0));
}
}
diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
index d62acc3..84de443 100644
--- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
@@ -163,7 +163,7 @@ void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer*
delete m_decoder;
m_decoder = 0;
if (data)
- setData(data, allDataReceived);
+ setData(data, allDataReceived);
}
}
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
index b1a48fb..c80d73b 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -76,7 +77,7 @@ namespace WebCore {
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_networkState(MediaPlayer::Empty)
- , m_readyState(MediaPlayer::DataUnavailable)
+ , m_readyState(MediaPlayer::HaveNothing)
, m_mediaObject(new MediaObject())
, m_videoWidget(new VideoWidget(0))
, m_audioOutput(new AudioOutput())
@@ -110,6 +111,18 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
}
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+
MediaPlayerPrivate::~MediaPlayerPrivate()
{
LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting videowidget");
@@ -131,6 +144,13 @@ void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&)
notImplemented();
}
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // FIXME: do the real thing
+ notImplemented();
+ return MediaPlayer::IsNotSupported;
+}
+
bool MediaPlayerPrivate::hasVideo() const
{
bool hasVideo = m_mediaObject->hasVideo();
@@ -138,7 +158,7 @@ bool MediaPlayerPrivate::hasVideo() const
return hasVideo;
}
-void MediaPlayerPrivate::load(String url)
+void MediaPlayerPrivate::load(const String& url)
{
LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data());
@@ -149,8 +169,8 @@ void MediaPlayerPrivate::load(String url)
}
// And we don't have any data yet
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
@@ -205,7 +225,7 @@ bool MediaPlayerPrivate::seeking() const
float MediaPlayerPrivate::duration() const
{
- if (m_networkState < MediaPlayer::LoadedMetaData)
+ if (m_readyState < MediaPlayer::HaveMetadata)
return 0.0f;
float duration = m_mediaObject->totalTime() / 1000.0f;
@@ -309,18 +329,19 @@ void MediaPlayerPrivate::updateStates()
Phonon::State phononState = m_mediaObject->state();
if (phononState == Phonon::StoppedState) {
- if (oldNetworkState < MediaPlayer::LoadedMetaData) {
- m_networkState = MediaPlayer::LoadedMetaData;
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState < MediaPlayer::HaveMetadata) {
+ m_networkState = MediaPlayer::Loading; // FIXME: should this be MediaPlayer::Idle?
+ m_readyState = MediaPlayer::HaveMetadata;
m_mediaObject->pause();
}
} else if (phononState == Phonon::PausedState) {
m_networkState = MediaPlayer::Loaded;
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (phononState == Phonon::ErrorState) {
if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) {
- m_networkState = MediaPlayer::LoadFailed;
- m_readyState = MediaPlayer::DataUnavailable;
+ // FIXME: is it possile to differentiate between different types of errors
+ m_networkState = MediaPlayer::NetworkError;
+ m_readyState = MediaPlayer::HaveNothing;
cancelLoad();
} else {
m_mediaObject->pause();
@@ -328,7 +349,7 @@ void MediaPlayerPrivate::updateStates()
}
if (seeking())
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveNothing;
if (m_networkState != oldNetworkState) {
const QMetaObject* metaObj = this->metaObject();
@@ -357,19 +378,18 @@ void MediaPlayerPrivate::setVisible(bool visible)
m_videoWidget->setVisible(m_isVisible);
}
-void MediaPlayerPrivate::setRect(const IntRect& newRect)
+void MediaPlayerPrivate::setSize(const IntSize& newSize)
{
if (!m_videoWidget)
return;
- LOG(Media, "MediaPlayerPrivatePhonon::setRect(%d,%d %dx%d)",
- newRect.x(), newRect.y(),
- newRect.width(), newRect.height());
+ LOG(Media, "MediaPlayerPrivatePhonon::setSize(%d,%d)",
+ newSize.width(), newSize.height());
QRect currentRect = m_videoWidget->rect();
- if (newRect.width() != currentRect.width() || newRect.height() != currentRect.height())
- m_videoWidget->resize(newRect.width(), newRect.height());
+ if (newSize.width() != currentRect.width() || newSize.height() != currentRect.height())
+ m_videoWidget->resize(newSize.width(), newSize.height());
}
IntSize MediaPlayerPrivate::naturalSize() const
@@ -380,7 +400,7 @@ IntSize MediaPlayerPrivate::naturalSize() const
return IntSize();
}
- if (m_networkState < MediaPlayer::LoadedMetaData) {
+ if (m_readyState < MediaPlayer::HaveMetadata) {
LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
0, 0);
return IntSize();
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
index 1b20a84..9572d61 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -20,8 +21,7 @@
#ifndef MediaPlayerPrivatePhonon_h
#define MediaPlayerPrivatePhonon_h
-#include "MediaPlayer.h"
-#include <wtf/Noncopyable.h>
+#include "MediaPlayerPrivate.h"
#include <QObject>
#include <phononnamespace.h>
@@ -40,31 +40,33 @@ QT_END_NAMESPACE
namespace WebCore {
- class MediaPlayerPrivate : public QObject, Noncopyable {
+ class MediaPlayerPrivate : public QObject, public MediaPlayerPrivateInterface {
Q_OBJECT
public:
- MediaPlayerPrivate(MediaPlayer*);
+ static void registerMediaEngine(MediaEngineRegistrar);
~MediaPlayerPrivate();
// These enums are used for debugging
Q_ENUMS(ReadyState NetworkState PhononState)
enum ReadyState {
- DataUnavailable,
- CanShowCurrentFrame,
- CanPlay,
- CanPlayThrough
+ HaveNothing,
+ HaveMetadata,
+ HaveCurrentData,
+ HaveFutureData,
+ HaveEnoughData
};
enum NetworkState {
- Empty,
- LoadFailed,
- Loading,
- LoadedMetaData,
- LoadedFirstFrame,
- Loaded
+ Empty,
+ Idle,
+ Loading,
+ Loaded,
+ FormatError,
+ NetworkError,
+ DecodeError
};
enum PhononState {
@@ -79,7 +81,7 @@ namespace WebCore {
IntSize naturalSize() const;
bool hasVideo() const;
- void load(String url);
+ void load(const String &url);
void cancelLoad();
void play();
@@ -109,11 +111,9 @@ namespace WebCore {
unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect&);
+ void setSize(const IntSize&);
void paint(GraphicsContext*, const IntRect&);
- static void getSupportedTypes(HashSet<String>&);
- static bool isAvailable() { return true; }
protected:
bool eventFilter(QObject*, QEvent*);
@@ -130,6 +130,13 @@ namespace WebCore {
void totalTimeChanged(qint64);
private:
+ MediaPlayerPrivate(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable() { return true; }
+
void updateStates();
MediaPlayer* m_player;
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
index bd0192c..a8a3ea2 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -1,6 +1,7 @@
/*
- * Copyright (C) 2006 Zack Rusin <zack@kde.org>
- * 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * 2006 Rob Buis <buis@kde.org>
+ * 2009 Dirk Schulze <krit@webkit.org>
*
* All rights reserved.
*
@@ -36,7 +37,7 @@
#include "PlatformString.h"
#include "StrokeStyleApplier.h"
#include <QPainterPath>
-#include <QMatrix>
+#include <QTransform>
#include <QString>
#define _USE_MATH_DEFINES
@@ -108,7 +109,7 @@ bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point)
void Path::translate(const FloatSize& size)
{
- QMatrix matrix;
+ QTransform matrix;
matrix.translate(size.width(), size.height());
*m_path = (*m_path) * matrix;
}
@@ -161,9 +162,72 @@ void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const
void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
{
- //FIXME: busted
- qWarning("arcTo is busted");
- m_path->arcTo(p1.x(), p1.y(), p2.x(), p2.y(), radius, 90);
+ 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);
+ return;
+ }
+
+ FloatPoint p1p0((p0.x() - p1.x()),(p0.y() - p1.y()));
+ FloatPoint p1p2((p2.x() - p1.x()),(p2.y() - p1.y()));
+ float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
+ float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+
+ 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);
+ return;
+ }
+ if (cos_phi == 1) {
+ // add infinite far away point
+ 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);
+ return;
+ }
+
+ float tangent = radius / tan(acos(cos_phi) / 2);
+ float factor_p1p0 = tangent / p1p0_length;
+ FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
+
+ FloatPoint orth_p1p0(p1p0.y(), -p1p0.x());
+ float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
+ float factor_ra = radius / orth_p1p0_length;
+
+ // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
+ double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ if (cos_alpha < 0.f)
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+
+ FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
+
+ // calculate angles for addArc
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+ float sa = acos(orth_p1p0.x() / orth_p1p0_length);
+ if (orth_p1p0.y() < 0.f)
+ sa = 2 * piDouble - sa;
+
+ // anticlockwise logic
+ bool anticlockwise = false;
+
+ float factor_p1p2 = tangent / p1p2_length;
+ FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
+ FloatPoint orth_p1p2((t_p1p2.x() - p.x()),(t_p1p2.y() - p.y()));
+ float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
+ float ea = acos(orth_p1p2.x() / orth_p1p2_length);
+ if (orth_p1p2.y() < 0)
+ ea = 2 * piDouble - ea;
+ if ((sa > ea) && ((sa - ea) < piDouble))
+ anticlockwise = true;
+ if ((sa < ea) && ((ea - sa) > piDouble))
+ anticlockwise = true;
+
+ m_path->lineTo(t_p1p0);
+
+ addArc(p, radius, sa, ea, anticlockwise);
}
void Path::closeSubpath()
@@ -316,7 +380,7 @@ void Path::apply(void* info, PathApplierFunction function) const
void Path::transform(const TransformationMatrix& transform)
{
if (m_path) {
- QMatrix mat = transform;
+ QTransform mat = transform;
QPainterPath temp = mat.map(*m_path);
delete m_path;
m_path = new QPainterPath(temp);
diff --git a/WebCore/platform/graphics/qt/PatternQt.cpp b/WebCore/platform/graphics/qt/PatternQt.cpp
index 5b76841..b261613 100644
--- a/WebCore/platform/graphics/qt/PatternQt.cpp
+++ b/WebCore/platform/graphics/qt/PatternQt.cpp
@@ -31,14 +31,15 @@
namespace WebCore {
-QBrush Pattern::createPlatformPattern(const TransformationMatrix& transform) const
+QBrush Pattern::createPlatformPattern(const TransformationMatrix&) const
{
QPixmap* pixmap = tileImage()->nativeImageForCurrentFrame();
if (!pixmap)
return QBrush();
+ // Qt merges patter space and user space itself
QBrush brush(*pixmap);
- brush.setMatrix(transform);
+ brush.setTransform(m_patternSpaceTransformation);
return brush;
}
diff --git a/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
index 47abd17..15f0cc5 100644
--- a/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
+++ b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
@@ -31,170 +31,9 @@
namespace WebCore {
-TransformationMatrix::TransformationMatrix()
- : m_transform()
-{
-}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
- : m_transform(a, b, c, d, tx, ty)
-{
-}
-
-TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
- : m_transform(matrix)
-{
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
-{
- m_transform.setMatrix(a, b, c, d, tx, ty);
-}
-
-void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
-{
- qreal tx2, ty2;
- m_transform.map(qreal(x), qreal(y), &tx2, &ty2);
- *x2 = tx2;
- *y2 = ty2;
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect& rect) const
-{
- return m_transform.mapRect(rect);
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect& rect) const
-{
- return m_transform.mapRect(rect);
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return m_transform.isIdentity();
-}
-
-double TransformationMatrix::a() const
-{
- return m_transform.m11();
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.setMatrix(a, b(), c(), d(), e(), f());
-}
-
-double TransformationMatrix::b() const
-{
- return m_transform.m12();
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.setMatrix(a(), b, c(), d(), e(), f());
-}
-
-double TransformationMatrix::c() const
-{
- return m_transform.m21();
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.setMatrix(a(), b(), c, d(), e(), f());
-}
-
-double TransformationMatrix::d() const
-{
- return m_transform.m22();
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.setMatrix(a(), b(), c(), d, e(), f());
-}
-
-double TransformationMatrix::e() const
-{
- return m_transform.dx();
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.setMatrix(a(), b(), c(), d(), e, f());
-}
-
-double TransformationMatrix::f() const
-{
- return m_transform.dy();
-}
-
-void TransformationMatrix::setF(double f)
-{
- m_transform.setMatrix(a(), b(), c(), d(), e(), f);
-}
-
-void TransformationMatrix::reset()
-{
- m_transform.reset();
-}
-
-TransformationMatrix& TransformationMatrix::scale(double sx, double sy)
-{
- m_transform.scale(sx, sy);
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::rotate(double d)
-{
- m_transform.rotate(d);
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
-{
- m_transform.translate(tx, ty);
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::shear(double sx, double sy)
-{
- m_transform.shear(sx, sy);
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return m_transform.det();
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- if(!isInvertible())
- return TransformationMatrix();
-
- return m_transform.inverted();
-}
-
-TransformationMatrix::operator QMatrix() const
-{
- return m_transform;
-}
-
-bool TransformationMatrix::operator==(const TransformationMatrix& other) const
-{
- return m_transform == other.m_transform;
-}
-
-TransformationMatrix& TransformationMatrix::operator*=(const TransformationMatrix& other)
-{
- m_transform *= other.m_transform;
- return *this;
-}
-
-TransformationMatrix TransformationMatrix::operator*(const TransformationMatrix& other)
-{
- return m_transform * other.m_transform;
+TransformationMatrix::operator QTransform() const
+{
+ return QTransform(m11(), m12(), m14(), m21(), m22(), m24(), m41(), m42(), m44());
}
}
diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp
index eff7c66..2d2000c 100644
--- a/WebCore/platform/graphics/skia/GradientSkia.cpp
+++ b/WebCore/platform/graphics/skia/GradientSkia.cpp
@@ -136,6 +136,19 @@ SkShader* Gradient::platformGradient()
fillStops(m_stops.data(), m_stops.size(), pos, colors);
+ SkShader::TileMode tile = SkShader::kClamp_TileMode;
+ switch (m_spreadMethod) {
+ case SpreadMethodReflect:
+ tile = SkShader::kMirror_TileMode;
+ break;
+ case SpreadMethodRepeat:
+ tile = SkShader::kRepeat_TileMode;
+ break;
+ case SpreadMethodPad:
+ tile = SkShader::kClamp_TileMode;
+ break;
+ }
+
if (m_radial) {
// FIXME: CSS radial Gradients allow an offset focal point (the
// "start circle"), but skia doesn't seem to support that, so this just
@@ -145,13 +158,16 @@ SkShader* Gradient::platformGradient()
// description of the expected behavior.
m_gradient = SkGradientShader::CreateRadial(m_p1,
WebCoreFloatToSkScalar(m_r1), colors, pos,
- static_cast<int>(countUsed), SkShader::kClamp_TileMode);
+ static_cast<int>(countUsed), tile);
} else {
SkPoint pts[2] = { m_p0, m_p1 };
m_gradient = SkGradientShader::CreateLinear(pts, colors, pos,
- static_cast<int>(countUsed), SkShader::kClamp_TileMode);
+ static_cast<int>(countUsed), tile);
}
+ SkMatrix matrix = m_gradientSpaceTransformation;
+ m_gradient->setLocalMatrix(matrix);
+
return m_gradient;
}
diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
index e6c7783..376fa4b 100644
--- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
@@ -36,6 +36,7 @@
#include "Color.h"
#include "FloatRect.h"
#include "Gradient.h"
+#include "ImageBuffer.h"
#include "IntRect.h"
#include "NativeImageSkia.h"
#include "NotImplemented.h"
@@ -274,11 +275,6 @@ void GraphicsContext::endTransparencyLayer()
{
if (paintingDisabled())
return;
-
-#if PLATFORM(WIN_OS)
- platformContext()->canvas()->getTopPlatformDevice().
- fixupAlphaBeforeCompositing();
-#endif
platformContext()->canvas()->restore();
}
@@ -406,8 +402,7 @@ void GraphicsContext::clipPath(WindRule clipRule)
if (paintingDisabled())
return;
- const SkPath* oldPath = platformContext()->currentPath();
- SkPath path(*oldPath);
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
platformContext()->canvas()->clipPath(path);
}
@@ -418,8 +413,9 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect,
if (paintingDisabled())
return;
- // FIXME: This is needed for image masking and complex text fills.
- notImplemented();
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ platformContext()->beginLayerClippedToImage(rect, imageBuffer);
+#endif
}
void GraphicsContext::concatCTM(const TransformationMatrix& xform)
@@ -645,6 +641,9 @@ void GraphicsContext::drawLineForText(const IntPoint& pt,
if (paintingDisabled())
return;
+ if (width <= 0)
+ return;
+
int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
SkRect r;
r.fLeft = SkIntToScalar(pt.x());
@@ -653,7 +652,9 @@ void GraphicsContext::drawLineForText(const IntPoint& pt,
r.fBottom = r.fTop + SkIntToScalar(thickness);
SkPaint paint;
- paint.setColor(strokeColor().rgb());
+ platformContext()->setupPaintForFilling(&paint);
+ // Text lines are drawn using the stroke color.
+ paint.setColor(platformContext()->effectiveStrokeColor());
platformContext()->canvas()->drawRect(r, paint);
}
@@ -664,9 +665,10 @@ void GraphicsContext::drawRect(const IntRect& rect)
return;
SkRect r = rect;
- if (!isRectSkiaSafe(getCTM(), r))
+ if (!isRectSkiaSafe(getCTM(), r)) {
// See the fillRect below.
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ }
platformContext()->drawRect(r);
}
@@ -676,7 +678,7 @@ void GraphicsContext::fillPath()
if (paintingDisabled())
return;
- const SkPath& path = *platformContext()->currentPath();
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
if (!isPathSkiaSafe(getCTM(), path))
return;
@@ -686,7 +688,7 @@ void GraphicsContext::fillPath()
if (colorSpace == SolidColorSpace && !fillColor().alpha())
return;
- platformContext()->setFillRule(state.fillRule == RULE_EVENODD ?
+ path.setFillType(state.fillRule == RULE_EVENODD ?
SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
SkPaint paint;
@@ -708,9 +710,10 @@ void GraphicsContext::fillRect(const FloatRect& rect)
return;
SkRect r = rect;
- if (!isRectSkiaSafe(getCTM(), r))
+ if (!isRectSkiaSafe(getCTM(), r)) {
// See the other version of fillRect below.
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ }
const GraphicsContextState& state = m_common->state;
ColorSpace colorSpace = state.fillColorSpace;
@@ -775,6 +778,17 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect,
// See fillRect().
ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ if (topLeft.width() + topRight.width() > rect.width()
+ || bottomLeft.width() + bottomRight.width() > rect.width()
+ || topLeft.height() + bottomLeft.height() > rect.height()
+ || topRight.height() + bottomRight.height() > rect.height()) {
+ // Not all the radii fit, return a rect. This matches the behavior of
+ // Path::createRoundedRectangle. Without this we attempt to draw a round
+ // shadow for a square box.
+ fillRect(rect, color);
+ return;
+ }
+
SkPath path;
addCornerArc(&path, r, topRight, 270);
addCornerArc(&path, r, bottomRight, 0);
@@ -784,12 +798,17 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect,
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
platformContext()->canvas()->drawPath(path, paint);
- return fillRect(rect, color);
}
TransformationMatrix GraphicsContext::getCTM() const
{
- return platformContext()->canvas()->getTotalMatrix();
+ const SkMatrix& m = platformContext()->canvas()->getTotalMatrix();
+ return TransformationMatrix(SkScalarToDouble(m.getScaleX()), // a
+ SkScalarToDouble(m.getSkewY()), // b
+ SkScalarToDouble(m.getSkewX()), // c
+ SkScalarToDouble(m.getScaleY()), // d
+ SkScalarToDouble(m.getTranslateX()), // e
+ SkScalarToDouble(m.getTranslateY())); // f
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
@@ -1050,7 +1069,7 @@ void GraphicsContext::strokePath()
if (paintingDisabled())
return;
- const SkPath& path = *platformContext()->currentPath();
+ SkPath path = platformContext()->currentPathInLocalCoordinates();
if (!isPathSkiaSafe(getCTM(), path))
return;
diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
index fdfcb85..5e90491 100644
--- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
@@ -31,12 +31,14 @@
#include "config.h"
#include "ImageBuffer.h"
+#include "Base64.h"
#include "BitmapImage.h"
#include "BitmapImageSingleFrameSkia.h"
#include "GraphicsContext.h"
#include "ImageData.h"
#include "NotImplemented.h"
#include "PlatformContextSkia.h"
+#include "PNGImageEncoder.h"
#include "SkiaUtils.h"
using namespace std;
@@ -63,6 +65,9 @@ ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
m_data.m_platformContext.setCanvas(&m_data.m_canvas);
m_context.set(new GraphicsContext(&m_data.m_platformContext));
+#if PLATFORM(WIN_OS)
+ m_context->platformContext()->setDrawingToImageBuffer(true);
+#endif
// Make the background transparent. It would be nice if this wasn't
// required, but the canvas is currently filled with the magic transparency
@@ -101,7 +106,7 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
ASSERT(context());
RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
- unsigned char* data = result->data()->data();
+ unsigned char* data = result->data()->data()->data();
if (rect.x() < 0 || rect.y() < 0 ||
(rect.x() + rect.width()) > m_size.width() ||
@@ -188,7 +193,7 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect,
unsigned srcBytesPerRow = 4 * source->width();
- const unsigned char* srcRow = source->data()->data() + originY * srcBytesPerRow + originX * 4;
+ const unsigned char* srcRow = source->data()->data()->data() + originY * srcBytesPerRow + originX * 4;
for (int y = 0; y < numRows; ++y) {
uint32_t* destRow = bitmap.getAddr32(destX, destY + y);
@@ -203,8 +208,18 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect,
String ImageBuffer::toDataURL(const String&) const
{
- notImplemented();
- return String();
+ // Encode the image into a vector.
+ Vector<unsigned char> pngEncodedData;
+ PNGImageEncoder::encode(*context()->platformContext()->bitmap(), &pngEncodedData);
+
+ // Convert it into base64.
+ Vector<char> base64EncodedData;
+ base64Encode(*reinterpret_cast<Vector<char>*>(&pngEncodedData), base64EncodedData);
+ // Append with a \0 so that it's a valid string.
+ base64EncodedData.append('\0');
+
+ // And the resulting string.
+ return String::format("data:image/png;base64,%s", base64EncodedData.data());
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp
index 1123fe9..d7f2830 100644
--- a/WebCore/platform/graphics/skia/ImageSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageSkia.cpp
@@ -225,6 +225,7 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag
{
SkPaint paint;
paint.setPorterDuffXfermode(compOp);
+ paint.setFilterBitmap(true);
skia::PlatformCanvas* canvas = platformContext->canvas();
@@ -233,7 +234,6 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag
SkScalarToFloat(destRect.width()),
SkScalarToFloat(destRect.height()));
if (resampling == RESAMPLE_AWESOME) {
- paint.setFilterBitmap(false);
drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
} else {
// No resampling necessary, we can just draw the bitmap. We want to
@@ -241,7 +241,6 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag
// is something interesting going on with the matrix (like a rotation).
// Note: for serialization, we will want to subset the bitmap first so
// we don't send extra pixels.
- paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint);
}
}
@@ -401,6 +400,7 @@ void BitmapImage::invalidatePlatformData()
void BitmapImage::checkForSolidColor()
{
+ m_checkedForSolidColor = true;
}
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
@@ -427,7 +427,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
paintSkBitmap(ctxt->platformContext(),
*bm,
enclosingIntRect(normSrcRect),
- enclosingIntRect(normDstRect),
+ normDstRect,
WebCoreCompositeToSkiaComposite(compositeOp));
}
@@ -447,7 +447,7 @@ void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
paintSkBitmap(ctxt->platformContext(),
m_nativeImage,
enclosingIntRect(normSrcRect),
- enclosingIntRect(normDstRect),
+ normDstRect,
WebCoreCompositeToSkiaComposite(compositeOp));
}
diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
index f77620b..b5f7e1d 100644
--- a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
@@ -100,16 +100,16 @@ ImageSource::~ImageSource()
void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
{
- // TODO(darin): Figure out what to do with the |data| and |allDataReceived| params.
-
- if (destroyAll) {
- delete m_decoder;
- m_decoder = 0;
+ if (!destroyAll) {
+ if (m_decoder)
+ m_decoder->clearFrameBufferCache(clearBeforeFrame);
return;
}
- if (m_decoder)
- m_decoder->clearFrameBufferCache(clearBeforeFrame);
+ delete m_decoder;
+ m_decoder = 0;
+ if (data)
+ setData(data, allDataReceived);
}
bool ImageSource::initialized() const
diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp
index ca99322..2700da8 100644
--- a/WebCore/platform/graphics/skia/PathSkia.cpp
+++ b/WebCore/platform/graphics/skia/PathSkia.cpp
@@ -274,7 +274,7 @@ static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context)
SkPaint paint;
context->platformContext()->setupPaintForStroking(&paint, 0, 0);
SkPath boundingPath;
- paint.getFillPath(context->platformContext()->currentPath(), &boundingPath);
+ paint.getFillPath(context->platformContext()->currentPathInLocalCoordinates(), &boundingPath);
SkRect r;
boundingPath.computeBounds(&r, SkPath::kExact_BoundsType);
return r;
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
index 60dbbe0..6c633f2 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -31,6 +31,7 @@
#include "config.h"
#include "GraphicsContext.h"
+#include "ImageBuffer.h"
#include "NativeImageSkia.h"
#include "PlatformContextSkia.h"
#include "SkiaUtils.h"
@@ -45,10 +46,6 @@
#include <wtf/MathExtras.h>
-#if defined(__linux__)
-#include "GdkSkia.h"
-#endif
-
// State -----------------------------------------------------------------------
// Encapsulates the additional painting state information we store for each
@@ -86,6 +83,13 @@ struct PlatformContextSkia::State {
// color to produce a new output color.
SkColor applyAlpha(SkColor) const;
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ // 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.
+ WebCore::FloatRect m_clip;
+#endif
+
private:
// Not supported.
void operator=(const State&);
@@ -113,9 +117,28 @@ PlatformContextSkia::State::State()
}
PlatformContextSkia::State::State(const State& other)
+ : m_alpha(other.m_alpha)
+ , m_porterDuffMode(other.m_porterDuffMode)
+ , m_gradient(other.m_gradient)
+ , m_pattern(other.m_pattern)
+ , m_useAntialiasing(other.m_useAntialiasing)
+ , m_looper(other.m_looper)
+ , m_fillColor(other.m_fillColor)
+ , m_strokeStyle(other.m_strokeStyle)
+ , m_strokeColor(other.m_strokeColor)
+ , m_strokeThickness(other.m_strokeThickness)
+ , m_dashRatio(other.m_dashRatio)
+ , m_miterLimit(other.m_miterLimit)
+ , m_lineCap(other.m_lineCap)
+ , m_lineJoin(other.m_lineJoin)
+ , m_dash(other.m_dash)
+ , m_textDrawingMode(other.m_textDrawingMode)
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ , m_imageBufferClip(other.m_imageBufferClip)
+ , m_clip(other.m_clip)
+#endif
{
- memcpy(this, &other, sizeof(State));
-
+ // Up the ref count of these. saveRef does nothing if 'this' is NULL.
m_looper->safeRef();
m_dash->safeRef();
m_gradient->safeRef();
@@ -148,22 +171,16 @@ SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
: m_canvas(canvas)
, m_stateStack(sizeof(State))
+#if PLATFORM(WIN_OS)
+ , m_drawingToImageBuffer(false)
+#endif
{
m_stateStack.append(State());
m_state = &m_stateStack.last();
-#if defined(OS_LINUX)
- m_gdkskia = m_canvas ? gdk_skia_new(m_canvas) : 0;
-#endif
}
PlatformContextSkia::~PlatformContextSkia()
{
-#if defined(OS_LINUX)
- if (m_gdkskia) {
- g_object_unref(m_gdkskia);
- m_gdkskia = 0;
- }
-#endif
}
void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
@@ -171,17 +188,72 @@ void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
m_canvas = canvas;
}
+#if PLATFORM(WIN_OS)
+void PlatformContextSkia::setDrawingToImageBuffer(bool value)
+{
+ m_drawingToImageBuffer = value;
+}
+
+bool PlatformContextSkia::isDrawingToImageBuffer() const
+{
+ return m_drawingToImageBuffer;
+}
+#endif
+
void PlatformContextSkia::save()
{
m_stateStack.append(*m_state);
m_state = &m_stateStack.last();
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ // 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();
+#endif
+
// Save our native canvas.
canvas()->save();
}
+#if defined(__linux__) || PLATFORM(WIN_OS)
+void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rect,
+ const WebCore::ImageBuffer* imageBuffer)
+{
+ // Skia doesn't support clipping to an image, so we create a layer. The next
+ // time restore is invoked the layer and |imageBuffer| are combined to
+ // create the resulting image.
+ m_state->m_clip = rect;
+ SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
+ SkFloatToScalar(rect.right()), SkFloatToScalar(rect.bottom()) };
+
+ 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.
+ const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
+ if (!bitmap->pixelRef()) {
+ // The bitmap owns it's pixels. This happens when we've allocated the
+ // pixels in some way and assigned them directly to the bitmap (as
+ // happens when we allocate a DIB). In this case the assignment operator
+ // does not copy the pixels, rather the copied bitmap ends up
+ // referencing the same pixels. As the pixels may not live as long as we
+ // need it to, we copy the image.
+ bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config);
+ } else {
+ // If there is a pixel ref, we can safely use the assignment operator.
+ m_state->m_imageBufferClip = *bitmap;
+ }
+}
+#endif
+
void PlatformContextSkia::restore()
{
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ if (!m_state->m_imageBufferClip.empty()) {
+ applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
+ canvas()->restore();
+ }
+#endif
+
m_stateStack.removeLast();
m_state = &m_stateStack.last();
@@ -200,12 +272,21 @@ void PlatformContextSkia::drawRect(SkRect rect)
if (m_state->m_strokeStyle != WebCore::NoStroke &&
(m_state->m_strokeColor & 0xFF000000)) {
- if (fillcolorNotTransparent) {
- // This call is expensive so don't call it unnecessarily.
- paint.reset();
- }
- setupPaintForStroking(&paint, &rect, 0);
- canvas()->drawRect(rect, paint);
+ // We do a fill of four rects to simulate the stroke of a border.
+ SkColor oldFillColor = m_state->m_fillColor;
+ if (oldFillColor != m_state->m_strokeColor)
+ setFillColor(m_state->m_strokeColor);
+ setupPaintForFilling(&paint);
+ SkRect topBorder = { rect.fLeft, rect.fTop, rect.width(), 1 };
+ canvas()->drawRect(topBorder, paint);
+ SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.width(), 1 };
+ canvas()->drawRect(bottomBorder, paint);
+ SkRect leftBorder = { rect.fLeft, rect.fTop + 1, 1, rect.height() - 2 };
+ canvas()->drawRect(leftBorder, paint);
+ SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, 1, rect.height() - 2 };
+ canvas()->drawRect(rightBorder, paint);
+ if (oldFillColor != m_state->m_strokeColor)
+ setFillColor(oldFillColor);
}
}
@@ -239,10 +320,6 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
setupPaintCommon(paint);
float width = m_state->m_strokeThickness;
- // This allows dashing and dotting to work properly for hairline strokes.
- if (width == 0)
- width = 1;
-
paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
paint->setStyle(SkPaint::kStroke_Style);
paint->setStrokeWidth(SkFloatToScalar(width));
@@ -250,9 +327,6 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
paint->setStrokeJoin(m_state->m_lineJoin);
paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
- if (rect != 0 && (static_cast<int>(roundf(width)) & 1))
- rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
-
if (m_state->m_dash)
paint->setPathEffect(m_state->m_dash);
else {
@@ -267,7 +341,8 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
SkScalar dashLength;
if (length) {
// Determine about how many dashes or dots we should have.
- int numDashes = length / roundf(width);
+ float roundedWidth = roundf(width);
+ int numDashes = roundedWidth ? (length / roundedWidth) : length;
if (!(numDashes & 1))
numDashes++; // Make it odd so we end on a dash/dot.
// Use the number of dashes to determine the length of a
@@ -366,9 +441,14 @@ void PlatformContextSkia::setUseAntialiasing(bool enable)
m_state->m_useAntialiasing = enable;
}
-SkColor PlatformContextSkia::fillColor() const
+SkColor PlatformContextSkia::effectiveFillColor() const
{
- return m_state->m_fillColor;
+ return m_state->applyAlpha(m_state->m_fillColor);
+}
+
+SkColor PlatformContextSkia::effectiveStrokeColor() const
+{
+ return m_state->applyAlpha(m_state->m_strokeColor);
}
void PlatformContextSkia::beginPath()
@@ -378,7 +458,17 @@ void PlatformContextSkia::beginPath()
void PlatformContextSkia::addPath(const SkPath& path)
{
- m_path.addPath(path);
+ m_path.addPath(path, m_canvas->getTotalMatrix());
+}
+
+SkPath PlatformContextSkia::currentPathInLocalCoordinates() const
+{
+ SkPath localPath = m_path;
+ const SkMatrix& matrix = m_canvas->getTotalMatrix();
+ SkMatrix inverseMatrix;
+ matrix.invert(&inverseMatrix);
+ localPath.transform(inverseMatrix);
+ return localPath;
}
void PlatformContextSkia::setFillRule(SkPath::FillType fr)
@@ -425,3 +515,14 @@ bool PlatformContextSkia::isPrinting()
{
return m_canvas->getTopPlatformDevice().IsVectorial();
}
+
+#if defined(__linux__) || PLATFORM(WIN_OS)
+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
+ // only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping.
+ SkPaint paint;
+ paint.setPorterDuffXfermode(SkPorterDuff::kDstIn_Mode);
+ m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
+}
+#endif
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h
index 78e9a19..8850a6a 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.h
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h
@@ -43,8 +43,6 @@
#include <wtf/Vector.h>
-typedef struct _GdkDrawable GdkSkia;
-
// This class holds the platform-specific state for GraphicsContext. We put
// most of our Skia wrappers on this class. In theory, a lot of this stuff could
// be moved to GraphicsContext directly, except that some code external to this
@@ -73,9 +71,28 @@ public:
// to the constructor.
void setCanvas(skia::PlatformCanvas*);
+#if PLATFORM(WIN_OS)
+ // 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
+ // color and all text drawing needs to go to a layer so that the alpha is
+ // correctly updated.
+ void setDrawingToImageBuffer(bool);
+ bool isDrawingToImageBuffer() const;
+#endif
+
void save();
void restore();
+ // Begins a layer that is clipped to the image |imageBuffer| at the location
+ // |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)
+ void beginLayerClippedToImage(const WebCore::FloatRect&,
+ const WebCore::ImageBuffer*);
+#endif
+
// Sets up the common flags on a paint for antialiasing, effects, etc.
// This is implicitly called by setupPaintFill and setupPaintStroke, but
// you may wish to call it directly sometimes if you don't want that other
@@ -116,9 +133,15 @@ public:
void beginPath();
void addPath(const SkPath&);
- const SkPath* currentPath() const { return &m_path; }
+ SkPath currentPathInLocalCoordinates() const;
+
+ // Returns the fill color. The returned color has it's alpha adjusted
+ // by the current alpha.
+ SkColor effectiveFillColor() const;
- SkColor fillColor() const;
+ // Returns the stroke color. The returned color has it's alpha adjusted
+ // by the current alpha.
+ SkColor effectiveStrokeColor() const;
skia::PlatformCanvas* canvas() { return m_canvas; }
@@ -142,12 +165,13 @@ public:
// possible quality.
bool isPrinting();
-#if defined(__linux__)
- // FIXME: should be camelCase.
- GdkSkia* gdk_skia() const { return m_gdkskia; }
+private:
+#if defined(__linux__) || PLATFORM(WIN_OS)
+ // 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&);
#endif
-private:
// Defines drawing style.
struct State;
@@ -161,12 +185,11 @@ private:
// mStateStack.back().
State* m_state;
- // Current path.
+ // Current path in global coordinates.
SkPath m_path;
-#if defined(__linux__)
- // A pointer to a GDK Drawable wrapping of this Skia canvas
- GdkSkia* m_gdkskia;
+#if PLATFORM(WIN_OS)
+ bool m_drawingToImageBuffer;
#endif
};
diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp
index 6e79a7e..d0cd4c5 100644
--- a/WebCore/platform/graphics/skia/SkiaFontWin.cpp
+++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp
@@ -31,8 +31,13 @@
#include "config.h"
#include "SkiaFontWin.h"
+#include "PlatformContextSkia.h"
+#include "Gradient.h"
+#include "Pattern.h"
#include "SkCanvas.h"
#include "SkPaint.h"
+#include "SkShader.h"
+#include "TransformationMatrix.h"
#include <wtf/ListHashSet.h>
#include <wtf/Vector.h>
@@ -162,10 +167,10 @@ static bool getPathForGlyph(HDC dc, WORD glyph, SkPath* path)
addPolyCurveToPath(polyCurve, path);
curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx;
}
+ path->close();
curGlyph += polyHeader->cb;
}
- path->close();
return true;
}
@@ -215,4 +220,152 @@ void SkiaWinOutlineCache::removePathsForFont(HFONT hfont)
deleteOutline(outlineCache.find(*i));
}
+bool windowsCanHandleTextDrawing(GraphicsContext* context)
+{
+ // Check for non-translation transforms. Sometimes zooms will look better in
+ // Skia, and sometimes better in Windows. The main problem is that zooming
+ // in using Skia will show you the hinted outlines for the smaller size,
+ // which look weird. All else being equal, it's better to use Windows' text
+ // drawing, so we don't check for zooms.
+ const TransformationMatrix& matrix = context->getCTM();
+ if (matrix.b() != 0 || matrix.c() != 0) // Check for skew.
+ return false;
+
+ // Check for stroke effects.
+ if (context->platformContext()->getTextDrawingMode() != cTextFill)
+ return false;
+
+ // Check for gradients.
+ if (context->fillGradient() || context->strokeGradient())
+ return false;
+
+ // Check for patterns.
+ if (context->fillPattern() || context->strokePattern())
+ return false;
+
+ // Check for shadow effects.
+ if (context->platformContext()->getDrawLooper())
+ return false;
+
+ return true;
+}
+
+// Draws the given text string using skia. Note that gradient or
+// pattern may be NULL, in which case a solid colour is used.
+static bool skiaDrawText(HFONT hfont,
+ HDC dc,
+ SkCanvas* canvas,
+ const SkPoint& point,
+ SkPaint* paint,
+ const TransformationMatrix& transformationMatrix,
+ Gradient* gradient,
+ Pattern* pattern,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ int numGlyphs)
+{
+ SkShader* shader = NULL;
+ if (gradient)
+ shader = gradient->platformGradient();
+ else if (pattern)
+ shader = pattern->createPlatformPattern(transformationMatrix);
+
+ paint->setShader(shader);
+ float x = point.fX, y = point.fY;
+
+ for (int i = 0; i < numGlyphs; i++) {
+ const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);
+ if (!path)
+ return false;
+
+ float offsetX = 0.0f, offsetY = 0.0f;
+ if (offsets && (offsets[i].du != 0 || offsets[i].dv != 0)) {
+ offsetX = offsets[i].du;
+ offsetY = offsets[i].dv;
+ }
+
+ SkPath newPath;
+ newPath.addPath(*path, x + offsetX, y + offsetY);
+ canvas->drawPath(newPath, *paint);
+
+ x += advances[i];
+ }
+
+ return true;
+}
+
+bool paintSkiaText(GraphicsContext* context,
+ HFONT hfont,
+ int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ const SkPoint* origin)
+{
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, hfont);
+
+ PlatformContextSkia* platformContext = context->platformContext();
+ int textMode = platformContext->getTextDrawingMode();
+
+ // Filling (if necessary). This is the common case.
+ SkPaint paint;
+ platformContext->setupPaintForFilling(&paint);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ bool didFill = false;
+
+ if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) {
+ Gradient* fillGradient = 0;
+ Pattern* fillPattern = 0;
+ if (context->fillColorSpace() == GradientColorSpace)
+ fillGradient = context->fillGradient();
+ else if (context->fillColorSpace() == PatternColorSpace)
+ fillPattern = context->fillPattern();
+ if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,
+ context->getCTM(), fillGradient, fillPattern,
+ &glyphs[0], &advances[0], &offsets[0], numGlyphs))
+ return false;
+ didFill = true;
+ }
+
+ // Stroking on top (if necessary).
+ if ((textMode & WebCore::cTextStroke)
+ && platformContext->getStrokeStyle() != NoStroke
+ && platformContext->getStrokeThickness() > 0) {
+
+ paint.reset();
+ platformContext->setupPaintForStroking(&paint, 0, 0);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ if (didFill) {
+ // If there is a shadow and we filled above, there will already be
+ // a shadow. We don't want to draw it again or it will be too dark
+ // and it will go on top of the fill.
+ //
+ // Note that this isn't strictly correct, since the stroke could be
+ // very thick and the shadow wouldn't account for this. The "right"
+ // thing would be to draw to a new layer and then draw that layer
+ // with a shadow. But this is a lot of extra work for something
+ // that isn't normally an issue.
+ paint.setLooper(0)->safeUnref();
+ }
+
+ Gradient* strokeGradient = 0;
+ Pattern* strokePattern = 0;
+ if (context->strokeColorSpace() == GradientColorSpace)
+ strokeGradient = context->strokeGradient();
+ else if (context->strokeColorSpace() == PatternColorSpace)
+ strokePattern = context->strokePattern();
+ if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,
+ context->getCTM(), strokeGradient, strokePattern,
+ &glyphs[0], &advances[0], &offsets[0], numGlyphs))
+ return false;
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ return true;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.h b/WebCore/platform/graphics/skia/SkiaFontWin.h
index 2adab39..0e0c953 100644
--- a/WebCore/platform/graphics/skia/SkiaFontWin.h
+++ b/WebCore/platform/graphics/skia/SkiaFontWin.h
@@ -32,8 +32,12 @@
#define SkiaWinOutlineCache_h
#include <windows.h>
+#include <usp10.h>
+class GraphicsContext;
class SkPath;
+class SkPoint;
+class PlatformContextSkia;
namespace WebCore {
@@ -49,6 +53,37 @@ private:
SkiaWinOutlineCache();
};
+// The functions below are used for more complex font drawing (effects such as
+// stroking and more complex transforms) than Windows supports directly. Since
+// Windows drawing is faster you should use windowsCanHandleTextDrawing first to
+// check if using Skia is required at all.
+// Note that the text will look different (no ClearType) so this should only be
+// used when necessary.
+//
+// When you call a Skia* text drawing function, various glyph outlines will be
+// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont
+// when the font is destroyed so that the cache does not outlive the font (since
+// the HFONTs are recycled).
+//
+// Remember that Skia's text drawing origin is the baseline, like WebKit, not
+// the top, like Windows.
+
+// Returns true if advanced font rendering is recommended.
+bool windowsCanHandleTextDrawing(GraphicsContext* context);
+
+// Note that the offsets parameter is optional. If not NULL it represents a
+// per glyph offset (such as returned by ScriptPlace Windows API function).
+//
+// Returns true of the text was drawn successfully. False indicates an error
+// from Windows.
+bool paintSkiaText(GraphicsContext* graphicsContext,
+ HFONT hfont,
+ int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ const GOFFSET* offsets,
+ const SkPoint* origin);
+
} // namespace WebCore
#endif // SkiaWinOutlineCache_h
diff --git a/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp b/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
index 1e2a194..2d0f9f8 100644
--- a/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
+++ b/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
@@ -30,193 +30,28 @@
#include "config.h"
#include "TransformationMatrix.h"
-#include "FloatRect.h"
-#include "IntRect.h"
-
#include "SkiaUtils.h"
namespace WebCore {
-TransformationMatrix::TransformationMatrix()
-{
- m_transform.reset();
-}
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double e, double f)
-{
- setMatrix(a, b, c, d, e, f);
-}
-
-TransformationMatrix::TransformationMatrix(const SkMatrix& matrix)
- : m_transform(matrix)
-{
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double e, double f)
-{
- m_transform.reset();
-
- m_transform.setScaleX(WebCoreDoubleToSkScalar(a));
- m_transform.setSkewX(WebCoreDoubleToSkScalar(c));
- m_transform.setTranslateX(WebCoreDoubleToSkScalar(e));
-
- m_transform.setScaleY(WebCoreDoubleToSkScalar(d));
- m_transform.setSkewY(WebCoreDoubleToSkScalar(b));
- m_transform.setTranslateY(WebCoreDoubleToSkScalar(f));
-}
-
-void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
-{
- SkPoint src, dst;
- src.set(WebCoreDoubleToSkScalar(x), WebCoreDoubleToSkScalar(y));
- m_transform.mapPoints(&dst, &src, 1);
-
- *x2 = SkScalarToDouble(dst.fX);
- *y2 = SkScalarToDouble(dst.fY);
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect& src) const
-{
- SkRect dst;
- m_transform.mapRect(&dst, src);
- return enclosingIntRect(dst);
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect& src) const
-{
- SkRect dst;
- m_transform.mapRect(&dst, src);
- return dst;
-}
-
-bool TransformationMatrix::isIdentity() const
-{
- return m_transform.isIdentity();
-}
-
-void TransformationMatrix::reset()
-{
- m_transform.reset();
-}
-
-TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
-{
- m_transform.preScale(WebCoreDoubleToSkScalar(sx), WebCoreDoubleToSkScalar(sy), 0, 0);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::rotate(double d)
-{
- m_transform.preRotate(WebCoreDoubleToSkScalar(d), 0, 0);
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
-{
- m_transform.preTranslate(WebCoreDoubleToSkScalar(tx), WebCoreDoubleToSkScalar(ty));
- return *this;
-}
-
-TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
-{
- m_transform.preSkew(WebCoreDoubleToSkScalar(sx), WebCoreDoubleToSkScalar(sy), 0, 0);
- return *this;
-}
-
-double TransformationMatrix::det() const
-{
- return SkScalarToDouble(m_transform.getScaleX()) * SkScalarToDouble(m_transform.getScaleY()) -
- SkScalarToDouble(m_transform.getSkewY()) * SkScalarToDouble(m_transform.getSkewX());
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- TransformationMatrix inverse;
- m_transform.invert(&inverse.m_transform);
- return inverse;
-}
-
TransformationMatrix::operator SkMatrix() const
{
- return m_transform;
-}
-
-bool TransformationMatrix::operator==(const TransformationMatrix& m2) const
-{
- return m_transform == m2.m_transform;
-}
+ SkMatrix result;
-TransformationMatrix &TransformationMatrix::operator*=(const TransformationMatrix& m2)
-{
- m_transform.setConcat(m2.m_transform, m_transform);
- return *this;
-}
+ result.setScaleX(WebCoreDoubleToSkScalar(a()));
+ result.setSkewX(WebCoreDoubleToSkScalar(c()));
+ result.setTranslateX(WebCoreDoubleToSkScalar(e()));
-TransformationMatrix TransformationMatrix::operator*(const TransformationMatrix& m2)
-{
- TransformationMatrix cat;
- cat.m_transform.setConcat(m2.m_transform, m_transform);
- return cat;
-}
+ result.setScaleY(WebCoreDoubleToSkScalar(d()));
+ result.setSkewY(WebCoreDoubleToSkScalar(b()));
+ result.setTranslateY(WebCoreDoubleToSkScalar(f()));
-double TransformationMatrix::a() const
-{
- return SkScalarToDouble(m_transform.getScaleX());
-}
-
-void TransformationMatrix::setA(double a)
-{
- m_transform.setScaleX(WebCoreDoubleToSkScalar(a));
-}
-
-double TransformationMatrix::b() const
-{
- return SkScalarToDouble(m_transform.getSkewY());
-}
-
-void TransformationMatrix::setB(double b)
-{
- m_transform.setSkewY(WebCoreDoubleToSkScalar(b));
-}
+ // FIXME: Set perspective properly.
+ result.setPerspX(0);
+ result.setPerspY(0);
+ result.set(SkMatrix::kMPersp2, SK_Scalar1);
-double TransformationMatrix::c() const
-{
- return SkScalarToDouble(m_transform.getSkewX());
-}
-
-void TransformationMatrix::setC(double c)
-{
- m_transform.setSkewX(WebCoreDoubleToSkScalar(c));
-}
-
-double TransformationMatrix::d() const
-{
- return SkScalarToDouble(m_transform.getScaleY());
-}
-
-void TransformationMatrix::setD(double d)
-{
- m_transform.setScaleY(WebCoreDoubleToSkScalar(d));
-}
-
-double TransformationMatrix::e() const
-{
- return SkScalarToDouble(m_transform.getTranslateX());
-}
-
-void TransformationMatrix::setE(double e)
-{
- m_transform.setTranslateX(WebCoreDoubleToSkScalar(e));
-}
-
-double TransformationMatrix::f() const
-{
- return SkScalarToDouble(m_transform.getTranslateY());
-}
-
-void TransformationMatrix::setF(double f)
-{
- m_transform.setTranslateY(WebCoreDoubleToSkScalar(f));
+ return result;
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
new file mode 100644
index 0000000..ab3413b
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Matrix3DTransformOperation.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> Matrix3DTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ // Convert the TransformOperations into matrices
+ IntSize size;
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ if (from)
+ from->apply(fromT, size);
+
+ apply(toT, size);
+
+ if (blendToIdentity)
+ swap(fromT, toT);
+
+ toT.blend(fromT, progress);
+ return Matrix3DTransformOperation::create(toT);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
new file mode 100644
index 0000000..7430dbc
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Matrix3DTransformOperation_h
+#define Matrix3DTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class Matrix3DTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<Matrix3DTransformOperation> create(const TransformationMatrix& matrix)
+ {
+ return adoptRef(new Matrix3DTransformOperation(matrix));
+ }
+
+private:
+ virtual bool isIdentity() const { return m_matrix.isIdentity(); }
+
+ virtual OperationType getOperationType() const { return MATRIX_3D; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX_3D; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const Matrix3DTransformOperation* m = static_cast<const Matrix3DTransformOperation*>(&o);
+ return m_matrix == m->m_matrix;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.multLeft(TransformationMatrix(m_matrix));
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ Matrix3DTransformOperation(const TransformationMatrix& mat)
+ {
+ m_matrix = mat;
+ }
+
+ TransformationMatrix m_matrix;
+};
+
+} // namespace WebCore
+
+#endif // Matrix3DTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
index 153d96d..4934fa6 100644
--- a/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
@@ -24,6 +24,8 @@
#include <algorithm>
+using namespace std;
+
namespace WebCore {
PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
@@ -41,7 +43,7 @@ PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOp
}
if (blendToIdentity)
- std::swap(fromT, toT);
+ swap(fromT, toT);
toT.blend(fromT, progress);
return MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f());
diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
index d272229..ee47a11 100644
--- a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
@@ -26,6 +26,7 @@
#define MatrixTransformOperation_h
#include "TransformOperation.h"
+#include "TransformationMatrix.h"
namespace WebCore {
@@ -36,8 +37,14 @@ public:
return adoptRef(new MatrixTransformOperation(a, b, c, d, e, f));
}
+ static PassRefPtr<MatrixTransformOperation> create(const TransformationMatrix& t)
+ {
+ return adoptRef(new MatrixTransformOperation(t));
+ }
+
private:
virtual bool isIdentity() const { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; }
+
virtual OperationType getOperationType() const { return MATRIX; }
virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX; }
@@ -53,7 +60,7 @@ private:
virtual bool apply(TransformationMatrix& transform, const IntSize&) const
{
TransformationMatrix matrix(m_a, m_b, m_c, m_d, m_e, m_f);
- transform = matrix * transform;
+ transform.multLeft(TransformationMatrix(matrix));
return false;
}
@@ -68,6 +75,16 @@ private:
, m_f(f)
{
}
+
+ MatrixTransformOperation(const TransformationMatrix& t)
+ : m_a(t.a())
+ , m_b(t.b())
+ , m_c(t.c())
+ , m_d(t.d())
+ , m_e(t.e())
+ , m_f(t.f())
+ {
+ }
double m_a;
double m_b;
diff --git a/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp
new file mode 100644
index 0000000..9fd03a1
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PerspectiveTransformOperation.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> PerspectiveTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return PerspectiveTransformOperation::create(m_p + (1. - m_p) * progress);
+
+ const PerspectiveTransformOperation* fromOp = static_cast<const PerspectiveTransformOperation*>(from);
+ double fromP = fromOp ? fromOp->m_p : 0;
+ double toP = m_p;
+
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ fromT.applyPerspective(fromP);
+ toT.applyPerspective(toP);
+ toT.blend(fromT, progress);
+ TransformationMatrix::DecomposedType decomp;
+ toT.decompose(decomp);
+
+ return PerspectiveTransformOperation::create(decomp.perspectiveZ ? -1.0 / decomp.perspectiveZ : 0.0);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
new file mode 100644
index 0000000..a665f3e
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PerspectiveTransformOperation_h
+#define PerspectiveTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class PerspectiveTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<PerspectiveTransformOperation> create(double p)
+ {
+ return adoptRef(new PerspectiveTransformOperation(p));
+ }
+
+private:
+ virtual bool isIdentity() const { return m_p == 0; }
+ virtual OperationType getOperationType() const { return PERSPECTIVE; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == PERSPECTIVE; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const PerspectiveTransformOperation* p = static_cast<const PerspectiveTransformOperation*>(&o);
+ return m_p == p->m_p;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.applyPerspective(m_p);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ PerspectiveTransformOperation(double p)
+ : m_p(p)
+ {
+ }
+
+ double m_p;
+};
+
+} // namespace WebCore
+
+#endif // PerspectiveTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp b/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
index 4887cee..919d174 100644
--- a/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
@@ -22,6 +22,11 @@
#include "config.h"
#include "RotateTransformOperation.h"
+#include <algorithm>
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
namespace WebCore {
PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
@@ -30,11 +35,61 @@ PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOp
return this;
if (blendToIdentity)
- return RotateTransformOperation::create(m_angle - m_angle * progress, m_type);
+ return RotateTransformOperation::create(m_x, m_y, m_z, m_angle - m_angle * progress, m_type);
const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from);
- double fromAngle = fromOp ? fromOp->m_angle : 0;
- return RotateTransformOperation::create(fromAngle + (m_angle - fromAngle) * progress, m_type);
+
+ // Optimize for single axis rotation
+ if (!fromOp || (fromOp->m_x == 0 && fromOp->m_y == 0 && fromOp->m_z == 1) ||
+ (fromOp->m_x == 0 && fromOp->m_y == 1 && fromOp->m_z == 0) ||
+ (fromOp->m_x == 1 && fromOp->m_y == 0 && fromOp->m_z == 0)) {
+ double fromAngle = fromOp ? fromOp->m_angle : 0;
+ return RotateTransformOperation::create(fromOp ? fromOp->m_x : m_x,
+ fromOp ? fromOp->m_y : m_y,
+ fromOp ? fromOp->m_z : m_z,
+ fromAngle + (m_angle - fromAngle) * progress, m_type);
+ }
+
+ const RotateTransformOperation* toOp = this;
+
+ // Create the 2 rotation matrices
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ fromT.rotate3d((float)(fromOp ? fromOp->m_x : 0),
+ (float)(fromOp ? fromOp->m_y : 0),
+ (float)(fromOp ? fromOp->m_z : 1),
+ (float)(fromOp ? fromOp->m_angle : 0));
+
+ toT.rotate3d((float)(toOp ? toOp->m_x : 0),
+ (float)(toOp ? toOp->m_y : 0),
+ (float)(toOp ? toOp->m_z : 1),
+ (float)(toOp ? toOp->m_angle : 0));
+
+ // Blend them
+ toT.blend(fromT, progress);
+
+ // Extract the result as a quaternion
+ TransformationMatrix::DecomposedType decomp;
+ toT.decompose(decomp);
+
+ // Convert that to Axis/Angle form
+ double x = -decomp.quaternionX;
+ double y = -decomp.quaternionY;
+ double z = -decomp.quaternionZ;
+ double length = sqrt(x * x + y * y + z * z);
+ double angle = 0;
+
+ if (length > 0.00001) {
+ x /= length;
+ y /= length;
+ z /= length;
+ angle = rad2deg(acos(decomp.quaternionW) * 2);
+ } else {
+ x = 0;
+ y = 0;
+ z = 1;
+ }
+ return RotateTransformOperation::create(x, y, z, angle, ROTATE_3D);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.h b/WebCore/platform/graphics/transforms/RotateTransformOperation.h
index adc6c4c..699ea43 100644
--- a/WebCore/platform/graphics/transforms/RotateTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.h
@@ -33,10 +33,19 @@ class RotateTransformOperation : public TransformOperation {
public:
static PassRefPtr<RotateTransformOperation> create(double angle, OperationType type)
{
- return adoptRef(new RotateTransformOperation(angle, type));
+ return adoptRef(new RotateTransformOperation(0, 0, 1, angle, type));
}
+ static PassRefPtr<RotateTransformOperation> create(double x, double y, double z, double angle, OperationType type)
+ {
+ return adoptRef(new RotateTransformOperation(x, y, z, angle, type));
+ }
+
+ double angle() const { return m_angle; }
+
+private:
virtual bool isIdentity() const { return m_angle == 0; }
+
virtual OperationType getOperationType() const { return m_type; }
virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
@@ -45,26 +54,30 @@ public:
if (!isSameType(o))
return false;
const RotateTransformOperation* r = static_cast<const RotateTransformOperation*>(&o);
- return m_angle == r->m_angle;
+ return m_x == r->m_x && m_y == r->m_y && m_z == r->m_z && m_angle == r->m_angle;
}
virtual bool apply(TransformationMatrix& transform, const IntSize& /*borderBoxSize*/) const
{
- transform.rotate(m_angle);
+ transform.rotate3d(m_x, m_y, m_z, m_angle);
return false;
}
virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
- double angle() const { return m_angle; }
-
-private:
- RotateTransformOperation(double angle, OperationType type)
- : m_angle(angle)
+ RotateTransformOperation(double x, double y, double z, double angle, OperationType type)
+ : m_x(x)
+ , m_y(y)
+ , m_z(z)
+ , m_angle(angle)
, m_type(type)
{
+ ASSERT(type == ROTATE_X || type == ROTATE_Y || type == ROTATE_Z || type == ROTATE_3D);
}
+ double m_x;
+ double m_y;
+ double m_z;
double m_angle;
OperationType m_type;
};
diff --git a/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp b/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
index 49a8fd8..45d119c 100644
--- a/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
@@ -30,12 +30,17 @@ PassRefPtr<TransformOperation> ScaleTransformOperation::blend(const TransformOpe
return this;
if (blendToIdentity)
- return ScaleTransformOperation::create(m_x + (1. - m_x) * progress, m_y + (1. - m_y) * progress, m_type);
+ return ScaleTransformOperation::create(m_x + (1. - m_x) * progress,
+ m_y + (1. - m_y) * progress,
+ m_z + (1. - m_z) * progress, m_type);
const ScaleTransformOperation* fromOp = static_cast<const ScaleTransformOperation*>(from);
double fromX = fromOp ? fromOp->m_x : 1.;
double fromY = fromOp ? fromOp->m_y : 1.;
- return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress, fromY + (m_y - fromY) * progress, m_type);
+ double fromZ = fromOp ? fromOp->m_z : 1.;
+ return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress,
+ fromY + (m_y - fromY) * progress,
+ fromZ + (m_z - fromZ) * progress, m_type);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/ScaleTransformOperation.h b/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
index 289f8a1..a87bb3b 100644
--- a/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
@@ -33,11 +33,21 @@ class ScaleTransformOperation : public TransformOperation {
public:
static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, OperationType type)
{
- return adoptRef(new ScaleTransformOperation(sx, sy, type));
+ return adoptRef(new ScaleTransformOperation(sx, sy, 1, type));
}
+ static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, double sz, OperationType type)
+ {
+ return adoptRef(new ScaleTransformOperation(sx, sy, sz, type));
+ }
+
+ double x() const { return m_x; }
+ double y() const { return m_y; }
+ double z() const { return m_z; }
+
private:
- virtual bool isIdentity() const { return m_x == 1 && m_y == 1; }
+ virtual bool isIdentity() const { return m_x == 1 && m_y == 1 && m_z == 1; }
+
virtual OperationType getOperationType() const { return m_type; }
virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
@@ -46,26 +56,29 @@ private:
if (!isSameType(o))
return false;
const ScaleTransformOperation* s = static_cast<const ScaleTransformOperation*>(&o);
- return m_x == s->m_x && m_y == s->m_y;
+ return m_x == s->m_x && m_y == s->m_y && m_z == s->m_z;
}
virtual bool apply(TransformationMatrix& transform, const IntSize&) const
{
- transform.scale(m_x, m_y);
+ transform.scale3d(m_x, m_y, m_z);
return false;
}
virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
- ScaleTransformOperation(double sx, double sy, OperationType type)
+ ScaleTransformOperation(double sx, double sy, double sz, OperationType type)
: m_x(sx)
, m_y(sy)
+ , m_z(sz)
, m_type(type)
{
+ ASSERT(type == SCALE_X || type == SCALE_Y || type == SCALE_Z || type == SCALE || type == SCALE_3D);
}
double m_x;
double m_y;
+ double m_z;
OperationType m_type;
};
diff --git a/WebCore/platform/graphics/transforms/TransformOperation.h b/WebCore/platform/graphics/transforms/TransformOperation.h
index 65a0def..c610c4b 100644
--- a/WebCore/platform/graphics/transforms/TransformOperation.h
+++ b/WebCore/platform/graphics/transforms/TransformOperation.h
@@ -39,9 +39,16 @@ public:
enum OperationType {
SCALE_X, SCALE_Y, SCALE,
TRANSLATE_X, TRANSLATE_Y, TRANSLATE,
- ROTATE,
+ ROTATE,
+ ROTATE_Z = ROTATE,
SKEW_X, SKEW_Y, SKEW,
- MATRIX, IDENTITY, NONE
+ MATRIX,
+ SCALE_Z, SCALE_3D,
+ TRANSLATE_Z, TRANSLATE_3D,
+ ROTATE_X, ROTATE_Y, ROTATE_3D,
+ MATRIX_3D,
+ PERSPECTIVE,
+ IDENTITY, NONE
};
virtual ~TransformOperation() { }
@@ -51,12 +58,27 @@ public:
virtual bool isIdentity() const = 0;
+ // Return true if the borderBoxSize was used in the computation, false otherwise.
virtual bool apply(TransformationMatrix&, const IntSize& borderBoxSize) const = 0;
virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false) = 0;
virtual OperationType getOperationType() const = 0;
virtual bool isSameType(const TransformOperation&) const { return false; }
+
+ bool is3DOperation() const
+ {
+ OperationType opType = getOperationType();
+ return opType == SCALE_Z ||
+ opType == SCALE_3D ||
+ opType == TRANSLATE_Z ||
+ opType == TRANSLATE_3D ||
+ opType == ROTATE_X ||
+ opType == ROTATE_Y ||
+ opType == ROTATE_3D ||
+ opType == MATRIX_3D ||
+ opType == PERSPECTIVE;
+ }
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/TransformOperations.h b/WebCore/platform/graphics/transforms/TransformOperations.h
index f929417..11605e8 100644
--- a/WebCore/platform/graphics/transforms/TransformOperations.h
+++ b/WebCore/platform/graphics/transforms/TransformOperations.h
@@ -47,6 +47,16 @@ public:
m_operations[i]->apply(t, sz);
}
+ // Return true if any of the operation types are 3D operation types (even if the
+ // values describe affine transforms)
+ bool has3DOperation() const
+ {
+ for (unsigned i = 0; i < m_operations.size(); ++i)
+ if (m_operations[i]->is3DOperation())
+ return true;
+ return false;
+ }
+
Vector<RefPtr<TransformOperation> >& operations() { return m_operations; }
const Vector<RefPtr<TransformOperation> >& operations() const { return m_operations; }
diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
index b48d572..4bcfdb2 100644
--- a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "TransformationMatrix.h"
+#include "FloatPoint3D.h"
#include "FloatRect.h"
#include "FloatQuad.h"
#include "IntRect.h"
@@ -34,76 +35,467 @@
namespace WebCore {
-static void affineTransformDecompose(const TransformationMatrix& matrix, double sr[9])
+//
+// Supporting Math Functions
+//
+// This is a set of function from various places (attributed inline) to do things like
+// inversion and decomposition of a 4x4 matrix. They are used throughout the code
+//
+
+//
+// Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
+
+// EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
+// as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
+// or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
+// are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
+// webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
+// with no guarantee.
+
+typedef double Vector4[4];
+typedef double Vector3[3];
+
+const double SMALL_NUMBER = 1.e-8;
+
+// inverse(original_matrix, inverse_matrix)
+//
+// calculate the inverse of a 4x4 matrix
+//
+// -1
+// A = ___1__ adjoint A
+// det A
+
+// double = determinant2x2(double a, double b, double c, double d)
+//
+// calculate the determinant of a 2x2 matrix.
+
+static double determinant2x2(double a, double b, double c, double d)
{
- TransformationMatrix m(matrix);
+ return a * d - b * c;
+}
- // Compute scaling factors
- double sx = sqrt(m.a() * m.a() + m.b() * m.b());
- double sy = sqrt(m.c() * m.c() + m.d() * m.d());
+// double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
+//
+// Calculate the determinant of a 3x3 matrix
+// in the form
+//
+// | a1, b1, c1 |
+// | a2, b2, c2 |
+// | a3, b3, c3 |
- /* Compute cross product of transformed unit vectors. If negative,
- one axis was flipped. */
+static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)
+{
+ return a1 * determinant2x2(b2, b3, c2, c3)
+ - b1 * determinant2x2(a2, a3, c2, c3)
+ + c1 * determinant2x2(a2, a3, b2, b3);
+}
- if (m.a() * m.d() - m.c() * m.b() < 0.0) {
- // Flip axis with minimum unit vector dot product
+// double = determinant4x4(matrix)
+//
+// calculate the determinant of a 4x4 matrix.
- if (m.a() < m.d())
- sx = -sx;
- else
- sy = -sy;
- }
+static double determinant4x4(const TransformationMatrix::Matrix4& m)
+{
+ // Assign to individual variable names to aid selecting
+ // correct elements
+
+ double a1 = m[0][0];
+ double b1 = m[0][1];
+ double c1 = m[0][2];
+ double d1 = m[0][3];
+
+ double a2 = m[1][0];
+ double b2 = m[1][1];
+ double c2 = m[1][2];
+ double d2 = m[1][3];
+
+ double a3 = m[2][0];
+ double b3 = m[2][1];
+ double c3 = m[2][2];
+ double d3 = m[2][3];
+
+ double a4 = m[3][0];
+ double b4 = m[3][1];
+ double c4 = m[3][2];
+ double d4 = m[3][3];
+
+ return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
+ - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
+ + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
+ - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
+}
+
+// adjoint( original_matrix, inverse_matrix )
+//
+// calculate the adjoint of a 4x4 matrix
+//
+// Let a denote the minor determinant of matrix A obtained by
+// ij
+//
+// deleting the ith row and jth column from A.
+//
+// i+j
+// Let b = (-1) a
+// ij ji
+//
+// The matrix B = (b ) is the adjoint of A
+// ij
+
+static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
+{
+ // Assign to individual variable names to aid
+ // selecting correct values
+ double a1 = matrix[0][0];
+ double b1 = matrix[0][1];
+ double c1 = matrix[0][2];
+ double d1 = matrix[0][3];
- // Remove scale from matrix
+ double a2 = matrix[1][0];
+ double b2 = matrix[1][1];
+ double c2 = matrix[1][2];
+ double d2 = matrix[1][3];
- m.scale(1.0 / sx, 1.0 / sy);
+ double a3 = matrix[2][0];
+ double b3 = matrix[2][1];
+ double c3 = matrix[2][2];
+ double d3 = matrix[2][3];
- // Compute rotation
+ double a4 = matrix[3][0];
+ double b4 = matrix[3][1];
+ double c4 = matrix[3][2];
+ double d4 = matrix[3][3];
- double angle = atan2(m.b(), m.a());
+ // Row column labeling reversed since we transpose rows & columns
+ result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
+ result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
+ result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
+ result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
+
+ result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
+ result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
+ result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
+ result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
+
+ result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
+ result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
+ result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
+ result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
+
+ result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
+ result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
+ result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
+ result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
+}
+
+// Returns false if the matrix is not invertible
+static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
+{
+ // Calculate the adjoint matrix
+ adjoint(matrix, result);
- // Remove rotation from matrix
+ // Calculate the 4x4 determinant
+ // If the determinant is zero,
+ // then the inverse matrix is not unique.
+ double det = determinant4x4(matrix);
- m.rotate(rad2deg(-angle));
+ if (fabs(det) < SMALL_NUMBER)
+ return false;
- // Return results
+ // Scale the adjoint matrix to get the inverse
- sr[0] = sx; sr[1] = sy; sr[2] = angle;
- sr[3] = m.a(); sr[4] = m.b();
- sr[5] = m.c(); sr[6] = m.d();
- sr[7] = m.e(); sr[8] = m.f();
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ result[i][j] = result[i][j] / det;
+
+ return true;
}
-static void affineTransformCompose(TransformationMatrix& m, const double sr[9])
+// End of code adapted from Matrix Inversion by Richard Carling
+
+// Perform a decomposition on the passed matrix, return false if unsuccessful
+// From Graphics Gems: unmatrix.c
+
+// Transpose rotation portion of matrix a, return b
+static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b)
{
- m.setA(sr[3]);
- m.setB(sr[4]);
- m.setC(sr[5]);
- m.setD(sr[6]);
- m.setE(sr[7]);
- m.setF(sr[8]);
- m.rotate(rad2deg(sr[2]));
- m.scale(sr[0], sr[1]);
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
+ b[i][j] = a[j][i];
}
-bool TransformationMatrix::isInvertible() const
+// Multiply a homogeneous point by a matrix and return the transformed point
+static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result)
{
- return det() != 0.0;
+ result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) +
+ (p[2] * m[2][0]) + (p[3] * m[3][0]);
+ result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) +
+ (p[2] * m[2][1]) + (p[3] * m[3][1]);
+ result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) +
+ (p[2] * m[2][2]) + (p[3] * m[3][2]);
+ result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) +
+ (p[2] * m[2][3]) + (p[3] * m[3][3]);
}
-TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& other)
+static double v3Length(Vector3 a)
{
- return (*this) *= other;
+ return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));
}
-TransformationMatrix& TransformationMatrix::scale(double s)
+static void v3Scale(Vector3 v, double desiredLength)
{
- return scale(s, s);
+ double len = v3Length(v);
+ if (len != 0) {
+ double l = desiredLength / len;
+ v[0] *= l;
+ v[1] *= l;
+ v[2] *= l;
+ }
}
-TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
+static double v3Dot(const Vector3 a, const Vector3 b)
{
- return scale(sx, sy);
+ return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
+}
+
+// Make a linear combination of two vectors and return the result.
+// result = (a * ascl) + (b * bscl)
+static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl)
+{
+ result[0] = (ascl * a[0]) + (bscl * b[0]);
+ result[1] = (ascl * a[1]) + (bscl * b[1]);
+ result[2] = (ascl * a[2]) + (bscl * b[2]);
+}
+
+// Return the cross product result = a cross b */
+static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result)
+{
+ result[0] = (a[1] * b[2]) - (a[2] * b[1]);
+ result[1] = (a[2] * b[0]) - (a[0] * b[2]);
+ result[2] = (a[0] * b[1]) - (a[1] * b[0]);
+}
+
+static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result)
+{
+ TransformationMatrix::Matrix4 localMatrix;
+ memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4));
+
+ // Normalize the matrix.
+ if (localMatrix[3][3] == 0)
+ return false;
+
+ int i, j;
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ localMatrix[i][j] /= localMatrix[3][3];
+
+ // perspectiveMatrix is used to solve for perspective, but it also provides
+ // an easy way to test for singularity of the upper 3x3 component.
+ TransformationMatrix::Matrix4 perspectiveMatrix;
+ memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4));
+ for (i = 0; i < 3; i++)
+ perspectiveMatrix[i][3] = 0;
+ perspectiveMatrix[3][3] = 1;
+
+ if (determinant4x4(perspectiveMatrix) == 0)
+ return false;
+
+ // First, isolate perspective. This is the messiest.
+ if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) {
+ // rightHandSide is the right hand side of the equation.
+ Vector4 rightHandSide;
+ rightHandSide[0] = localMatrix[0][3];
+ rightHandSide[1] = localMatrix[1][3];
+ rightHandSide[2] = localMatrix[2][3];
+ rightHandSide[3] = localMatrix[3][3];
+
+ // Solve the equation by inverting perspectiveMatrix and multiplying
+ // rightHandSide by the inverse. (This is the easiest way, not
+ // necessarily the best.)
+ TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix;
+ inverse(perspectiveMatrix, inversePerspectiveMatrix);
+ transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
+
+ Vector4 perspectivePoint;
+ v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
+
+ result.perspectiveX = perspectivePoint[0];
+ result.perspectiveY = perspectivePoint[1];
+ result.perspectiveZ = perspectivePoint[2];
+ result.perspectiveW = perspectivePoint[3];
+
+ // Clear the perspective partition
+ localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0;
+ localMatrix[3][3] = 1;
+ } else {
+ // No perspective.
+ result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0;
+ result.perspectiveW = 1;
+ }
+
+ // Next take care of translation (easy).
+ result.translateX = localMatrix[3][0];
+ localMatrix[3][0] = 0;
+ result.translateY = localMatrix[3][1];
+ localMatrix[3][1] = 0;
+ result.translateZ = localMatrix[3][2];
+ localMatrix[3][2] = 0;
+
+ // Vector4 type and functions need to be added to the common set.
+ Vector3 row[3], pdum3;
+
+ // Now get scale and shear.
+ for (i = 0; i < 3; i++) {
+ row[i][0] = localMatrix[i][0];
+ row[i][1] = localMatrix[i][1];
+ row[i][2] = localMatrix[i][2];
+ }
+
+ // Compute X scale factor and normalize first row.
+ result.scaleX = v3Length(row[0]);
+ v3Scale(row[0], 1.0);
+
+ // Compute XY shear factor and make 2nd row orthogonal to 1st.
+ result.skewXY = v3Dot(row[0], row[1]);
+ v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY);
+
+ // Now, compute Y scale and normalize 2nd row.
+ result.scaleY = v3Length(row[1]);
+ v3Scale(row[1], 1.0);
+ result.skewXY /= result.scaleY;
+
+ // Compute XZ and YZ shears, orthogonalize 3rd row.
+ result.skewXZ = v3Dot(row[0], row[2]);
+ v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ);
+ result.skewYZ = v3Dot(row[1], row[2]);
+ v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ);
+
+ // Next, get Z scale and normalize 3rd row.
+ result.scaleZ = v3Length(row[2]);
+ v3Scale(row[2], 1.0);
+ result.skewXZ /= result.scaleZ;
+ result.skewYZ /= result.scaleZ;
+
+ // At this point, the matrix (in rows[]) is orthonormal.
+ // Check for a coordinate system flip. If the determinant
+ // is -1, then negate the matrix and the scaling factors.
+ v3Cross(row[1], row[2], pdum3);
+ if (v3Dot(row[0], pdum3) < 0) {
+ for (i = 0; i < 3; i++) {
+ result.scaleX *= -1;
+ row[i][0] *= -1;
+ row[i][1] *= -1;
+ row[i][2] *= -1;
+ }
+ }
+
+ // Now, get the rotations out, as described in the gem.
+
+ // FIXME - Add the ability to return either quaternions (which are
+ // easier to recompose with) or Euler angles (rx, ry, rz), which
+ // are easier for authors to deal with. The latter will only be useful
+ // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
+ // will leave the Euler angle code here for now.
+
+ // ret.rotateY = asin(-row[0][2]);
+ // if (cos(ret.rotateY) != 0) {
+ // ret.rotateX = atan2(row[1][2], row[2][2]);
+ // ret.rotateZ = atan2(row[0][1], row[0][0]);
+ // } else {
+ // ret.rotateX = atan2(-row[2][0], row[1][1]);
+ // ret.rotateZ = 0;
+ // }
+
+ double s, t, x, y, z, w;
+
+ t = row[0][0] + row[1][1] + row[2][2] + 1.0;
+
+ if (t > 1e-4) {
+ s = 0.5 / sqrt(t);
+ w = 0.25 / s;
+ x = (row[2][1] - row[1][2]) * s;
+ y = (row[0][2] - row[2][0]) * s;
+ z = (row[1][0] - row[0][1]) * s;
+ } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
+ s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx
+ x = 0.25 * s;
+ y = (row[0][1] + row[1][0]) / s;
+ z = (row[0][2] + row[2][0]) / s;
+ w = (row[2][1] - row[1][2]) / s;
+ } else if (row[1][1] > row[2][2]) {
+ s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy
+ x = (row[0][1] + row[1][0]) / s;
+ y = 0.25 * s;
+ z = (row[1][2] + row[2][1]) / s;
+ w = (row[0][2] - row[2][0]) / s;
+ } else {
+ s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz
+ x = (row[0][2] + row[2][0]) / s;
+ y = (row[1][2] + row[2][1]) / s;
+ z = 0.25 * s;
+ w = (row[1][0] - row[0][1]) / s;
+ }
+
+ result.quaternionX = x;
+ result.quaternionY = y;
+ result.quaternionZ = z;
+ result.quaternionW = w;
+
+ return true;
+}
+
+// Perform a spherical linear interpolation between the two
+// passed quaternions with 0 <= t <= 1
+static void slerp(double qa[4], const double qb[4], double t)
+{
+ double ax, ay, az, aw;
+ double bx, by, bz, bw;
+ double cx, cy, cz, cw;
+ double angle;
+ double th, invth, scale, invscale;
+
+ ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3];
+ bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3];
+
+ angle = ax * bx + ay * by + az * bz + aw * bw;
+
+ if (angle < 0.0) {
+ ax = -ax; ay = -ay;
+ az = -az; aw = -aw;
+ angle = -angle;
+ }
+
+ if (angle + 1.0 > .05) {
+ if (1.0 - angle >= .05) {
+ th = acos (angle);
+ invth = 1.0 / sin (th);
+ scale = sin (th * (1.0 - t)) * invth;
+ invscale = sin (th * t) * invth;
+ } else {
+ scale = 1.0 - t;
+ invscale = t;
+ }
+ } else {
+ bx = -ay;
+ by = ax;
+ bz = -aw;
+ bw = az;
+ scale = sin(piDouble * (.5 - t));
+ invscale = sin (piDouble * t);
+ }
+
+ cx = ax * scale + bx * invscale;
+ cy = ay * scale + by * invscale;
+ cz = az * scale + bz * invscale;
+ cw = aw * scale + bw * invscale;
+
+ qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw;
+}
+
+// End of Supporting Math Functions
+
+TransformationMatrix& TransformationMatrix::scale(double s)
+{
+ return scaleNonUniform(s, s);
}
TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
@@ -113,93 +505,574 @@ TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
TransformationMatrix& TransformationMatrix::flipX()
{
- return scale(-1.0f, 1.0f);
+ return scaleNonUniform(-1.0f, 1.0f);
}
TransformationMatrix& TransformationMatrix::flipY()
{
- return scale(1.0f, -1.0f);
+ return scaleNonUniform(1.0f, -1.0f);
}
-TransformationMatrix& TransformationMatrix::skew(double angleX, double angleY)
+FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) const
{
- return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
+ // This is basically raytracing. We have a point in the destination
+ // plane with z=0, and we cast a ray parallel to the z-axis from that
+ // point to find the z-position at which it intersects the z=0 plane
+ // with the transform applied. Once we have that point we apply the
+ // inverse transform to find the corresponding point in the source
+ // space.
+ //
+ // Given a plane with normal Pn, and a ray starting at point R0 and
+ // with direction defined by the vector Rd, we can find the
+ // intersection point as a distance d from R0 in units of Rd by:
+ //
+ // d = -dot (Pn', R0) / dot (Pn', Rd)
+
+ double x = p.x();
+ double y = p.y();
+ double z = -(m13() * x + m23() * y + m43()) / m33();
+
+ double outX = x * m11() + y * m21() + z * m31() + m41();
+ double outY = x * m12() + y * m22() + z * m32() + m42();
+
+ double w = x * m14() + y * m24() + z * m34() + m44();
+ if (w != 1 && w != 0) {
+ outX /= w;
+ outY /= w;
+ }
+
+ return FloatPoint(static_cast<float>(outX), static_cast<float>(outY));
}
-TransformationMatrix& TransformationMatrix::skewX(double angle)
+FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const
{
- return shear(tan(deg2rad(angle)), 0.0f);
+ FloatQuad projectedQuad;
+ projectedQuad.setP1(projectPoint(q.p1()));
+ projectedQuad.setP2(projectPoint(q.p2()));
+ projectedQuad.setP3(projectPoint(q.p3()));
+ projectedQuad.setP4(projectPoint(q.p4()));
+ return projectedQuad;
}
-TransformationMatrix& TransformationMatrix::skewY(double angle)
+FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
{
- return shear(0.0f, tan(deg2rad(angle)));
+ double x, y;
+ multVecMatrix(p.x(), p.y(), x, y);
+ return FloatPoint(static_cast<float>(x), static_cast<float>(y));
}
-TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
+FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const
{
- TransformationMatrix transform;
- transform.translate(dest.x() - source.x(), dest.y() - source.y());
- transform.scale(dest.width() / source.width(), dest.height() / source.height());
- return transform;
+ double x, y, z;
+ multVecMatrix(p.x(), p.y(), p.z(), x, y, z);
+ return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
}
IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const
{
- double x2, y2;
- map(point.x(), point.y(), &x2, &y2);
+ double x, y;
+ multVecMatrix(point.x(), point.y(), x, y);
// Round the point.
- return IntPoint(lround(x2), lround(y2));
+ return IntPoint(lround(x), lround(y));
+}
+
+IntRect TransformationMatrix::mapRect(const IntRect &rect) const
+{
+ return enclosingIntRect(mapRect(FloatRect(rect)));
}
-FloatPoint TransformationMatrix::mapPoint(const FloatPoint& point) const
+FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
{
- double x2, y2;
- map(point.x(), point.y(), &x2, &y2);
+ FloatQuad resultQuad = mapQuad(FloatQuad(r));
+ return resultQuad.boundingBox();
+}
- return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
+FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const
+{
+ FloatQuad result;
+ result.setP1(mapPoint(q.p1()));
+ result.setP2(mapPoint(q.p2()));
+ result.setP3(mapPoint(q.p3()));
+ result.setP4(mapPoint(q.p4()));
+ return result;
}
-FloatQuad TransformationMatrix::mapQuad(const FloatQuad& quad) const
+TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
{
- // FIXME: avoid 4 seperate library calls. Point mapping really needs
- // to be platform-independent code.
- return FloatQuad(mapPoint(quad.p1()),
- mapPoint(quad.p2()),
- mapPoint(quad.p3()),
- mapPoint(quad.p4()));
+ TransformationMatrix mat;
+ mat.m_matrix[0][0] = sx;
+ mat.m_matrix[1][1] = sy;
+
+ multLeft(mat);
+ return *this;
}
-void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
+TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz)
+{
+ TransformationMatrix mat;
+ mat.m_matrix[0][0] = sx;
+ mat.m_matrix[1][1] = sy;
+ mat.m_matrix[2][2] = sz;
+
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle)
+{
+ // angles are in degrees. Switch to radians
+ angle = deg2rad(angle);
+
+ angle /= 2.0f;
+ double sinA = sin(angle);
+ double cosA = cos(angle);
+ double sinA2 = sinA * sinA;
+
+ // normalize
+ double length = sqrt(x * x + y * y + z * z);
+ if (length == 0) {
+ // bad vector, just use something reasonable
+ x = 0;
+ y = 0;
+ z = 1;
+ } else if (length != 1) {
+ x /= length;
+ y /= length;
+ z /= length;
+ }
+
+ TransformationMatrix mat;
+
+ // optimize case where axis is along major axis
+ if (x == 1.0f && y == 0.0f && z == 0.0f) {
+ mat.m_matrix[0][0] = 1.0f;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = -2.0f * sinA * cosA;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else if (x == 0.0f && y == 1.0f && z == 0.0f) {
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else if (x == 0.0f && y == 0.0f && z == 1.0f) {
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 2.0f * sinA * cosA;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ } else {
+ double x2 = x*x;
+ double y2 = y*y;
+ double z2 = z*z;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * (y2 + z2) * sinA2;
+ mat.m_matrix[0][1] = 2.0f * (x * y * sinA2 + z * sinA * cosA);
+ mat.m_matrix[0][2] = 2.0f * (x * z * sinA2 - y * sinA * cosA);
+ mat.m_matrix[1][0] = 2.0f * (y * x * sinA2 - z * sinA * cosA);
+ mat.m_matrix[1][1] = 1.0f - 2.0f * (z2 + x2) * sinA2;
+ mat.m_matrix[1][2] = 2.0f * (y * z * sinA2 + x * sinA * cosA);
+ mat.m_matrix[2][0] = 2.0f * (z * x * sinA2 + y * sinA * cosA);
+ mat.m_matrix[2][1] = 2.0f * (z * y * sinA2 - x * sinA * cosA);
+ mat.m_matrix[2][2] = 1.0f - 2.0f * (x2 + y2) * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+ }
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz)
+{
+ // angles are in degrees. Switch to radians
+ rx = deg2rad(rx);
+ ry = deg2rad(ry);
+ rz = deg2rad(rz);
+
+ TransformationMatrix mat;
+
+ rz /= 2.0f;
+ double sinA = sin(rz);
+ double cosA = cos(rz);
+ double sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 2.0f * sinA * cosA;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ TransformationMatrix rmat(mat);
+
+ ry /= 2.0f;
+ sinA = sin(ry);
+ cosA = cos(ry);
+ sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = -2.0f * sinA * cosA;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f;
+ mat.m_matrix[1][2] = 0.0f;
+ mat.m_matrix[2][0] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][1] = 0.0f;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ rmat.multLeft(mat);
+
+ rx /= 2.0f;
+ sinA = sin(rx);
+ cosA = cos(rx);
+ sinA2 = sinA * sinA;
+
+ mat.m_matrix[0][0] = 1.0f;
+ mat.m_matrix[0][1] = 0.0f;
+ mat.m_matrix[0][2] = 0.0f;
+ mat.m_matrix[1][0] = 0.0f;
+ mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[1][2] = 2.0f * sinA * cosA;
+ mat.m_matrix[2][0] = 0.0f;
+ mat.m_matrix[2][1] = -2.0f * sinA * cosA;
+ mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
+ mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
+ mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
+ mat.m_matrix[3][3] = 1.0f;
+
+ rmat.multLeft(mat);
+
+ multLeft(rmat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
+{
+ // FIXME: optimize to avoid matrix copy
+ TransformationMatrix mat;
+ mat.m_matrix[3][0] = tx;
+ mat.m_matrix[3][1] = ty;
+
+ multLeft(mat);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz)
{
- double srA[9], srB[9];
+ // FIXME: optimize to avoid matrix copy
+ TransformationMatrix mat;
+ mat.m_matrix[3][0] = tx;
+ mat.m_matrix[3][1] = ty;
+ mat.m_matrix[3][2] = tz;
- affineTransformDecompose(from, srA);
- affineTransformDecompose(*this, srB);
+ multLeft(mat);
+ return *this;
+}
- // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
- if ((srA[0] < 0.0 && srB[1] < 0.0) || (srA[1] < 0.0 && srB[0] < 0.0)) {
- srA[0] = -srA[0];
- srA[1] = -srA[1];
- srA[2] += srA[2] < 0 ? piDouble : -piDouble;
+TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty)
+{
+ if (tx != 0) {
+ m_matrix[0][0] += m_matrix[0][3] * tx;
+ m_matrix[1][0] += m_matrix[1][3] * tx;
+ m_matrix[2][0] += m_matrix[2][3] * tx;
+ m_matrix[3][0] += m_matrix[3][3] * tx;
}
- // Don't rotate the long way around.
- srA[2] = fmod(srA[2], 2.0 * piDouble);
- srB[2] = fmod(srB[2], 2.0 * piDouble);
+ if (ty != 0) {
+ m_matrix[0][1] += m_matrix[0][3] * ty;
+ m_matrix[1][1] += m_matrix[1][3] * ty;
+ m_matrix[2][1] += m_matrix[2][3] * ty;
+ m_matrix[3][1] += m_matrix[3][3] * ty;
+ }
- if (fabs(srA[2] - srB[2]) > piDouble) {
- if (srA[2] > srB[2])
- srA[2] -= piDouble * 2.0;
- else
- srB[2] -= piDouble * 2.0;
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz)
+{
+ translateRight(tx, ty);
+ if (tz != 0) {
+ m_matrix[0][2] += m_matrix[0][3] * tz;
+ m_matrix[1][2] += m_matrix[1][3] * tz;
+ m_matrix[2][2] += m_matrix[2][3] * tz;
+ m_matrix[3][2] += m_matrix[3][3] * tz;
}
- for (int i = 0; i < 9; i++)
- srA[i] = srA[i] + progress * (srB[i] - srA[i]);
+ return *this;
+}
+
+TransformationMatrix& TransformationMatrix::skew(double sx, double sy)
+{
+ // angles are in degrees. Switch to radians
+ sx = deg2rad(sx);
+ sy = deg2rad(sy);
+
+ TransformationMatrix mat;
+ mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row
+ mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row
+
+ multLeft(mat);
+ return *this;
+}
- affineTransformCompose(*this, srA);
+TransformationMatrix& TransformationMatrix::applyPerspective(double p)
+{
+ TransformationMatrix mat;
+ if (p != 0)
+ mat.m_matrix[2][3] = -1/p;
+
+ multLeft(mat);
+ return *this;
+}
+
+//
+// *this = mat * *this
+//
+TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix& mat)
+{
+ Matrix4 tmp;
+
+ tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0]
+ + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]);
+ tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1]
+ + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]);
+ tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2]
+ + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]);
+ tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3]
+ + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]);
+
+ tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0]
+ + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]);
+ tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1]
+ + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]);
+ tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2]
+ + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]);
+ tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3]
+ + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]);
+
+ tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0]
+ + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]);
+ tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1]
+ + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]);
+ tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2]
+ + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]);
+ tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3]
+ + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]);
+
+ tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0]
+ + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]);
+ tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1]
+ + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]);
+ tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2]
+ + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]);
+ tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3]
+ + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]);
+
+ setMatrix(tmp);
+ return *this;
+}
+
+void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const
+{
+ resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0];
+ resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1];
+ double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3];
+ if (w != 1 && w != 0) {
+ resultX /= w;
+ resultY /= w;
+ }
+}
+
+void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const
+{
+ resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
+ resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
+ resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2];
+ double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3];
+ if (w != 1 && w != 0) {
+ resultX /= w;
+ resultY /= w;
+ resultZ /= w;
+ }
+}
+
+bool TransformationMatrix::isInvertible() const
+{
+ double det = WebCore::determinant4x4(m_matrix);
+
+ if (fabs(det) < SMALL_NUMBER)
+ return false;
+
+ return true;
+}
+
+TransformationMatrix TransformationMatrix::inverse() const
+{
+ TransformationMatrix invMat;
+
+ bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix);
+ if (!inverted)
+ return TransformationMatrix();
+
+ return invMat;
+}
+
+void TransformationMatrix::makeAffine()
+{
+ m_matrix[0][2] = 0;
+ m_matrix[0][3] = 0;
+
+ 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][2] = 0;
+ m_matrix[3][3] = 1;
+}
+
+static inline void blendFloat(double& from, double to, double progress)
+{
+ if (from != to)
+ from = from + (to - from) * progress;
+}
+
+void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
+{
+ if (from.isIdentity() && isIdentity())
+ return;
+
+ // decompose
+ DecomposedType fromDecomp;
+ DecomposedType toDecomp;
+ from.decompose(fromDecomp);
+ decompose(toDecomp);
+
+ // interpolate
+ blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
+ blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
+ blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress);
+ blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress);
+ blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress);
+ blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress);
+ blendFloat(fromDecomp.translateX, toDecomp.translateX, progress);
+ blendFloat(fromDecomp.translateY, toDecomp.translateY, progress);
+ blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress);
+ blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress);
+ blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress);
+ blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress);
+ blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress);
+
+ slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress);
+
+ // recompose
+ recompose(fromDecomp);
+}
+
+bool TransformationMatrix::decompose(DecomposedType& decomp) const
+{
+ if (isIdentity()) {
+ memset(&decomp, 0, sizeof(decomp));
+ decomp.perspectiveW = 1;
+ decomp.scaleX = 1;
+ decomp.scaleY = 1;
+ decomp.scaleZ = 1;
+ }
+
+ if (!WebCore::decompose(m_matrix, decomp))
+ return false;
+ return true;
+}
+
+void TransformationMatrix::recompose(const DecomposedType& decomp)
+{
+ makeIdentity();
+
+ // first apply perspective
+ m_matrix[0][3] = (float) decomp.perspectiveX;
+ m_matrix[1][3] = (float) decomp.perspectiveY;
+ m_matrix[2][3] = (float) decomp.perspectiveZ;
+ m_matrix[3][3] = (float) decomp.perspectiveW;
+
+ // now translate
+ translate3d((float) decomp.translateX, (float) decomp.translateY, (float) decomp.translateZ);
+
+ // apply rotation
+ double xx = decomp.quaternionX * decomp.quaternionX;
+ double xy = decomp.quaternionX * decomp.quaternionY;
+ double xz = decomp.quaternionX * decomp.quaternionZ;
+ double xw = decomp.quaternionX * decomp.quaternionW;
+ double yy = decomp.quaternionY * decomp.quaternionY;
+ double yz = decomp.quaternionY * decomp.quaternionZ;
+ double yw = decomp.quaternionY * decomp.quaternionW;
+ double zz = decomp.quaternionZ * decomp.quaternionZ;
+ double zw = decomp.quaternionZ * decomp.quaternionW;
+
+ // Construct a composite rotation matrix from the quaternion values
+ TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0,
+ 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
+ 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
+ 0, 0, 0, 1);
+
+ multLeft(rotationMatrix);
+
+ // now apply skew
+ if (decomp.skewYZ) {
+ TransformationMatrix tmp;
+ tmp.setM32((float) decomp.skewYZ);
+ multLeft(tmp);
+ }
+
+ if (decomp.skewXZ) {
+ TransformationMatrix tmp;
+ tmp.setM31((float) decomp.skewXZ);
+ multLeft(tmp);
+ }
+
+ if (decomp.skewXY) {
+ TransformationMatrix tmp;
+ tmp.setM21((float) decomp.skewXY);
+ multLeft(tmp);
+ }
+
+ // finally, apply scale
+ scale3d((float) decomp.scaleX, (float) decomp.scaleY, (float) decomp.scaleZ);
}
}
diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h
index db121d1..62e4eb8 100644
--- a/WebCore/platform/graphics/transforms/TransformationMatrix.h
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h
@@ -28,112 +28,293 @@
#if PLATFORM(CG)
#include <CoreGraphics/CGAffineTransform.h>
-typedef CGAffineTransform PlatformTransformationMatrix;
-#elif PLATFORM(QT)
-#include <QMatrix>
-typedef QMatrix PlatformTransformationMatrix;
#elif PLATFORM(CAIRO)
#include <cairo.h>
-typedef cairo_matrix_t PlatformTransformationMatrix;
+#elif PLATFORM(QT)
+#include <QTransform>
#elif PLATFORM(SKIA) || PLATFORM(SGL)
-#include "SkMatrix.h"
-typedef SkMatrix PlatformTransformationMatrix;
+#include <SkMatrix.h>
#elif PLATFORM(WX) && USE(WXGC)
-#include <wx/defs.h>
#include <wx/graphics.h>
-typedef wxGraphicsMatrix PlatformTransformationMatrix;
#endif
+#include <string.h> //for memcpy
+
namespace WebCore {
class IntPoint;
class IntRect;
class FloatPoint;
+class FloatPoint3D;
class FloatRect;
class FloatQuad;
class TransformationMatrix {
public:
- TransformationMatrix();
- TransformationMatrix(double a, double b, double c, double d, double e, double f);
-#if !PLATFORM(WX) || USE(WXGC)
- TransformationMatrix(const PlatformTransformationMatrix&);
-#endif
+ typedef double Matrix4[4][4];
- void setMatrix(double a, double b, double c, double d, double e, double f);
- void map(double x, double y, double *x2, double *y2) const;
+ TransformationMatrix() { makeIdentity(); }
+ TransformationMatrix(const TransformationMatrix& t) { *this = t; }
+ TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); }
+ TransformationMatrix(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44)
+ {
+ setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
+ }
- // Rounds the mapped point to the nearest integer value.
- IntPoint mapPoint(const IntPoint&) const;
+ void setMatrix(double a, double b, double c, double d, double e, double f)
+ {
+ m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0;
+ m_matrix[1][0] = c; m_matrix[1][1] = d; 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][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1;
+ }
+
+ void setMatrix(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44)
+ {
+ m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14;
+ m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24;
+ m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34;
+ m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44;
+ }
+
+ TransformationMatrix& operator =(const TransformationMatrix &t)
+ {
+ setMatrix(t.m_matrix);
+ return *this;
+ }
+
+ TransformationMatrix& makeIdentity()
+ {
+ setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ return *this;
+ }
+
+ bool isIdentity() 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][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1;
+ }
+
+ // This form preserves the double math from input to output
+ void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); }
+ // Map a 3D point through the transform, returning a 3D point.
+ FloatPoint3D mapPoint(const FloatPoint3D&) const;
+
+ // Map a 2D point through the transform, returning a 2D point.
+ // Note that this ignores the z component, effectively projecting the point into the z=0 plane.
FloatPoint mapPoint(const FloatPoint&) const;
+ // Like the version above, except that it rounds the mapped point to the nearest integer value.
+ IntPoint mapPoint(const IntPoint&) const;
+
+ // If the matrix has 3D components, the z component of the result is
+ // dropped, effectively projecting the rect into the z=0 plane
+ FloatRect mapRect(const FloatRect&) const;
+
// Rounds the resulting mapped rectangle out. This is helpful for bounding
// box computations but may not be what is wanted in other contexts.
IntRect mapRect(const IntRect&) const;
- FloatRect mapRect(const FloatRect&) const;
-
+ // If the matrix has 3D components, the z component of the result is
+ // dropped, effectively projecting the quad into the z=0 plane
FloatQuad mapQuad(const FloatQuad&) const;
- bool isIdentity() const;
+ // Map a point on the z=0 plane into a point on
+ // the plane with with the transform applied, by extending
+ // a ray perpendicular to the source plane and computing
+ // the local x,y position of the point where that ray intersects
+ // with the destination plane.
+ FloatPoint projectPoint(const FloatPoint&) const;
+ // Projects the four corners of the quad
+ FloatQuad projectQuad(const FloatQuad&) const;
- double a() const;
- void setA(double a);
+ double m11() const { return m_matrix[0][0]; }
+ void setM11(double f) { m_matrix[0][0] = f; }
+ double m12() const { return m_matrix[0][1]; }
+ void setM12(double f) { m_matrix[0][1] = f; }
+ double m13() const { return m_matrix[0][2]; }
+ void setM13(double f) { m_matrix[0][2] = f; }
+ double m14() const { return m_matrix[0][3]; }
+ void setM14(double f) { m_matrix[0][3] = f; }
+ double m21() const { return m_matrix[1][0]; }
+ void setM21(double f) { m_matrix[1][0] = f; }
+ double m22() const { return m_matrix[1][1]; }
+ void setM22(double f) { m_matrix[1][1] = f; }
+ double m23() const { return m_matrix[1][2]; }
+ void setM23(double f) { m_matrix[1][2] = f; }
+ double m24() const { return m_matrix[1][3]; }
+ void setM24(double f) { m_matrix[1][3] = f; }
+ double m31() const { return m_matrix[2][0]; }
+ void setM31(double f) { m_matrix[2][0] = f; }
+ double m32() const { return m_matrix[2][1]; }
+ void setM32(double f) { m_matrix[2][1] = f; }
+ double m33() const { return m_matrix[2][2]; }
+ void setM33(double f) { m_matrix[2][2] = f; }
+ double m34() const { return m_matrix[2][3]; }
+ void setM34(double f) { m_matrix[2][3] = f; }
+ double m41() const { return m_matrix[3][0]; }
+ void setM41(double f) { m_matrix[3][0] = f; }
+ double m42() const { return m_matrix[3][1]; }
+ void setM42(double f) { m_matrix[3][1] = f; }
+ double m43() const { return m_matrix[3][2]; }
+ void setM43(double f) { m_matrix[3][2] = f; }
+ double m44() const { return m_matrix[3][3]; }
+ void setM44(double f) { m_matrix[3][3] = f; }
+
+ double a() const { return m_matrix[0][0]; }
+ void setA(double a) { m_matrix[0][0] = a; }
- double b() const;
- void setB(double b);
+ double b() const { return m_matrix[0][1]; }
+ void setB(double b) { m_matrix[0][1] = b; }
- double c() const;
- void setC(double c);
+ double c() const { return m_matrix[1][0]; }
+ void setC(double c) { m_matrix[1][0] = c; }
- double d() const;
- void setD(double d);
+ double d() const { return m_matrix[1][1]; }
+ void setD(double d) { m_matrix[1][1] = d; }
- double e() const;
- void setE(double e);
+ double e() const { return m_matrix[3][0]; }
+ void setE(double e) { m_matrix[3][0] = e; }
- double f() const;
- void setF(double f);
+ double f() const { return m_matrix[3][1]; }
+ void setF(double f) { m_matrix[3][1] = f; }
- void reset();
+ // this = this * mat
+ TransformationMatrix& multiply(const TransformationMatrix& t) { return *this *= t; }
- TransformationMatrix& multiply(const TransformationMatrix&);
+ // this = mat * this
+ TransformationMatrix& multLeft(const TransformationMatrix& mat);
+
TransformationMatrix& scale(double);
- TransformationMatrix& scale(double sx, double sy);
TransformationMatrix& scaleNonUniform(double sx, double sy);
- TransformationMatrix& rotate(double d);
+ TransformationMatrix& scale3d(double sx, double sy, double sz);
+
+ TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); }
TransformationMatrix& rotateFromVector(double x, double y);
+ TransformationMatrix& rotate3d(double rx, double ry, double rz);
+
+ // The vector (x,y,z) is normalized if it's not already. A vector of
+ // (0,0,0) uses a vector of (0,0,1).
+ TransformationMatrix& rotate3d(double x, double y, double z, double angle);
+
TransformationMatrix& translate(double tx, double ty);
- TransformationMatrix& shear(double sx, double sy);
+ TransformationMatrix& translate3d(double tx, double ty, double tz);
+
+ // translation added with a post-multiply
+ TransformationMatrix& translateRight(double tx, double ty);
+ TransformationMatrix& translateRight3d(double tx, double ty, double tz);
+
TransformationMatrix& flipX();
TransformationMatrix& flipY();
TransformationMatrix& skew(double angleX, double angleY);
- TransformationMatrix& skewX(double angle);
- TransformationMatrix& skewY(double angle);
+ TransformationMatrix& skewX(double angle) { return skew(angle, 0); }
+ TransformationMatrix& skewY(double angle) { return skew(0, angle); }
+
+ TransformationMatrix& applyPerspective(double p);
+ bool hasPerspective() const { return m_matrix[2][3] != 0.0f; }
- double det() const;
bool isInvertible() const;
+
+ // This method returns the identity matrix if it is not invertible.
+ // Use isInvertible() before calling this if you need to know.
TransformationMatrix inverse() const;
+ // decompose the matrix into its component parts
+ typedef struct {
+ double scaleX, scaleY, scaleZ;
+ double skewXY, skewXZ, skewYZ;
+ double quaternionX, quaternionY, quaternionZ, quaternionW;
+ double translateX, translateY, translateZ;
+ double perspectiveX, perspectiveY, perspectiveZ, perspectiveW;
+ } DecomposedType;
+
+ bool decompose(DecomposedType& decomp) const;
+ void recompose(const DecomposedType& decomp);
+
void blend(const TransformationMatrix& from, double progress);
-#if !PLATFORM(WX) || USE(WXGC)
- operator PlatformTransformationMatrix() const;
-#endif
+ bool isAffine() const
+ {
+ return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 &&
+ m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1);
+ }
+
+ // Throw away the non-affine parts of the matrix (lossy!)
+ void makeAffine();
+
+ bool operator==(const TransformationMatrix& m2) const
+ {
+ return (m_matrix[0][0] == m2.m_matrix[0][0] &&
+ m_matrix[0][1] == m2.m_matrix[0][1] &&
+ m_matrix[0][2] == m2.m_matrix[0][2] &&
+ m_matrix[0][3] == m2.m_matrix[0][3] &&
+ m_matrix[1][0] == m2.m_matrix[1][0] &&
+ m_matrix[1][1] == m2.m_matrix[1][1] &&
+ m_matrix[1][2] == m2.m_matrix[1][2] &&
+ m_matrix[1][3] == m2.m_matrix[1][3] &&
+ m_matrix[2][0] == m2.m_matrix[2][0] &&
+ m_matrix[2][1] == m2.m_matrix[2][1] &&
+ m_matrix[2][2] == m2.m_matrix[2][2] &&
+ m_matrix[2][3] == m2.m_matrix[2][3] &&
+ m_matrix[3][0] == m2.m_matrix[3][0] &&
+ m_matrix[3][1] == m2.m_matrix[3][1] &&
+ m_matrix[3][2] == m2.m_matrix[3][2] &&
+ m_matrix[3][3] == m2.m_matrix[3][3]);
+ }
- bool operator==(const TransformationMatrix&) const;
bool operator!=(const TransformationMatrix& other) const { return !(*this == other); }
- TransformationMatrix& operator*=(const TransformationMatrix&);
- TransformationMatrix operator*(const TransformationMatrix&);
+
+ // *this = *this * t (i.e., a multRight)
+ TransformationMatrix& operator*=(const TransformationMatrix& t)
+ {
+ *this = *this * t;
+ return *this;
+ }
+
+ // result = *this * t (i.e., a multRight)
+ TransformationMatrix operator*(const TransformationMatrix& t)
+ {
+ TransformationMatrix result = t;
+ result.multLeft(*this);
+ return result;
+ }
-private:
-#if !PLATFORM(WX) || USE(WXGC)
- PlatformTransformationMatrix m_transform;
+#if PLATFORM(CG)
+ operator CGAffineTransform() const;
+#elif PLATFORM(CAIRO)
+ operator cairo_matrix_t() const;
+#elif PLATFORM(QT)
+ operator QTransform() const;
+#elif PLATFORM(SKIA) || PLATFORM(SGL)
+ operator SkMatrix() const;
+#elif PLATFORM(WX) && USE(WXGC)
+ operator wxGraphicsMatrix() const;
#endif
-};
-TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest);
+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));
+ }
+
+ Matrix4 m_matrix;
+};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp b/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
index 47471c4..a8ad131 100644
--- a/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
@@ -30,12 +30,15 @@ PassRefPtr<TransformOperation> TranslateTransformOperation::blend(const Transfor
return this;
if (blendToIdentity)
- return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress), Length(m_y.type()).blend(m_y, progress), m_type);
+ return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress),
+ Length(m_y.type()).blend(m_y, progress),
+ Length(m_z.type()).blend(m_z, progress), m_type);
const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from);
Length fromX = fromOp ? fromOp->m_x : Length(m_x.type());
Length fromY = fromOp ? fromOp->m_y : Length(m_y.type());
- return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_type);
+ Length fromZ = fromOp ? fromOp->m_z : Length(m_z.type());
+ return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_z.blend(fromZ, progress), m_type);
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
index 61ccbcc..a66cc3d 100644
--- a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
+++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
@@ -34,10 +34,21 @@ class TranslateTransformOperation : public TransformOperation {
public:
static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, OperationType type)
{
- return adoptRef(new TranslateTransformOperation(tx, ty, type));
+ return adoptRef(new TranslateTransformOperation(tx, ty, Length(0, Fixed), type));
}
- virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0; }
+ static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, const Length& tz, OperationType type)
+ {
+ return adoptRef(new TranslateTransformOperation(tx, ty, tz, type));
+ }
+
+ double x(const IntSize& borderBoxSize) const { return m_x.calcFloatValue(borderBoxSize.width()); }
+ double y(const IntSize& borderBoxSize) const { return m_y.calcFloatValue(borderBoxSize.height()); }
+ double z(const IntSize&) const { return m_z.calcFloatValue(1); }
+
+private:
+ virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0 && m_z.calcFloatValue(1) == 0; }
+
virtual OperationType getOperationType() const { return m_type; }
virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
@@ -46,27 +57,29 @@ public:
if (!isSameType(o))
return false;
const TranslateTransformOperation* t = static_cast<const TranslateTransformOperation*>(&o);
- return m_x == t->m_x && m_y == t->m_y;
+ return m_x == t->m_x && m_y == t->m_y && m_z == t->m_z;
}
virtual bool apply(TransformationMatrix& transform, const IntSize& borderBoxSize) const
{
- transform.translate(m_x.calcFloatValue(borderBoxSize.width()), m_y.calcFloatValue(borderBoxSize.height()));
+ transform.translate3d(x(borderBoxSize), y(borderBoxSize), z(borderBoxSize));
return m_x.type() == Percent || m_y.type() == Percent;
}
virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
-private:
- TranslateTransformOperation(const Length& tx, const Length& ty, OperationType type)
+ TranslateTransformOperation(const Length& tx, const Length& ty, const Length& tz, OperationType type)
: m_x(tx)
, m_y(ty)
+ , m_z(tz)
, m_type(type)
{
+ ASSERT(type == TRANSLATE_X || type == TRANSLATE_Y || type == TRANSLATE_Z || type == TRANSLATE || type == TRANSLATE_3D);
}
Length m_x;
Length m_y;
+ Length m_z;
OperationType m_type;
};
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
index 9ca95f3..feeb2ae 100644
--- a/WebCore/platform/graphics/win/FontCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -223,8 +223,6 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData
ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
}
} else {
- RetainPtr<CGMutablePathRef> path(AdoptCF, CGPathCreateMutable());
-
XFORM xform;
GetWorldTransform(hdc, &xform);
TransformationMatrix hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy);
@@ -233,16 +231,8 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData
initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0));
initialGlyphTransform.tx = 0;
initialGlyphTransform.ty = 0;
- CGAffineTransform glyphTranslation = CGAffineTransformIdentity;
-
- for (unsigned i = 0; i < numGlyphs; ++i) {
- RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
- CGAffineTransform glyphTransform = CGAffineTransformConcat(initialGlyphTransform, glyphTranslation);
- CGPathAddPath(path.get(), &glyphTransform, glyphPath.get());
- glyphTranslation = CGAffineTransformTranslate(glyphTranslation, gdiAdvances[i], 0);
- }
-
CGContextRef cgContext = graphicsContext->platformContext();
+
CGContextSaveGState(cgContext);
BOOL fontSmoothingEnabled = false;
@@ -252,26 +242,36 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData
CGContextScaleCTM(cgContext, 1.0, -1.0);
CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height()));
- if (drawingMode & cTextFill) {
- CGContextAddPath(cgContext, path.get());
- CGContextFillPath(cgContext);
- if (font->m_syntheticBoldOffset) {
- CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
- CGContextAddPath(cgContext, path.get());
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
+ CGContextSaveGState(cgContext);
+ CGContextConcatCTM(cgContext, initialGlyphTransform);
+
+ if (drawingMode & cTextFill) {
+ CGContextAddPath(cgContext, glyphPath.get());
CGContextFillPath(cgContext);
- CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ if (font->m_syntheticBoldOffset) {
+ CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextFillPath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ }
}
- }
- if (drawingMode & cTextStroke) {
- CGContextAddPath(cgContext, path.get());
- CGContextStrokePath(cgContext);
- if (font->m_syntheticBoldOffset) {
- CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
- CGContextAddPath(cgContext, path.get());
+ if (drawingMode & cTextStroke) {
+ CGContextAddPath(cgContext, glyphPath.get());
CGContextStrokePath(cgContext);
- CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ if (font->m_syntheticBoldOffset) {
+ CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
+ CGContextAddPath(cgContext, glyphPath.get());
+ CGContextStrokePath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ }
}
+
+ CGContextRestoreGState(cgContext);
+ CGContextTranslateCTM(cgContext, gdiAdvances[i], 0);
}
+
CGContextRestoreGState(cgContext);
}
@@ -298,8 +298,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();
if (font->platformData().useGDI()) {
- static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs();
- if (!canUsePlatformNativeGlyphs || !shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) {
+ if (!shouldUseFontSmoothing || (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 9acc5a0..887bf79 100644
--- a/WebCore/platform/graphics/win/FontCacheWin.cpp
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -422,7 +422,24 @@ static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool
matchData.m_chosen.lfQuality = DEFAULT_QUALITY;
matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- return CreateFontIndirect(&matchData.m_chosen);
+ HFONT result = CreateFontIndirect(&matchData.m_chosen);
+ if (!result)
+ return 0;
+
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ SelectObject(dc, result);
+ WCHAR actualName[LF_FACESIZE];
+ GetTextFace(dc, LF_FACESIZE, actualName);
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+
+ if (wcsicmp(matchData.m_chosen.lfFaceName, actualName)) {
+ DeleteObject(result);
+ result = 0;
+ }
+
+ return result;
}
struct TraitsInFamilyProcData {
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
index ba8afe7..1ac3359 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -65,10 +65,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
ASSERT(m_fontReference);
ASSERT(T2embedLibrary());
- static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs();
- LOGFONT _logFont;
-
- LOGFONT& logFont = canUsePlatformNativeGlyphs ? *static_cast<LOGFONT*>(malloc(sizeof(LOGFONT))) : _logFont;
+ LOGFONT& logFont = *static_cast<LOGFONT*>(malloc(sizeof(LOGFONT)));
if (m_name.isNull())
TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0);
else
@@ -90,8 +87,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
logFont.lfWeight = bold ? 700 : 400;
HFONT hfont = CreateFontIndirect(&logFont);
- if (canUsePlatformNativeGlyphs)
- wkSetFontPlatformInfo(m_cgFont, &logFont, free);
+ wkSetFontPlatformInfo(m_cgFont, &logFont, free);
return FontPlatformData(hfont, m_cgFont, size, bold, italic, renderingMode == AlternateRenderingMode);
}
@@ -120,7 +116,7 @@ size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count)
// Streams the concatenation of a header and font data.
class EOTStream {
public:
- EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
+ EOTStream(const Vector<uint8_t, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
: m_eotHeader(eotHeader)
, m_fontData(fontData)
, m_overlayDst(overlayDst)
@@ -134,7 +130,7 @@ public:
size_t read(void* buffer, size_t count);
private:
- const Vector<UInt8, 512>& m_eotHeader;
+ const Vector<uint8_t, 512>& m_eotHeader;
const SharedBuffer* m_fontData;
size_t m_overlayDst;
size_t m_overlaySrc;
@@ -210,7 +206,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
// TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, so we need to create an EOT header
// and prepend it to the font data.
- Vector<UInt8, 512> eotHeader;
+ Vector<uint8_t, 512> eotHeader;
size_t overlayDst;
size_t overlaySrc;
size_t overlayLength;
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
index c7e59ab..59f7e5c 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -120,7 +120,7 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR*
ASSERT(m_cgFont);
}
}
- if (m_useGDI && wkCanUsePlatformNativeGlyphs()) {
+ if (m_useGDI) {
LOGFONT* logfont = static_cast<LOGFONT*>(malloc(sizeof(LOGFONT)));
GetObject(font, sizeof(*logfont), logfont);
wkSetFontPlatformInfo(m_cgFont.get(), logfont, free);
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index dccbe6c..da5b503 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -76,8 +76,6 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
}
}
-bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
-
// FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into a single API
// suitable for all clients?
HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
@@ -173,16 +171,6 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
m_data->restore();
}
-void GraphicsContext::setShouldIncludeChildWindows(bool include)
-{
- m_data->m_shouldIncludeChildWindows = include;
-}
-
-bool GraphicsContext::shouldIncludeChildWindows() const
-{
- return m_data->m_shouldIncludeChildWindows;
-}
-
GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
: m_hdc(0)
, m_size(size)
@@ -265,7 +253,7 @@ void GraphicsContext::drawFocusRing(const Color& color)
float radius = (focusRingWidth() - 1) / 2.0f;
int offset = radius + focusRingOffset();
- CGColorRef colorRef = color.isValid() ? cgColor(color) : 0;
+ CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0;
CGMutablePathRef focusRingPath = CGPathCreateMutable();
const Vector<IntRect>& rects = focusRingRects();
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
index 892d24a..1980d18 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -87,8 +87,6 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
return hdc;
}
-bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
-
void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
// FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs
diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
index b3ebcb0..e4c5b04 100644
--- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -43,6 +43,18 @@ namespace WebCore {
class SVGResourceImage;
+bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
+
+void GraphicsContext::setShouldIncludeChildWindows(bool include)
+{
+ m_data->m_shouldIncludeChildWindows = include;
+}
+
+bool GraphicsContext::shouldIncludeChildWindows() const
+{
+ return m_data->m_shouldIncludeChildWindows;
+}
+
void GraphicsContextPlatformPrivate::save()
{
if (!m_hdc)
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index 1b09e1f..c293f49 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -32,7 +32,10 @@
#include "KURL.h"
#include "QTMovieWin.h"
#include "ScrollView.h"
+#include "StringHash.h"
+#include <wtf/HashSet.h>
#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
#if DRAW_FRAME_RATE
#include "Font.h"
@@ -48,16 +51,25 @@ using namespace std;
namespace WebCore {
-static const double endPointTimerInterval = 0.020;
-
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
: m_player(player)
, m_seekTo(-1)
, m_endTime(numeric_limits<float>::infinity())
, m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
- , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired)
, m_networkState(MediaPlayer::Empty)
- , m_readyState(MediaPlayer::DataUnavailable)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_enabledTrackCount(0)
, m_startedPlaying(false)
, m_isStreaming(false)
#if DRAW_FRAME_RATE
@@ -75,7 +87,8 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
void MediaPlayerPrivate::load(const String& url)
{
if (!QTMovieWin::initializeQuickTime()) {
- m_networkState = MediaPlayer::LoadFailed;
+ // FIXME: is this the right error to return?
+ m_networkState = MediaPlayer::DecodeError;
m_player->networkStateChanged();
return;
}
@@ -84,17 +97,16 @@ void MediaPlayerPrivate::load(const String& url)
m_networkState = MediaPlayer::Loading;
m_player->networkStateChanged();
}
- if (m_readyState != MediaPlayer::DataUnavailable) {
- m_readyState = MediaPlayer::DataUnavailable;
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
m_player->readyStateChanged();
}
cancelSeek();
- m_endPointTimer.stop();
m_qtMovie.set(new QTMovieWin(this));
m_qtMovie->load(url.characters(), url.length());
- m_qtMovie->setVolume(m_player->m_volume);
- m_qtMovie->setVisible(m_player->m_visible);
+ m_qtMovie->setVolume(m_player->volume());
+ m_qtMovie->setVisible(m_player->visible());
}
void MediaPlayerPrivate::play()
@@ -107,7 +119,6 @@ void MediaPlayerPrivate::play()
#endif
m_qtMovie->play();
- startEndPointTimerIfNeeded();
}
void MediaPlayerPrivate::pause()
@@ -119,7 +130,6 @@ void MediaPlayerPrivate::pause()
m_timeStoppedPlaying = GetTickCount();
#endif
m_qtMovie->pause();
- m_endPointTimer.stop();
}
float MediaPlayerPrivate::duration() const
@@ -156,11 +166,12 @@ void MediaPlayerPrivate::seek(float time)
void MediaPlayerPrivate::doSeek()
{
float oldRate = m_qtMovie->rate();
- m_qtMovie->setRate(0);
+ if (oldRate)
+ m_qtMovie->setRate(0);
m_qtMovie->setCurrentTime(m_seekTo);
float timeAfterSeek = currentTime();
// restore playback only if not at end, othewise QTMovie will loop
- if (timeAfterSeek < duration() && timeAfterSeek < m_endTime)
+ if (oldRate && timeAfterSeek < duration() && timeAfterSeek < m_endTime)
m_qtMovie->setRate(oldRate);
cancelSeek();
}
@@ -195,22 +206,6 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
void MediaPlayerPrivate::setEndTime(float time)
{
m_endTime = time;
- startEndPointTimerIfNeeded();
-}
-
-void MediaPlayerPrivate::startEndPointTimerIfNeeded()
-{
- if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive())
- m_endPointTimer.startRepeating(endPointTimerInterval);
-}
-
-void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
-{
- float time = currentTime();
- if (time >= m_endTime) {
- pause();
- didEnd();
- }
}
bool MediaPlayerPrivate::paused() const
@@ -325,42 +320,44 @@ void MediaPlayerPrivate::updateStates()
long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;
- if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData && !m_player->inMediaDocument()) {
- unsigned enabledTrackCount;
- m_qtMovie->disableUnsupportedTracks(enabledTrackCount);
- // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>
- if (!enabledTrackCount)
+ if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) {
+ m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount);
+ if (!m_enabledTrackCount)
loadState = QTMovieLoadStateError;
}
// "Loaded" is reserved for fully buffered movies, never the case when streaming
if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
- if (m_networkState < MediaPlayer::Loaded)
- m_networkState = MediaPlayer::Loaded;
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (loadState >= QTMovieLoadStatePlaythroughOK) {
- if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
- m_networkState = MediaPlayer::LoadedFirstFrame;
- m_readyState = MediaPlayer::CanPlayThrough;
+ m_readyState = MediaPlayer::HaveEnoughData;
} else if (loadState >= QTMovieLoadStatePlayable) {
- if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
- m_networkState = MediaPlayer::LoadedFirstFrame;
- m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable;
+ // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
} else if (loadState >= QTMovieLoadStateLoaded) {
- if (m_networkState < MediaPlayer::LoadedMetaData)
- m_networkState = MediaPlayer::LoadedMetaData;
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveMetadata;
} else if (loadState > QTMovieLoadStateError) {
- if (m_networkState < MediaPlayer::Loading)
- m_networkState = MediaPlayer::Loading;
- m_readyState = MediaPlayer::DataUnavailable;
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveNothing;
} else {
- m_networkState = MediaPlayer::LoadFailed;
- m_readyState = MediaPlayer::DataUnavailable;
+ float loaded = maxTimeLoaded();
+ if (!loaded)
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (!m_enabledTrackCount)
+ m_networkState = MediaPlayer::FormatError;
+ else {
+ // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
+ if (loaded > 0)
+ m_networkState = MediaPlayer::DecodeError;
+ else
+ m_readyState = MediaPlayer::HaveNothing;
+ }
}
if (seeking())
- m_readyState = MediaPlayer::DataUnavailable;
+ m_readyState = MediaPlayer::HaveNothing;
if (m_networkState != oldNetworkState)
m_player->networkStateChanged();
@@ -371,7 +368,6 @@ void MediaPlayerPrivate::updateStates()
void MediaPlayerPrivate::didEnd()
{
- m_endPointTimer.stop();
m_startedPlaying = false;
#if DRAW_FRAME_RATE
m_timeStoppedPlaying = GetTickCount();
@@ -380,10 +376,10 @@ void MediaPlayerPrivate::didEnd()
m_player->timeChanged();
}
-void MediaPlayerPrivate::setRect(const IntRect& r)
+void MediaPlayerPrivate::setSize(const IntSize& size)
{
if (m_qtMovie)
- m_qtMovie->setSize(r.width(), r.height());
+ m_qtMovie->setSize(size.width(), size.height());
}
void MediaPlayerPrivate::setVisible(bool b)
@@ -403,7 +399,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
#if DRAW_FRAME_RATE
if (m_frameCountWhilePlaying > 10) {
- Frame* frame = m_player->m_frameView ? m_player->m_frameView->frame() : NULL;
+ 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;
@@ -427,16 +423,30 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
#endif
}
-void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+static HashSet<String> mimeTypeCache()
{
- unsigned count = QTMovieWin::countSupportedTypes();
- for (unsigned n = 0; n < count; n++) {
- const UChar* character;
- unsigned len;
- QTMovieWin::getSupportedType(n, character, len);
- if (len)
- types.add(String(character, len));
+ DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ());
+ static bool typeListInitialized = false;
+
+ if (!typeListInitialized) {
+ unsigned count = QTMovieWin::countSupportedTypes();
+ for (unsigned n = 0; n < count; n++) {
+ const UChar* character;
+ unsigned len;
+ QTMovieWin::getSupportedType(n, character, len);
+ if (len)
+ typeCache.add(String(character, len));
+ }
+
+ typeListInitialized = true;
}
+
+ return typeCache;
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ types = mimeTypeCache();
}
bool MediaPlayerPrivate::isAvailable()
@@ -444,6 +454,13 @@ bool MediaPlayerPrivate::isAvailable()
return QTMovieWin::initializeQuickTime();
}
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
+ // extended MIME type
+ return mimeTypeCache().contains(type) ? (!codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+}
+
void MediaPlayerPrivate::movieEnded(QTMovieWin* movie)
{
ASSERT(m_qtMovie.get() == movie);
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
index c4c893c..63aa62b 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
#if ENABLE(VIDEO)
-#include "MediaPlayer.h"
+#include "MediaPlayerPrivate.h"
#include "Timer.h"
#include <QTMovieWin.h>
#include <wtf/OwnPtr.h>
@@ -44,9 +44,10 @@ class IntSize;
class IntRect;
class String;
-class MediaPlayerPrivate : QTMovieWinClient, Noncopyable {
+class MediaPlayerPrivate : public MediaPlayerPrivateInterface, public QTMovieWinClient {
public:
- MediaPlayerPrivate(MediaPlayer*);
+ static void registerMediaEngine(MediaEngineRegistrar);
+
~MediaPlayerPrivate();
IntSize naturalSize() const;
@@ -81,38 +82,42 @@ public:
unsigned totalBytes() const;
void setVisible(bool);
- void setRect(const IntRect&);
+ void setSize(const IntSize&);
void loadStateChanged();
void didEnd();
void paint(GraphicsContext*, const IntRect&);
- static void getSupportedTypes(HashSet<String>& types);
- static bool isAvailable();
private:
+ MediaPlayerPrivate(MediaPlayer*);
+
void updateStates();
void doSeek();
void cancelSeek();
void seekTimerFired(Timer<MediaPlayerPrivate>*);
- void endPointTimerFired(Timer<MediaPlayerPrivate>*);
float maxTimeLoaded() const;
- void startEndPointTimerIfNeeded();
virtual void movieEnded(QTMovieWin*);
virtual void movieLoadStateChanged(QTMovieWin*);
virtual void movieTimeChanged(QTMovieWin*);
virtual void movieNewImageAvailable(QTMovieWin*);
-
+
+ // engine support
+ static MediaPlayerPrivateInterface* create(MediaPlayer*);
+ static void getSupportedTypes(HashSet<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
MediaPlayer* m_player;
OwnPtr<QTMovieWin> m_qtMovie;
float m_seekTo;
float m_endTime;
Timer<MediaPlayerPrivate> m_seekTimer;
- Timer<MediaPlayerPrivate> m_endPointTimer;
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
+ unsigned m_enabledTrackCount;
bool m_startedPlaying;
bool m_isStreaming;
#if DRAW_FRAME_RATE
diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp
index 32aecd3..3f23698 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -658,6 +658,12 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount)
continue;
if (!allowedTrackTypes->contains(mediaType)) {
+
+ // Different mpeg variants import as different track types so check for the "mpeg
+ // characteristic" instead of hard coding the (current) list of mpeg media types.
+ if (GetMovieIndTrackType(m_private->m_movie, 1, 'mpeg', movieTrackCharacteristic | movieTrackEnabledOnly))
+ continue;
+
SetTrackEnabled(currentTrack, false);
--enabledTrackCount;
}
diff --git a/WebCore/platform/graphics/win/QTMovieWinTimer.cpp b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
index d0aa3e6..f6103ea 100644
--- a/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2009 Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,6 +51,9 @@ static LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wPara
processingCustomTimerMessage = true;
sharedTimerFiredFunction();
processingCustomTimerMessage = false;
+ } else if (message == WM_TIMER && wParam == timerID) {
+ stopSharedTimer();
+ sharedTimerFiredFunction();
} else
return DefWindowProc(hWnd, message, wParam, lParam);
return 0;
@@ -79,11 +82,6 @@ void setSharedTimerFiredFunction(void (*f)())
sharedTimerFiredFunction = f;
}
-static void CALLBACK timerFired(HWND, UINT, UINT_PTR, DWORD)
-{
- sharedTimerFiredFunction();
-}
-
void setSharedTimerFireDelay(double interval)
{
ASSERT(sharedTimerFiredFunction);
@@ -99,29 +97,27 @@ void setSharedTimerFireDelay(double interval)
intervalInMS = (unsigned)interval;
}
- if (timerID) {
- KillTimer(0, timerID);
- timerID = 0;
- }
+ stopSharedTimer();
+ initializeOffScreenTimerWindow();
// We don't allow nested PostMessages, since the custom messages will effectively starve
// painting and user input. (Win32 has a tri-level queue with application messages >
// user input > WM_PAINT/WM_TIMER.)
// In addition, if the queue contains input events that have been there since the last call to
// GetQueueStatus, PeekMessage or GetMessage we favor timers.
- if (intervalInMS < USER_TIMER_MINIMUM && processingCustomTimerMessage &&
- !LOWORD(::GetQueueStatus(QS_ALLINPUT))) {
+ if (intervalInMS < USER_TIMER_MINIMUM
+ && !processingCustomTimerMessage
+ && !LOWORD(::GetQueueStatus(QS_ALLINPUT))) {
// Windows SetTimer does not allow timeouts smaller than 10ms (USER_TIMER_MINIMUM)
- initializeOffScreenTimerWindow();
PostMessage(timerWindowHandle, timerFiredMessage, 0, 0);
} else
- timerID = SetTimer(0, 0, intervalInMS, timerFired);
+ timerID = SetTimer(timerWindowHandle, timerFiredMessage, intervalInMS, 0);
}
void stopSharedTimer()
{
if (timerID) {
- KillTimer(0, timerID);
+ KillTimer(timerWindowHandle, timerID);
timerID = 0;
}
}
diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h
index d2394dc..c77968a 100644
--- a/WebCore/platform/graphics/wx/FontPlatformData.h
+++ b/WebCore/platform/graphics/wx/FontPlatformData.h
@@ -30,41 +30,59 @@
#define FontPlatformData_H
#include "FontDescription.h"
-#include "CString.h"
#include "AtomicString.h"
+#include "CString.h"
#include "StringImpl.h"
+#include <wtf/RefPtr.h>
#include <wx/defs.h>
#include <wx/font.h>
namespace WebCore {
+class FontHolder: public WTF::RefCounted<FontHolder>
+{
+public:
+ FontHolder()
+ : m_font(0)
+ {}
+
+ FontHolder(wxFont* font)
+ : m_font(font)
+ {}
+
+ wxFont* font() { return m_font; }
+
+private:
+ wxFont* m_font;
+};
+
class FontPlatformData {
public:
enum FontState { UNINITIALIZED, DELETED, VALID };
FontPlatformData(WTF::HashTableDeletedValueType)
- : m_fontState(DELETED)
+ : m_fontState(DELETED),
+ m_font(0)
{ }
~FontPlatformData();
- FontPlatformData(wxFont f)
- : m_font(f)
- , m_fontState(VALID)
+ FontPlatformData(const FontDescription&, const AtomicString&);
+ FontPlatformData(float size, bool bold, bool italic)
+ : m_fontState(UNINITIALIZED)
+ , m_font(0)
{
- m_fontHash = computeHash();
}
- FontPlatformData(const FontDescription&, const AtomicString&);
-
FontPlatformData()
: m_fontState(UNINITIALIZED)
+ , m_font(0)
{
}
- wxFont font() const {
- return m_font;
+ wxFont* font() const {
+ return m_font->font();
}
unsigned hash() const {
@@ -78,32 +96,26 @@ public:
}
}
+ unsigned computeHash() const;
+
bool operator==(const FontPlatformData& other) const
{
- if (m_fontState == VALID)
- return other.m_fontState == VALID && m_font.IsOk() && other.m_font.IsOk() && m_font.IsSameAs(other.m_font);
+ if (m_font && m_fontState == VALID && other.m_fontState == VALID && other.m_font) {
+ wxFont* thisFont = m_font->font();
+ wxFont* otherFont = other.m_font->font();
+ return thisFont->IsOk() && otherFont->IsOk() && thisFont->IsSameAs(*otherFont);
+ }
else
return m_fontState == other.m_fontState;
}
bool isHashTableDeletedValue() const { return m_fontState == DELETED; }
- unsigned computeHash() const {
- ASSERT(m_font.IsOk());
-
- // make a hash that is unique for this font, but not globally unique - that is,
- // a font whose properties are equal should generate the same hash
- uintptr_t hashCodes[6] = { m_font.GetPointSize(), m_font.GetFamily(), m_font.GetStyle(),
- m_font.GetWeight(), m_font.GetUnderlined(),
- StringImpl::computeHash(m_font.GetFaceName().mb_str(wxConvUTF8)) };
-
- return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
- }
+
private:
- wxFont m_font;
- FontState m_fontState;
- unsigned m_fontHash;
+ WTF::RefPtr<FontHolder> m_font;
+ FontState m_fontState;
};
}
diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
index 7162eab..ce5e40e 100644
--- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
+++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
@@ -58,6 +58,9 @@ static wxFontWeight fontWeightToWxFontWeight(FontWeight weight)
{
if (weight >= FontWeight600)
return wxFONTWEIGHT_BOLD;
+
+ if (weight <= FontWeight300)
+ return wxFONTWEIGHT_LIGHT;
return wxFONTWEIGHT_NORMAL;
}
@@ -78,30 +81,45 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri
// this is a moot issue on Linux and Mac as they only accept the point argument. So,
// we use the pixel size constructor on Windows, but we use point size on Linux and Mac.
#if __WXMSW__
- m_font = wxFont( wxSize(0, -desc.computedPixelSize()),
+ m_font = new FontHolder(new wxFont( wxSize(0, -desc.computedPixelSize()),
fontFamilyToWxFontFamily(desc.genericFamily()),
italicToWxFontStyle(desc.italic()),
fontWeightToWxFontWeight(desc.weight()),
false,
family.string()
- );
+ )
+ );
#else
- m_font = wxFont( desc.computedPixelSize(),
+ m_font = new FontHolder(new wxFont( desc.computedPixelSize(),
fontFamilyToWxFontFamily(desc.genericFamily()),
italicToWxFontStyle(desc.italic()),
fontWeightToWxFontWeight(desc.weight()),
false,
family.string()
- );
+ )
+ );
#endif
m_fontState = VALID;
- m_fontHash = computeHash();
}
-
+
+unsigned FontPlatformData::computeHash() const {
+ wxFont* thisFont = m_font->font();
+ ASSERT(thisFont && thisFont->IsOk());
+
+ // make a hash that is unique for this font, but not globally unique - that is,
+ // a font whose properties are equal should generate the same hash
+ uintptr_t hashCodes[6] = { thisFont->GetPointSize(), thisFont->GetFamily(), thisFont->GetStyle(),
+ thisFont->GetWeight(), thisFont->GetUnderlined(),
+ StringImpl::computeHash(thisFont->GetFaceName().mb_str(wxConvUTF8)) };
+
+ return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+}
+
FontPlatformData::~FontPlatformData()
{
m_fontState = UNINITIALIZED;
+ m_font = 0;
}
}
diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
index d523354..fc8ce71 100644
--- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
@@ -170,7 +170,7 @@ void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer*
delete m_decoder;
m_decoder = 0;
if (data)
- setData(data, allDataReceived);
+ setData(data, allDataReceived);
}
NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp
index e52e9ff..e1d435e 100644
--- a/WebCore/platform/graphics/wx/ImageWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageWx.cpp
@@ -237,7 +237,7 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c
void BitmapImage::checkForSolidColor()
{
-
+ m_checkedForSolidColor = true;
}
void BitmapImage::invalidatePlatformData()
diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
index a509933..ab50518 100644
--- a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
+++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
@@ -45,14 +45,16 @@ namespace WebCore
void SimpleFontData::platformInit()
{
- wxFont font = m_font.font();
- wxFontProperties props = wxFontProperties(&font);
- m_ascent = props.GetAscent();
- m_descent = props.GetDescent();
- m_lineSpacing = props.GetLineSpacing();
- m_xHeight = props.GetXHeight();
- m_unitsPerEm = 1; // FIXME!
- m_lineGap = props.GetLineGap();
+ wxFont *font = m_font.font();
+ if (font && font->IsOk()) {
+ wxFontProperties props = wxFontProperties(font);
+ m_ascent = props.GetAscent();
+ m_descent = props.GetDescent();
+ m_lineSpacing = props.GetLineSpacing();
+ m_xHeight = props.GetXHeight();
+ m_unitsPerEm = 1; // FIXME!
+ m_lineGap = props.GetLineGap();
+ }
}
void SimpleFontData::platformDestroy()
@@ -79,8 +81,8 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con
void SimpleFontData::determinePitch()
{
- if (m_font.font().Ok())
- m_treatAsFixedPitch = m_font.font().IsFixedWidth();
+ if (m_font.font() && m_font.font()->Ok())
+ m_treatAsFixedPitch = m_font.font()->IsFixedWidth();
else
m_treatAsFixedPitch = false;
}
@@ -89,7 +91,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
// TODO: fix this! Make GetTextExtents a method of wxFont in 2.9
int width = 10;
- GetTextExtent(m_font.font(), (wxChar)glyph, &width, NULL);
+ GetTextExtent(*m_font.font(), (wxChar)glyph, &width, NULL);
return width;
}
diff --git a/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
index e6a02b8..f21dc17 100644
--- a/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
+++ b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
@@ -37,235 +37,14 @@
namespace WebCore {
#if USE(WXGC)
-TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
-{
- m_transform = matrix;
-}
-#endif
-
-TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double e, double f)
-{
-#if USE(WXGC)
- wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
- m_transform = renderer->CreateMatrix();
-#endif
- setMatrix(a, b, c, d, e, f);
-}
-
-TransformationMatrix::TransformationMatrix()
-{
- // NB: If we ever support using Cairo backend on Win/Mac, this will need to be
- // changed somehow (though I'm not sure how as we don't have a reference to the
- // graphics context here.
-#if USE(WXGC)
- wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
- m_transform = renderer->CreateMatrix();
-#endif
-}
-
-TransformationMatrix TransformationMatrix::inverse() const
-{
- notImplemented();
- return *this;
-}
-
-void TransformationMatrix::setMatrix(double a, double b, double c, double d, double e, double f)
-{
-#if USE(WXGC)
- m_transform.Set(a, b, c, d, e, f);
-#endif
-}
-
-void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
-{
- notImplemented();
-}
-
-IntRect TransformationMatrix::mapRect(const IntRect &rect) const
-{
-#if USE(WXGC)
- double x, y, width, height;
- x = rect.x();
- y = rect.y();
- width = rect.width();
- height = rect.height();
-
- m_transform.TransformPoint(&x, &y);
- m_transform.TransformDistance(&width, &height);
- return IntRect(x, y, width, height);
-#endif
- return IntRect();
-}
-
-FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
-{
-#if USE(WXGC)
- double x, y, width, height;
- x = rect.x();
- y = rect.y();
- width = rect.width();
- height = rect.height();
-
- m_transform.TransformPoint(&x, &y);
- m_transform.TransformDistance(&width, &height);
- return FloatRect(x, y, width, height);
-#endif
- return FloatRect();
-}
-
-
-TransformationMatrix& TransformationMatrix::scale(double sx, double sy)
-{
-#if USE(WXGC)
- m_transform.Scale((wxDouble)sx, (wxDouble)sy);
-#endif
- return *this;
-}
-
-void TransformationMatrix::reset()
-{
- notImplemented();
-}
-
-TransformationMatrix& TransformationMatrix::rotate(double d)
-{
-#if USE(WXGC)
- m_transform.Rotate((wxDouble)d);
-#endif
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
-{
-#if USE(WXGC)
- m_transform.Translate((wxDouble)tx, (wxDouble)ty);
-#endif
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::shear(double sx, double sy)
-{
- notImplemented();
- return *this;
-}
-
-TransformationMatrix& TransformationMatrix::operator*=(const TransformationMatrix& other)
-{
- notImplemented();
- return *this;
-}
-
-bool TransformationMatrix::operator== (const TransformationMatrix &other) const
-{
-#if USE(WXGC)
- return m_transform.IsEqual((wxGraphicsMatrix)other);
-#else
- notImplemented();
- return true;
-#endif
-}
-
-TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &other)
-{
- notImplemented();
- return *this; //m_transform * other.m_transform;
-}
-
-double TransformationMatrix::det() const
-{
- notImplemented();
- return 0;
-}
-
-#if USE(WXGC)
TransformationMatrix::operator wxGraphicsMatrix() const
{
- return m_transform;
-}
-#endif
-
-double TransformationMatrix::a() const
-{
- double a = 0;
-#if USE(WXGC)
- m_transform.Get(&a);
-#endif
- return a;
-}
-
-void TransformationMatrix::setA(double a)
-{
- setMatrix(a, b(), c(), d(), e(), f());
-}
-
-double TransformationMatrix::b() const
-{
- double b = 0;
-#if USE(WXGC)
- m_transform.Get(&b);
-#endif
- return b;
-}
-
-void TransformationMatrix::setB(double b)
-{
- setMatrix(a(), b, c(), d(), e(), f());
-}
-
-double TransformationMatrix::c() const
-{
- double c = 0;
-#if USE(WXGC)
- m_transform.Get(&c);
-#endif
- return c;
-}
-
-void TransformationMatrix::setC(double c)
-{
- setMatrix(a(), b(), c, d(), e(), f());
-}
-
-double TransformationMatrix::d() const
-{
- double d = 0;
-#if USE(WXGC)
- m_transform.Get(&d);
-#endif
- return d;
-}
-
-void TransformationMatrix::setD(double d)
-{
- setMatrix(a(), b(), c(), d, e(), f());
-}
-
-double TransformationMatrix::e() const
-{
- double e = 0;
-#if USE(WXGC)
- m_transform.Get(&e);
-#endif
- return e;
-}
-
-void TransformationMatrix::setE(double e)
-{
- setMatrix(a(), b(), c(), d(), e, f());
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ ASSERT(renderer);
+
+ wxGraphicsMatrix matrix = renderer->CreateMatrix(a(), b(), c(), d(), e(), f());
+ return matrix;
}
-
-double TransformationMatrix::f() const
-{
- double f = 0;
-#if USE(WXGC)
- m_transform.Get(&f);
#endif
- return f;
-}
-
-void TransformationMatrix::setF(double f)
-{
- setMatrix(a(), b(), c(), d(), e(), f);
-}
}