diff options
Diffstat (limited to 'Source/WebCore/platform/graphics')
218 files changed, 6301 insertions, 1998 deletions
diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h index 7bddbf4..a9d2238 100644 --- a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h +++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h @@ -26,11 +26,15 @@ #ifndef ANGLEWebKitBridge_h #define ANGLEWebKitBridge_h -#include "ANGLE/ShaderLang.h" #include "PlatformString.h" - #include <wtf/text/CString.h> +#if !PLATFORM(GTK) +#include "ANGLE/ShaderLang.h" +#else +#include "ShaderLang.h" +#endif + namespace WebCore { enum ANGLEShaderType { diff --git a/Source/WebCore/platform/graphics/BitmapImage.cpp b/Source/WebCore/platform/graphics/BitmapImage.cpp index 6027f34..7cdb43d 100644 --- a/Source/WebCore/platform/graphics/BitmapImage.cpp +++ b/Source/WebCore/platform/graphics/BitmapImage.cpp @@ -103,6 +103,7 @@ void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll) void BitmapImage::destroyMetadataAndNotify(int framesCleared) { m_isSolidColor = false; + m_checkedForSolidColor = false; invalidatePlatformData(); int deltaBytes = framesCleared * -frameBytes(m_size); diff --git a/Source/WebCore/platform/graphics/BitmapImage.h b/Source/WebCore/platform/graphics/BitmapImage.h index c8cf0ab..8d9cd94 100644 --- a/Source/WebCore/platform/graphics/BitmapImage.h +++ b/Source/WebCore/platform/graphics/BitmapImage.h @@ -53,11 +53,11 @@ namespace WebCore { struct FrameData; } -// This complicated-looking declaration tells the FrameData Vector that it should copy without -// invoking our constructor or destructor. This allows us to have a vector even for a struct -// that's not copyable. namespace WTF { - template<> struct VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits {}; + // FIXME: This declaration gives FrameData a default constructor that zeroes + // all its data members, even though FrameData's default constructor defined + // below does not zero all its data members. One of these must be wrong! + template<> struct VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits { }; } namespace WebCore { @@ -139,8 +139,9 @@ public: virtual CFDataRef getTIFFRepresentation(); #endif -#if PLATFORM(CG) +#if USE(CG) virtual CGImageRef getCGImageRef(); + virtual CGImageRef getFirstCGImageRefOfSize(const IntSize&); #endif #if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)) @@ -160,6 +161,14 @@ public: #endif virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); } + bool frameHasAlphaAtIndex(size_t); + +#if !ASSERT_DISABLED + bool notSolidColor() + { + return size().width() != 1 || size().height() != 1 || frameCount() > 1; + } +#endif protected: enum RepetitionCountStatus { @@ -190,7 +199,6 @@ protected: NativeImagePtr frameAtIndex(size_t); bool frameIsCompleteAtIndex(size_t); float frameDurationAtIndex(size_t); - bool frameHasAlphaAtIndex(size_t); // Decodes and caches a frame. Never accessed except internally. void cacheFrame(size_t index); diff --git a/Source/WebCore/platform/graphics/Color.h b/Source/WebCore/platform/graphics/Color.h index 05d9554..02ec005 100644 --- a/Source/WebCore/platform/graphics/Color.h +++ b/Source/WebCore/platform/graphics/Color.h @@ -30,7 +30,7 @@ #include <wtf/Forward.h> #include <wtf/unicode/Unicode.h> -#if PLATFORM(CG) +#if USE(CG) #include "ColorSpace.h" typedef struct CGColor* CGColorRef; #endif @@ -143,7 +143,7 @@ public: operator wxColour() const; #endif -#if PLATFORM(CG) +#if USE(CG) Color(CGColorRef); #endif @@ -191,7 +191,7 @@ inline bool operator!=(const Color& a, const Color& b) Color colorFromPremultipliedARGB(unsigned); unsigned premultipliedARGBFromColor(const Color&); -#if PLATFORM(CG) +#if USE(CG) CGColorRef cachedCGColor(const Color&, ColorSpace); #endif diff --git a/Source/WebCore/platform/graphics/ContextShadow.h b/Source/WebCore/platform/graphics/ContextShadow.h index 850d489..87acee0 100644 --- a/Source/WebCore/platform/graphics/ContextShadow.h +++ b/Source/WebCore/platform/graphics/ContextShadow.h @@ -34,7 +34,7 @@ #include "IntRect.h" #include <wtf/RefCounted.h> -#if PLATFORM(CAIRO) +#if USE(CAIRO) typedef struct _cairo cairo_t; typedef struct _cairo_surface cairo_surface_t; #elif PLATFORM(QT) @@ -49,7 +49,7 @@ namespace WebCore { class AffineTransform; class GraphicsContext; -#if PLATFORM(CAIRO) +#if USE(CAIRO) typedef cairo_surface_t* PlatformImage; typedef cairo_t* PlatformContext; #elif PLATFORM(QT) @@ -116,7 +116,7 @@ public: void setShadowsIgnoreTransforms(bool enable) { m_shadowsIgnoreTransforms = enable; } bool shadowsIgnoreTransforms() const { return m_shadowsIgnoreTransforms; } -#if PLATFORM(CAIRO) +#if USE(CAIRO) void drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius = IntSize(), const IntSize& topRightRadius = IntSize(), const IntSize& bottomLeftRadius = IntSize(), const IntSize& bottomRightRadius = IntSize()); #endif #if PLATFORM(QT) @@ -135,7 +135,7 @@ private: void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride); IntRect calculateLayerBoundingRect(GraphicsContext*, const FloatRect& layerArea, const IntRect& clipRect); -#if PLATFORM(CAIRO) +#if USE(CAIRO) void drawRectShadowWithoutTiling(GraphicsContext*, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha); #endif }; diff --git a/Source/WebCore/platform/graphics/DashArray.h b/Source/WebCore/platform/graphics/DashArray.h index 46b84a4..0516584 100644 --- a/Source/WebCore/platform/graphics/DashArray.h +++ b/Source/WebCore/platform/graphics/DashArray.h @@ -28,9 +28,9 @@ #include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) typedef Vector<CGFloat> DashArray; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) typedef Vector<double> DashArray; #else typedef Vector<float> DashArray; diff --git a/Source/WebCore/platform/graphics/Extensions3D.h b/Source/WebCore/platform/graphics/Extensions3D.h index 5d5a5b7..fee1133 100644 --- a/Source/WebCore/platform/graphics/Extensions3D.h +++ b/Source/WebCore/platform/graphics/Extensions3D.h @@ -66,6 +66,11 @@ public: // extension names for which supports returns true. virtual void ensureEnabled(const String&) = 0; + // Takes full name of extension: for example, "GL_EXT_texture_format_BGRA8888". + // Checks to see whether the given extension is actually enabled (see ensureEnabled). + // Has no other side-effects. + virtual bool isEnabled(const String&) = 0; + enum ExtensionsEnumType { // GL_EXT_texture_format_BGRA8888 enums BGRA_EXT = 0x80E1, diff --git a/Source/WebCore/platform/graphics/FloatPoint.cpp b/Source/WebCore/platform/graphics/FloatPoint.cpp index 226ae71..abe9b86 100644 --- a/Source/WebCore/platform/graphics/FloatPoint.cpp +++ b/Source/WebCore/platform/graphics/FloatPoint.cpp @@ -31,6 +31,7 @@ #include "TransformationMatrix.h" #include "FloatConversion.h" #include "IntPoint.h" +#include <limits> #include <math.h> namespace WebCore { @@ -73,4 +74,43 @@ FloatPoint FloatPoint::narrowPrecision(double x, double y) return FloatPoint(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)); } +float findSlope(const FloatPoint& p1, const FloatPoint& p2, float& c) +{ + if (p2.x() == p1.x()) + return std::numeric_limits<float>::infinity(); + + // y = mx + c + float slope = (p2.y() - p1.y()) / (p2.x() - p1.x()); + c = p1.y() - slope * p1.x(); + return slope; +} + +bool findIntersection(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& d1, const FloatPoint& d2, FloatPoint& intersection) +{ + float pOffset = 0; + float pSlope = findSlope(p1, p2, pOffset); + + float dOffset = 0; + float dSlope = findSlope(d1, d2, dOffset); + + if (dSlope == pSlope) + return false; + + if (pSlope == std::numeric_limits<float>::infinity()) { + intersection.setX(p1.x()); + intersection.setY(dSlope * intersection.x() + dOffset); + return true; + } + if (dSlope == std::numeric_limits<float>::infinity()) { + intersection.setX(d1.x()); + intersection.setY(pSlope * intersection.x() + pOffset); + return true; + } + + // Find x at intersection, where ys overlap; x = (c' - c) / (m - m') + intersection.setX((dOffset - pOffset) / (pSlope - dSlope)); + intersection.setY(pSlope * intersection.x() + pOffset); + return true; +} + } diff --git a/Source/WebCore/platform/graphics/FloatPoint.h b/Source/WebCore/platform/graphics/FloatPoint.h index c4b2943..fd73c69 100644 --- a/Source/WebCore/platform/graphics/FloatPoint.h +++ b/Source/WebCore/platform/graphics/FloatPoint.h @@ -31,7 +31,7 @@ #include "IntPoint.h" #include <wtf/MathExtras.h> -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGPoint CGPoint; #endif @@ -109,7 +109,7 @@ public: return m_x * m_x + m_y * m_y; } -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) FloatPoint(const CGPoint&); operator CGPoint() const; #endif @@ -202,6 +202,11 @@ inline IntPoint roundedIntPoint(const FloatPoint& p) return IntPoint(static_cast<int>(roundf(p.x())), static_cast<int>(roundf(p.y()))); } +float findSlope(const FloatPoint& p1, const FloatPoint& p2, float& c); + +// Find point where lines through the two pairs of points intersect. Returns false if the lines don't intersect. +bool findIntersection(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& d1, const FloatPoint& d2, FloatPoint& intersection); + } #endif diff --git a/Source/WebCore/platform/graphics/FloatRect.cpp b/Source/WebCore/platform/graphics/FloatRect.cpp index 36f3d3a..165ef76 100644 --- a/Source/WebCore/platform/graphics/FloatRect.cpp +++ b/Source/WebCore/platform/graphics/FloatRect.cpp @@ -30,8 +30,8 @@ #include "FloatConversion.h" #include "IntRect.h" #include <algorithm> -#include <limits> #include <math.h> +#include <wtf/MathExtras.h> using std::max; using std::min; @@ -97,6 +97,24 @@ void FloatRect::unite(const FloatRect& other) setLocationAndSizeFromEdges(l, t, r, b); } +void FloatRect::uniteIfNonZero(const FloatRect& other) +{ + // Handle empty special cases first. + if (!other.width() && !other.height()) + return; + if (!width() && !height()) { + *this = other; + return; + } + + float left = min(x(), other.x()); + float top = min(y(), other.y()); + float right = max(maxX(), other.maxX()); + float bottom = max(maxY(), other.maxY()); + + setLocationAndSizeFromEdges(left, top, right, bottom); +} + void FloatRect::scale(float sx, float sy) { m_location.setX(x() * sx); @@ -182,6 +200,7 @@ IntRect enclosingIntRect(const FloatRect& rect) float top = floorf(rect.y()); float width = ceilf(rect.maxX()) - left; float height = ceilf(rect.maxY()) - top; + return IntRect(safeFloatToInt(left), safeFloatToInt(top), safeFloatToInt(width), safeFloatToInt(height)); } diff --git a/Source/WebCore/platform/graphics/FloatRect.h b/Source/WebCore/platform/graphics/FloatRect.h index bd23476..493c068 100644 --- a/Source/WebCore/platform/graphics/FloatRect.h +++ b/Source/WebCore/platform/graphics/FloatRect.h @@ -29,7 +29,7 @@ #include "FloatPoint.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGRect CGRect; #endif @@ -59,7 +59,7 @@ class BRect; struct SkRect; #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) typedef struct _cairo_rectangle cairo_rectangle_t; #endif @@ -112,6 +112,7 @@ public: void intersect(const FloatRect&); void unite(const FloatRect&); + void uniteIfNonZero(const FloatRect&); // Note, this doesn't match what IntRect::contains(IntPoint&) does; the int version // is really checking for containment of 1x1 rect, but that doesn't make sense with floats. @@ -136,7 +137,7 @@ public: void fitToPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2); void fitToPoints(const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3); -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) FloatRect(const CGRect&); operator CGRect() const; #endif @@ -172,7 +173,7 @@ public: operator VGRect() const; #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) FloatRect(const cairo_rectangle_t&); operator cairo_rectangle_t() const; #endif diff --git a/Source/WebCore/platform/graphics/FloatSize.h b/Source/WebCore/platform/graphics/FloatSize.h index 160fc9a..1485c71 100644 --- a/Source/WebCore/platform/graphics/FloatSize.h +++ b/Source/WebCore/platform/graphics/FloatSize.h @@ -31,7 +31,7 @@ #include "IntSize.h" #include <wtf/MathExtras.h> -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) typedef struct CGSize CGSize; #endif @@ -89,7 +89,7 @@ public: return m_width * m_width + m_height * m_height; } -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) explicit FloatSize(const CGSize&); // don't do this implicitly since it's lossy operator CGSize() const; #endif @@ -148,6 +148,11 @@ inline IntSize roundedIntSize(const FloatSize& p) return IntSize(static_cast<int>(roundf(p.width())), static_cast<int>(roundf(p.height()))); } +inline IntSize expandedIntSize(const FloatSize& p) +{ + return IntSize(clampToInteger(ceilf(p.width())), clampToInteger(ceilf(p.height()))); +} + } // namespace WebCore #endif // FloatSize_h diff --git a/Source/WebCore/platform/graphics/Font.h b/Source/WebCore/platform/graphics/Font.h index 554f8a0..beafdc7 100644 --- a/Source/WebCore/platform/graphics/Font.h +++ b/Source/WebCore/platform/graphics/Font.h @@ -203,7 +203,8 @@ public: FontSelector* fontSelector() const; static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; } - static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || (c >= 0x200c && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == objectReplacementCharacter; } + static bool treatAsZeroWidthSpace(UChar c) { return treatAsZeroWidthSpaceInComplexScript(c) || c == 0x200c || c == 0x200d; } + static bool treatAsZeroWidthSpaceInComplexScript(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || (c >= 0x200e && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == zeroWidthNoBreakSpace || c == objectReplacementCharacter; } static bool canReceiveTextEmphasis(UChar32 c); static inline UChar normalizeSpaces(UChar character) diff --git a/Source/WebCore/platform/graphics/FontCache.cpp b/Source/WebCore/platform/graphics/FontCache.cpp index 8c5edfe..d64878b 100644 --- a/Source/WebCore/platform/graphics/FontCache.cpp +++ b/Source/WebCore/platform/graphics/FontCache.cpp @@ -121,22 +121,7 @@ struct FontPlatformDataCacheKeyHash { static const bool safeToCompareToEmptyOrDeleted = true; }; -struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> { - static const bool emptyValueIsZero = true; - static const FontPlatformDataCacheKey& emptyValue() - { - DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (nullAtom)); - return key; - } - static void constructDeletedValue(FontPlatformDataCacheKey& slot) - { - new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue); - } - static bool isDeletedValue(const FontPlatformDataCacheKey& value) - { - return value.isHashTableDeletedValue(); - } -}; +struct FontPlatformDataCacheKeyTraits : WTF::SimpleClassHashTraits<FontPlatformDataCacheKey> { }; typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache; diff --git a/Source/WebCore/platform/graphics/FontMetrics.h b/Source/WebCore/platform/graphics/FontMetrics.h index 89c5545..367f004 100644 --- a/Source/WebCore/platform/graphics/FontMetrics.h +++ b/Source/WebCore/platform/graphics/FontMetrics.h @@ -96,6 +96,11 @@ public: int lineGap() const { return lroundf(m_lineGap); } int lineSpacing() const { return lroundf(m_lineSpacing); } + bool hasIdenticalAscentDescentAndLineGap(const FontMetrics& other) const + { + return ascent() == other.ascent() && descent() == other.descent() && lineGap() == other.lineGap(); + } + private: friend class SimpleFontData; diff --git a/Source/WebCore/platform/graphics/FontPlatformData.h b/Source/WebCore/platform/graphics/FontPlatformData.h index 5981c16..a32215d 100644 --- a/Source/WebCore/platform/graphics/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/FontPlatformData.h @@ -51,7 +51,7 @@ #include "RefCountedGDIHandle.h" #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include "HashFunctions.h" #include <cairo.h> #endif @@ -86,7 +86,7 @@ typedef const struct __CTFont* CTFontRef; typedef struct HFONT__* HFONT; #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGFont* CGFontRef; #if OS(DARWIN) #ifndef BUILDING_ON_TIGER @@ -119,9 +119,9 @@ public: #elif OS(DARWIN) , m_font(hashTableDeletedFontValue()) #endif -#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) +#if USE(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) , m_cgFont(0) -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) , m_scaledFont(hashTableDeletedFontValue()) #endif , m_isColorBitmapFont(false) @@ -141,9 +141,9 @@ public: #if OS(DARWIN) , m_font(0) #endif -#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) +#if USE(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) , m_cgFont(0) -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) , m_scaledFont(0) #endif , m_isColorBitmapFont(false) @@ -166,9 +166,9 @@ public: #if OS(DARWIN) , m_font(0) #endif -#if PLATFORM(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) +#if USE(CG) && (defined(BUILDING_ON_TIGER) || PLATFORM(WIN)) , m_cgFont(0) -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) , m_scaledFont(0) #endif , m_isColorBitmapFont(false) @@ -181,6 +181,7 @@ public: #if OS(DARWIN) FontPlatformData(NSFont*, float size, bool syntheticBold = false, bool syntheticOblique = false, FontOrientation = Horizontal, TextOrientation = TextOrientationVerticalRight, FontWidthVariant = RegularWidth); +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) FontPlatformData(CGFontRef cgFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, TextOrientation textOrientation, FontWidthVariant widthVariant) : m_syntheticBold(syntheticBold) @@ -195,13 +196,14 @@ public: { } #endif +#endif #if PLATFORM(WIN) FontPlatformData(HFONT, float size, bool syntheticBold, bool syntheticOblique, bool useGDI); -#if PLATFORM(CG) +#if USE(CG) FontPlatformData(HFONT, CGFontRef, float size, bool syntheticBold, bool syntheticOblique, bool useGDI); #endif #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) FontPlatformData(cairo_font_face_t*, float size, bool bold, bool italic); #endif @@ -215,7 +217,7 @@ public: void setFont(NSFont*); #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #if OS(DARWIN) #ifndef BUILDING_ON_TIGER CGFontRef cgFont() const { return m_cgFont.get(); } @@ -243,19 +245,21 @@ public: void setOrientation(FontOrientation orientation) { m_orientation = orientation; } -#if PLATFORM(CAIRO) +#if USE(CAIRO) cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } #endif unsigned hash() const { -#if PLATFORM(WIN) && !PLATFORM(CAIRO) +#if PLATFORM(WIN) && !USE(CAIRO) return m_font ? m_font->hash() : 0; #elif OS(DARWIN) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) ASSERT(m_font || !m_cgFont); +#endif uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, m_textOrientation << 3 | m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique }; return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) return PtrHash<cairo_scaled_font_t*>::hash(m_scaledFont); #endif } @@ -276,11 +280,11 @@ public: bool isHashTableDeletedValue() const { -#if PLATFORM(WIN) && !PLATFORM(CAIRO) +#if PLATFORM(WIN) && !USE(CAIRO) return m_font.isHashTableDeletedValue(); #elif OS(DARWIN) return m_font == hashTableDeletedFontValue(); -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) return m_scaledFont == hashTableDeletedFontValue(); #endif } @@ -307,7 +311,7 @@ private: void platformDataInit(HFONT, float size, HDC, WCHAR* faceName); #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) static cairo_scaled_font_t* hashTableDeletedFontValue() { return reinterpret_cast<cairo_scaled_font_t*>(-1); } #endif @@ -326,7 +330,7 @@ private: RefPtr<RefCountedGDIHandle<HFONT> > m_font; #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #if PLATFORM(WIN) RetainPtr<CGFontRef> m_cgFont; #else @@ -339,7 +343,7 @@ private: #endif #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) cairo_scaled_font_t* m_scaledFont; #endif diff --git a/Source/WebCore/platform/graphics/FontSelector.h b/Source/WebCore/platform/graphics/FontSelector.h index 156bf10..e18161b 100644 --- a/Source/WebCore/platform/graphics/FontSelector.h +++ b/Source/WebCore/platform/graphics/FontSelector.h @@ -33,6 +33,7 @@ namespace WebCore { class FontData; class FontDescription; +class FontSelectorClient; class FontSelector : public RefCounted<FontSelector> { public: @@ -40,6 +41,16 @@ public: virtual FontData* getFontData(const FontDescription&, const AtomicString& familyName) = 0; virtual void fontCacheInvalidated() { } + + virtual void registerForInvalidationCallbacks(FontSelectorClient*) = 0; + virtual void unregisterForInvalidationCallbacks(FontSelectorClient*) = 0; +}; + +class FontSelectorClient { +public: + virtual ~FontSelectorClient() { } + + virtual void fontsNeedUpdate(FontSelector*) = 0; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/GlyphBuffer.h b/Source/WebCore/platform/graphics/GlyphBuffer.h index 7aac1e3..f5216a9 100644 --- a/Source/WebCore/platform/graphics/GlyphBuffer.h +++ b/Source/WebCore/platform/graphics/GlyphBuffer.h @@ -34,11 +34,11 @@ #include <wtf/UnusedParam.h> #include <wtf/Vector.h> -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> #endif -#if PLATFORM(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__)) +#if USE(CAIRO) || (PLATFORM(WX) && defined(__WXGTK__)) #include <cairo.h> #endif @@ -47,7 +47,7 @@ namespace WebCore { typedef unsigned short Glyph; class SimpleFontData; -#if PLATFORM(CAIRO) +#if USE(CAIRO) // FIXME: Why does Cairo use such a huge struct instead of just an offset into an array? typedef cairo_glyph_t GlyphBufferGlyph; #elif OS(WINCE) @@ -58,7 +58,7 @@ typedef Glyph GlyphBufferGlyph; // CG uses CGSize instead of FloatSize so that the result of advances() // can be passed directly to CGContextShowGlyphsWithAdvances in FontMac.mm -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) typedef CGSize GlyphBufferAdvance; #elif OS(WINCE) // There is no cross-platform code that uses the height of GlyphBufferAdvance, @@ -113,7 +113,7 @@ public: Glyph glyphAt(int index) const { -#if PLATFORM(CAIRO) +#if USE(CAIRO) return m_glyphs[index].index; #else return m_glyphs[index]; @@ -122,7 +122,7 @@ public: float advanceAt(int index) const { -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) return m_advances[index].width; #elif OS(WINCE) return m_advances[index]; @@ -145,7 +145,7 @@ public: { m_fontData.append(font); -#if PLATFORM(CAIRO) +#if USE(CAIRO) cairo_glyph_t cairoGlyph; cairoGlyph.index = glyph; m_glyphs.append(cairoGlyph); @@ -153,7 +153,7 @@ public: m_glyphs.append(glyph); #endif -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) CGSize advance = { width, 0 }; m_advances.append(advance); #elif OS(WINCE) @@ -176,7 +176,7 @@ public: void add(Glyph glyph, const SimpleFontData* font, GlyphBufferAdvance advance) { m_fontData.append(font); -#if PLATFORM(CAIRO) +#if USE(CAIRO) cairo_glyph_t cairoGlyph; cairoGlyph.index = glyph; m_glyphs.append(cairoGlyph); @@ -192,7 +192,7 @@ public: { ASSERT(!isEmpty()); GlyphBufferAdvance& lastAdvance = m_advances.last(); -#if PLATFORM(CG) || (PLATFORM(WX) && OS(DARWIN)) +#if USE(CG) || (PLATFORM(WX) && OS(DARWIN)) || USE(SKIA_ON_MAC_CHROME) lastAdvance.width += width; #elif OS(WINCE) lastAdvance += width; diff --git a/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp index e7ed193..951cf56 100644 --- a/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/Source/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -191,6 +191,9 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) { // Object replacement character must not render at all. buffer[objectReplacementCharacter - start] = zeroWidthSpace; + } else if (start == (zeroWidthNoBreakSpace & ~(GlyphPage::size - 1))) { + // ZWNBS/BOM must not render at all. + buffer[zeroWidthNoBreakSpace - start] = zeroWidthSpace; } } else { bufferLength = GlyphPage::size * 2; diff --git a/Source/WebCore/platform/graphics/Gradient.cpp b/Source/WebCore/platform/graphics/Gradient.cpp index 783e552..4edb4bd 100644 --- a/Source/WebCore/platform/graphics/Gradient.cpp +++ b/Source/WebCore/platform/graphics/Gradient.cpp @@ -221,7 +221,11 @@ void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTra setPlatformGradientSpaceTransform(gradientSpaceTransformation); } +<<<<<<< HEAD #if !(USE(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(CAIRO) +======= +#if !USE(SKIA) && !USE(CAIRO) +>>>>>>> WebKit.org at r84325 void Gradient::setPlatformGradientSpaceTransform(const AffineTransform&) { } diff --git a/Source/WebCore/platform/graphics/Gradient.h b/Source/WebCore/platform/graphics/Gradient.h index acc6125..7595896 100644 --- a/Source/WebCore/platform/graphics/Gradient.h +++ b/Source/WebCore/platform/graphics/Gradient.h @@ -35,7 +35,7 @@ #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) typedef struct CGContext* CGContextRef; @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QGradient; QT_END_NAMESPACE typedef QGradient* PlatformGradient; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) typedef struct _cairo_pattern cairo_pattern_t; typedef cairo_pattern_t* PlatformGradient; #elif USE(SKIA) @@ -146,7 +146,7 @@ namespace WebCore { void setPlatformGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation); -#if PLATFORM(CG) +#if USE(CG) void paint(CGContextRef); void paint(GraphicsContext*); #endif diff --git a/Source/WebCore/platform/graphics/GraphicsContext.cpp b/Source/WebCore/platform/graphics/GraphicsContext.cpp index fa3280e..ddaf938 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext.cpp +++ b/Source/WebCore/platform/graphics/GraphicsContext.cpp @@ -148,7 +148,7 @@ void GraphicsContext::setLegacyShadow(const FloatSize& offset, float blur, const m_state.shadowBlur = blur; m_state.shadowColor = color; m_state.shadowColorSpace = colorSpace; -#if PLATFORM(CG) +#if USE(CG) m_state.shadowsUseLegacyRadius = true; #endif setPlatformShadow(offset, blur, color, colorSpace); @@ -397,7 +397,11 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F if (paintingDisabled()) return; + // FIXME: This ownership should be reversed. We should pass BidiRunList + // to BidiResolver in createBidiRunsForLine. BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; + BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); + WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, BidiContext::create(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); @@ -405,11 +409,11 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F bidiResolver.setPosition(TextRunIterator(&run, 0)); bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); - if (!bidiResolver.runCount()) + if (!bidiRuns.runCount()) return; FloatPoint currPoint = point; - BidiCharacterRun* bidiRun = bidiResolver.firstRun(); + BidiCharacterRun* bidiRun = bidiRuns.firstRun(); while (bidiRun) { TextRun subrun = run; @@ -425,7 +429,7 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F currPoint.move(font.width(subrun), 0); } - bidiResolver.deleteRuns(); + bidiRuns.deleteRuns(); } void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const FloatPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to) @@ -563,7 +567,7 @@ void GraphicsContext::addRoundedRectClip(const RoundedIntRect& rect) return; Path path; - path.addRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight()); + path.addRoundedRect(rect); clip(path); } @@ -573,7 +577,7 @@ void GraphicsContext::clipOutRoundedRect(const RoundedIntRect& rect) return; Path path; - path.addRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight()); + path.addRoundedRect(rect); clipOut(path); } @@ -584,7 +588,7 @@ void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& re buffer->clip(this, rect); } -#if !PLATFORM(CG) +#if !USE(CG) IntRect GraphicsContext::clipBounds() const { ASSERT_NOT_REACHED(); @@ -617,7 +621,7 @@ void GraphicsContext::fillRoundedRect(const RoundedIntRect& rect, const Color& c fillRoundedRect(rect.rect(), rect.radii().topLeft(), rect.radii().topRight(), rect.radii().bottomLeft(), rect.radii().bottomRight(), color, colorSpace); } -#if !PLATFORM(CG) +#if !USE(CG) void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const RoundedIntRect& roundedHoleRect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) @@ -627,7 +631,7 @@ void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const Rounded path.addRect(rect); if (!roundedHoleRect.radii().isZero()) - path.addRoundedRect(roundedHoleRect.rect(), roundedHoleRect.radii().topLeft(), roundedHoleRect.radii().topRight(), roundedHoleRect.radii().bottomLeft(), roundedHoleRect.radii().bottomRight()); + path.addRoundedRect(roundedHoleRect); else path.addRect(roundedHoleRect.rect()); @@ -674,7 +678,11 @@ void GraphicsContext::setPlatformStrokePattern(Pattern*) } #endif +<<<<<<< HEAD #if !PLATFORM(CG) && !(USE(SKIA) && !PLATFORM(ANDROID)) +======= +#if !USE(CG) && !USE(SKIA) +>>>>>>> WebKit.org at r84325 // Implement this if you want to go ahead and push the drawing mode into your native context // immediately. void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) @@ -682,13 +690,17 @@ void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) } #endif +<<<<<<< HEAD #if !PLATFORM(QT) && !PLATFORM(CAIRO) && !(USE(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG) +======= +#if !PLATFORM(QT) && !USE(CAIRO) && !USE(SKIA) && !PLATFORM(HAIKU) && !PLATFORM(OPENVG) +>>>>>>> WebKit.org at r84325 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle) { } #endif -#if !PLATFORM(CG) +#if !USE(CG) void GraphicsContext::setPlatformShouldSmoothFonts(bool) { } diff --git a/Source/WebCore/platform/graphics/GraphicsContext.h b/Source/WebCore/platform/graphics/GraphicsContext.h index c555a5f..2b41c2e 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext.h +++ b/Source/WebCore/platform/graphics/GraphicsContext.h @@ -37,9 +37,9 @@ #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> -#if PLATFORM(CG) +#if USE(CG) typedef struct CGContext PlatformGraphicsContext; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) namespace WebCore { class ContextShadow; class PlatformContextCairo; @@ -99,8 +99,9 @@ typedef void PlatformGraphicsContext; #endif #if PLATFORM(WIN) +#include "DIBPixelData.h" typedef struct HDC__* HDC; -#if !PLATFORM(CG) +#if !USE(CG) // UInt8 is defined in CoreFoundation/CFBase.h typedef unsigned char UInt8; #endif @@ -161,7 +162,7 @@ namespace WebCore { GraphicsContextState() : strokeThickness(0) , shadowBlur(0) -#if PLATFORM(CAIRO) +#if USE(CAIRO) , globalAlpha(1) #endif , textDrawingMode(TextModeFill) @@ -177,7 +178,7 @@ namespace WebCore { , shouldSmoothFonts(true) , paintingDisabled(false) , shadowsIgnoreTransforms(false) -#if PLATFORM(CG) +#if USE(CG) // Core Graphics incorrectly renders shadows with radius > 8px (<rdar://problem/8103442>), // but we need to preserve this buggy behavior for canvas and -webkit-box-shadow. , shadowsUseLegacyRadius(false) @@ -196,7 +197,7 @@ namespace WebCore { float strokeThickness; float shadowBlur; -#if PLATFORM(CAIRO) +#if USE(CAIRO) float globalAlpha; #endif TextDrawingModeFlags textDrawingMode; @@ -218,7 +219,7 @@ namespace WebCore { bool shouldSmoothFonts : 1; bool paintingDisabled : 1; bool shadowsIgnoreTransforms : 1; -#if PLATFORM(CG) +#if USE(CG) bool shadowsUseLegacyRadius : 1; #endif }; @@ -270,7 +271,7 @@ namespace WebCore { const GraphicsContextState& state() const; -#if PLATFORM(CG) +#if USE(CG) void applyStrokePattern(); void applyFillPattern(); void drawPath(const Path&); @@ -383,7 +384,11 @@ namespace WebCore { void drawBidiText(const Font&, const TextRun&, const FloatPoint&); void drawHighlightForText(const Font&, const TextRun&, const FloatPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1); - FloatRect roundToDevicePixels(const FloatRect&); + enum RoundingMode { + RoundAllSides, + RoundOriginAndDimensions + }; + FloatRect roundToDevicePixels(const FloatRect&, RoundingMode = RoundAllSides); void drawLineForText(const FloatPoint&, float width, bool printing); enum TextCheckingLineStyle { @@ -420,7 +425,7 @@ namespace WebCore { void setMiterLimit(float); void setAlpha(float); -#if PLATFORM(CAIRO) +#if USE(CAIRO) float getAlpha(); #endif @@ -486,18 +491,17 @@ namespace WebCore { ~WindowsBitmap(); HDC hdc() const { return m_hdc; } - UInt8* buffer() const { return m_bitmapBuffer; } - unsigned bufferLength() const { return m_bitmapBufferLength; } - IntSize size() const { return m_size; } - unsigned bytesPerRow() const { return m_bytesPerRow; } + UInt8* buffer() const { return m_pixelData.buffer(); } + unsigned bufferLength() const { return m_pixelData.bufferLength(); } + const IntSize& size() const { return m_pixelData.size(); } + unsigned bytesPerRow() const { return m_pixelData.bytesPerRow(); } + unsigned short bitsPerPixel() const { return m_pixelData.bitsPerPixel(); } + const DIBPixelData& windowsDIB() const { return m_pixelData; } private: HDC m_hdc; HBITMAP m_bitmap; - UInt8* m_bitmapBuffer; - unsigned m_bitmapBufferLength; - IntSize m_size; - unsigned m_bytesPerRow; + DIBPixelData m_pixelData; }; WindowsBitmap* createWindowsBitmap(IntSize); @@ -521,13 +525,12 @@ namespace WebCore { void takeOwnershipOfPlatformContext(); #endif -#if PLATFORM(QT) || PLATFORM(CAIRO) +#if PLATFORM(QT) || USE(CAIRO) ContextShadow* contextShadow(); #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) GraphicsContext(cairo_t*); - void pushImageMask(cairo_surface_t*, const FloatRect&); #endif #if PLATFORM(GTK) diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.h b/Source/WebCore/platform/graphics/GraphicsContext3D.h index 351b445..80226cf 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.h +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.h @@ -43,8 +43,11 @@ #undef VERSION #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || PLATFORM(GTK) #include "ANGLEWebKitBridge.h" +#endif + +#if PLATFORM(MAC) #include <OpenGL/OpenGL.h> #include <wtf/RetainPtr.h> #ifdef __OBJC__ @@ -73,7 +76,7 @@ typedef void* PlatformGraphicsContext3D; const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; const Platform3DObject NullPlatform3DObject = 0; -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGContext.h> #endif @@ -81,12 +84,15 @@ namespace WebCore { class CanvasRenderingContext; class DrawingBuffer; class Extensions3D; -#if PLATFORM(MAC) +#if PLATFORM(MAC) || PLATFORM(GTK) class Extensions3DOpenGL; #endif class HostWindow; class Image; class ImageData; +#if USE(CAIRO) +class PlatformContextCairo; +#endif struct ActiveInfo { String name; @@ -95,7 +101,7 @@ struct ActiveInfo { }; // FIXME: ideally this would be used on all platforms. -#if PLATFORM(CHROMIUM) || PLATFORM(QT) +#if PLATFORM(CHROMIUM) || PLATFORM(QT) || PLATFORM(GTK) class GraphicsContext3DInternal; #endif @@ -465,6 +471,9 @@ public: #if USE(ACCELERATED_COMPOSITING) PlatformLayer* platformLayer() const; #endif +#elif PLATFORM(GTK) + PlatformGraphicsContext3D platformGraphicsContext3D(); + Platform3DObject platformTexture() const { return m_texture; } #else PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } Platform3DObject platformTexture() const { return NullPlatform3DObject; } @@ -476,7 +485,7 @@ public: PassRefPtr<DrawingBuffer> createDrawingBuffer(const IntSize& = IntSize()); -#if PLATFORM(MAC) || PLATFORM(CHROMIUM) +#if PLATFORM(MAC) || PLATFORM(CHROMIUM) || PLATFORM(GTK) // With multisampling on, blit from multisampleFBO to regular FBO. void prepareTexture(); #endif @@ -753,9 +762,12 @@ public: void reshape(int width, int height); -#if PLATFORM(CG) +#if USE(CG) void paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, int canvasWidth, int canvasHeight, CGContextRef context); +#elif PLATFORM(GTK) + void paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, + int canvasWidth, int canvasHeight, PlatformContextCairo* context); #endif void markContextChanged(); @@ -769,6 +781,8 @@ public: bool paintsIntoCanvasBuffer() const { return true; } #elif PLATFORM(CHROMIUM) bool paintsIntoCanvasBuffer() const; +#elif PLATFORM(GTK) + bool paintsIntoCanvasBuffer() const { return true; } #else bool paintsIntoCanvasBuffer() const { return false; } #endif @@ -859,7 +873,7 @@ public: AlphaOp alphaOp, void* destinationData); -#if PLATFORM(MAC) +#if PLATFORM(MAC) || PLATFORM(GTK) // Take into account the user's requested context creation attributes, // in particular stencil and antialias, and determine which could or // could not be honored based on the capabilities of the OpenGL @@ -874,6 +888,11 @@ public: int m_currentWidth, m_currentHeight; #if PLATFORM(MAC) + CGLContextObj m_contextObj; + RetainPtr<WebGLLayer> m_webGLLayer; +#endif + +#if PLATFORM(MAC) || PLATFORM(GTK) typedef struct { String source; String log; @@ -889,8 +908,6 @@ public: Attributes m_attrs; Vector<Vector<float> > m_vertexArray; - CGLContextObj m_contextObj; - RetainPtr<WebGLLayer> m_webGLLayer; GC3Duint m_texture, m_compositorTexture; GC3Duint m_fbo; GC3Duint m_depthStencilBuffer; @@ -912,7 +929,7 @@ public: #endif // FIXME: ideally this would be used on all platforms. -#if PLATFORM(CHROMIUM) || PLATFORM(QT) +#if PLATFORM(CHROMIUM) || PLATFORM(QT) || PLATFORM(GTK) friend class GraphicsContext3DInternal; OwnPtr<GraphicsContext3DInternal> m_internal; #endif diff --git a/Source/WebCore/platform/graphics/Image.cpp b/Source/WebCore/platform/graphics/Image.cpp index 3096680..11da0ab 100644 --- a/Source/WebCore/platform/graphics/Image.cpp +++ b/Source/WebCore/platform/graphics/Image.cpp @@ -36,7 +36,7 @@ #include <math.h> #include <wtf/StdLibExtras.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreFoundation/CoreFoundation.h> #endif diff --git a/Source/WebCore/platform/graphics/Image.h b/Source/WebCore/platform/graphics/Image.h index 3c5e7fd..834a0d3 100644 --- a/Source/WebCore/platform/graphics/Image.h +++ b/Source/WebCore/platform/graphics/Image.h @@ -45,7 +45,7 @@ class NSImage; #endif #endif -#if PLATFORM(CG) +#if USE(CG) struct CGContext; #endif @@ -136,8 +136,9 @@ public: virtual CFDataRef getTIFFRepresentation() { return 0; } #endif -#if PLATFORM(CG) +#if USE(CG) virtual CGImageRef getCGImageRef() { return 0; } + virtual CGImageRef getFirstCGImageRefOfSize(const IntSize&) { return 0; } #endif #if PLATFORM(WIN) diff --git a/Source/WebCore/platform/graphics/ImageBuffer.cpp b/Source/WebCore/platform/graphics/ImageBuffer.cpp index 4a76be4..23b925a 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.cpp +++ b/Source/WebCore/platform/graphics/ImageBuffer.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "ImageBuffer.h" -#if !PLATFORM(CG) +#if !USE(CG) #include <math.h> @@ -69,4 +69,4 @@ void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstCo } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/ImageBuffer.h b/Source/WebCore/platform/graphics/ImageBuffer.h index 860f574..c184bbe 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.h +++ b/Source/WebCore/platform/graphics/ImageBuffer.h @@ -41,10 +41,6 @@ #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> -#if (PLATFORM(MAC) && PLATFORM(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)) -#define WTF_USE_IOSURFACE_CANVAS_BACKING_STORE 1 -#endif - namespace WebCore { class GraphicsContext; @@ -86,6 +82,7 @@ namespace WebCore { GraphicsContext* context() const; + bool isAccelerated() const { return m_accelerateRendering; } bool drawsUsingCopy() const; // If the image buffer has to render using a copied image, it will return true. PassRefPtr<Image> copyImage() const; // Return a new image that is a copy of the buffer. @@ -96,7 +93,7 @@ namespace WebCore { void putPremultipliedImageData(ByteArray*, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint); String toDataURL(const String& mimeType, const double* quality = 0) const; -#if !PLATFORM(CG) +#if !USE(CG) AffineTransform baseTransform() const { return AffineTransform(); } void transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace); void platformTransformColorSpace(const Vector<int>&); @@ -122,7 +119,7 @@ namespace WebCore { bool m_accelerateRendering; OwnPtr<GraphicsContext> m_context; -#if !PLATFORM(CG) +#if !USE(CG) Vector<int> m_linearRgbLUT; Vector<int> m_deviceRgbLUT; #endif @@ -132,7 +129,7 @@ namespace WebCore { ImageBuffer(const IntSize&, ColorSpace colorSpace, RenderingMode renderingMode, bool& success); }; -#if PLATFORM(CG) || USE(SKIA) +#if USE(CG) || USE(SKIA) String ImageDataToDataURL(const ImageData& input, const String& mimeType, const double* quality); #endif diff --git a/Source/WebCore/platform/graphics/ImageBufferData.h b/Source/WebCore/platform/graphics/ImageBufferData.h new file mode 100644 index 0000000..670a10f --- /dev/null +++ b/Source/WebCore/platform/graphics/ImageBufferData.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011 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. + */ + +#if USE(CG) +#include "ImageBufferDataCG.h" +#elif USE(CAIRO) +#include "ImageBufferDataCairo.h" +#elif PLATFORM(QT) +#include "ImageBufferDataQt.h" +#elif USE(SKIA) +#include "ImageBufferDataSkia.h" +#elif PLATFORM(HAIKU) +#include "ImageBufferDataHaiku.h" +#elif OS(WINCE) +#include "ImageBufferDataWince.h" +#elif PLATFORM(WX) +#include "ImageBufferDataWx.h" +#endif diff --git a/Source/WebCore/platform/graphics/ImageSource.h b/Source/WebCore/platform/graphics/ImageSource.h index 5ece15b..8dcc9a2 100644 --- a/Source/WebCore/platform/graphics/ImageSource.h +++ b/Source/WebCore/platform/graphics/ImageSource.h @@ -34,7 +34,7 @@ #if PLATFORM(WX) class wxBitmap; class wxGraphicsBitmap; -#elif PLATFORM(CG) +#elif USE(CG) typedef struct CGImageSource* CGImageSourceRef; typedef struct CGImage* CGImageRef; typedef const struct __CFData* CFDataRef; @@ -43,7 +43,7 @@ typedef const struct __CFData* CFDataRef; QT_BEGIN_NAMESPACE class QPixmap; QT_END_NAMESPACE -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) struct _cairo_surface; typedef struct _cairo_surface cairo_surface_t; #elif USE(SKIA) @@ -68,7 +68,7 @@ class IntPoint; class IntSize; class SharedBuffer; -#if PLATFORM(CG) +#if USE(CG) #if USE(WEBKIT_IMAGE_DECODERS) class ImageDecoder; typedef ImageDecoder* NativeImageSourcePtr; @@ -107,7 +107,7 @@ typedef wxGraphicsBitmap* NativeImagePtr; #else typedef wxBitmap* NativeImagePtr; #endif -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) typedef cairo_surface_t* NativeImagePtr; #elif USE(SKIA) typedef WebCore::NativeImageSkia* NativeImagePtr; diff --git a/Source/WebCore/platform/graphics/IntPoint.h b/Source/WebCore/platform/graphics/IntPoint.h index d27906b..46d49eb 100644 --- a/Source/WebCore/platform/graphics/IntPoint.h +++ b/Source/WebCore/platform/graphics/IntPoint.h @@ -32,7 +32,7 @@ #include <QDataStream> #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGPoint CGPoint; #endif @@ -114,7 +114,7 @@ public: return IntPoint(m_y, m_x); } -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) explicit IntPoint(const CGPoint&); // don't do this implicitly since it's lossy operator CGPoint() const; #endif diff --git a/Source/WebCore/platform/graphics/IntRect.cpp b/Source/WebCore/platform/graphics/IntRect.cpp index 7591c41..9507406 100644 --- a/Source/WebCore/platform/graphics/IntRect.cpp +++ b/Source/WebCore/platform/graphics/IntRect.cpp @@ -96,6 +96,27 @@ void IntRect::unite(const IntRect& other) m_size.setHeight(b - t); } +void IntRect::uniteIfNonZero(const IntRect& other) +{ + // Handle empty special cases first. + if (!other.width() && !other.height()) + return; + if (!width() && !height()) { + *this = other; + return; + } + + int left = min(x(), other.x()); + int top = min(y(), other.y()); + int right = max(maxX(), other.maxX()); + int bottom = max(maxY(), other.maxY()); + + m_location.setX(left); + m_location.setY(top); + m_size.setWidth(right - left); + m_size.setHeight(bottom - top); +} + void IntRect::scale(float s) { m_location.setX((int)(x() * s)); diff --git a/Source/WebCore/platform/graphics/IntRect.h b/Source/WebCore/platform/graphics/IntRect.h index c413e7a..d2b348b 100644 --- a/Source/WebCore/platform/graphics/IntRect.h +++ b/Source/WebCore/platform/graphics/IntRect.h @@ -29,7 +29,7 @@ #include "IntPoint.h" #include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGRect CGRect; #endif @@ -133,6 +133,11 @@ public: setHeight(std::max(0, height() + delta)); } + IntPoint minXMinYCorner() const { return m_location; } // typically topLeft + IntPoint maxXMinYCorner() const { return IntPoint(m_location.x() + m_size.width(), m_location.y()); } // typically topRight + IntPoint minXMaxYCorner() const { return IntPoint(m_location.x(), m_location.y() + m_size.height()); } // typically bottomLeft + IntPoint maxXMaxYCorner() const { return IntPoint(m_location.x() + m_size.width(), m_location.y() + m_size.height()); } // typically bottomRight + bool intersects(const IntRect&) const; bool contains(const IntRect&) const; @@ -144,6 +149,7 @@ public: void intersect(const IntRect&); void unite(const IntRect&); + void uniteIfNonZero(const IntRect&); void inflateX(int dx) { @@ -182,7 +188,7 @@ public: operator Eina_Rectangle() const; #endif -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) operator CGRect() const; #endif @@ -228,7 +234,7 @@ inline bool operator!=(const IntRect& a, const IntRect& b) return a.location() != b.location() || a.size() != b.size(); } -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) IntRect enclosingIntRect(const CGRect&); #endif diff --git a/Source/WebCore/platform/graphics/IntSize.h b/Source/WebCore/platform/graphics/IntSize.h index 9db2224..8cfabf5 100644 --- a/Source/WebCore/platform/graphics/IntSize.h +++ b/Source/WebCore/platform/graphics/IntSize.h @@ -26,7 +26,7 @@ #ifndef IntSize_h #define IntSize_h -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) typedef struct CGSize CGSize; #endif @@ -109,7 +109,7 @@ public: return IntSize(m_height, m_width); } -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) explicit IntSize(const CGSize&); // don't do this implicitly since it's lossy operator CGSize() const; #endif diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp index 03004b6..a7e4b90 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.cpp +++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp @@ -792,11 +792,12 @@ void MediaPlayer::networkStateChanged() // If more than one media engine is installed and this one failed before finding metadata, // let the next engine try. if (m_private->networkState() >= FormatError - && m_private->readyState() < HaveMetadata - && installedMediaEngines().size() > 1 - && bestMediaEngineForTypeAndCodecs(m_contentMIMEType, m_contentTypeCodecs, m_currentMediaEngine)) { + && m_private->readyState() < HaveMetadata + && installedMediaEngines().size() > 1) { + if ( m_contentMIMEType.isEmpty() || bestMediaEngineForTypeAndCodecs(m_contentMIMEType, m_contentTypeCodecs, m_currentMediaEngine)) { m_reloadTimer.startOneShot(0); return; + } } if (m_mediaPlayerClient) m_mediaPlayerClient->mediaPlayerNetworkStateChanged(this); @@ -858,6 +859,12 @@ void MediaPlayer::playbackStateChanged() m_mediaPlayerClient->mediaPlayerPlaybackStateChanged(this); } +void MediaPlayer::firstVideoFrameAvailable() +{ + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerFirstVideoFrameAvailable(this); +} + } #endif diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h index ff304ea..41cb6d2 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.h +++ b/Source/WebCore/platform/graphics/MediaPlayer.h @@ -143,6 +143,10 @@ public: virtual void mediaPlayerEngineUpdated(MediaPlayer*) { } + // The first frame of video is available to render. A media engine need only make this callback if the + // first frame is not available immediately when prepareForRendering is called. + virtual void mediaPlayerFirstVideoFrameAvailable(MediaPlayer*) { } + #if USE(ACCELERATED_COMPOSITING) // whether the rendering system can accelerate the display of this MediaPlayer. virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) { return false; } @@ -262,6 +266,7 @@ public: void rateChanged(); void playbackStateChanged(); void durationChanged(); + void firstVideoFrameAvailable(); void repaint(); diff --git a/Source/WebCore/platform/graphics/Path.cpp b/Source/WebCore/platform/graphics/Path.cpp index f7aedbe..da09c76 100644 --- a/Source/WebCore/platform/graphics/Path.cpp +++ b/Source/WebCore/platform/graphics/Path.cpp @@ -188,4 +188,9 @@ void Path::addRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, closeSubpath(); } +void Path::addRoundedRect(const RoundedIntRect& r) +{ + addRoundedRect(r.rect(), r.radii().topLeft(), r.radii().topRight(), r.radii().bottomLeft(), r.radii().bottomRight()); +} + } diff --git a/Source/WebCore/platform/graphics/Path.h b/Source/WebCore/platform/graphics/Path.h index c2ca576..9c07247 100644 --- a/Source/WebCore/platform/graphics/Path.h +++ b/Source/WebCore/platform/graphics/Path.h @@ -28,10 +28,11 @@ #ifndef Path_h #define Path_h +#include "RoundedIntRect.h" #include <wtf/FastAllocBase.h> #include <wtf/Forward.h> -#if PLATFORM(CG) +#if USE(CG) typedef struct CGPath PlatformPath; #elif PLATFORM(OPENVG) namespace WebCore { @@ -44,7 +45,7 @@ typedef QPainterPath PlatformPath; #elif PLATFORM(WX) && USE(WXGC) class wxGraphicsPath; typedef wxGraphicsPath PlatformPath; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) namespace WebCore { class CairoPath; } @@ -137,6 +138,7 @@ namespace WebCore { void addEllipse(const FloatRect&); void addRoundedRect(const FloatRect&, const FloatSize& roundingRadii); void addRoundedRect(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); + void addRoundedRect(const RoundedIntRect&); void translate(const FloatSize&); diff --git a/Source/WebCore/platform/graphics/Pattern.h b/Source/WebCore/platform/graphics/Pattern.h index c88f2fb..1d0b0f8 100644 --- a/Source/WebCore/platform/graphics/Pattern.h +++ b/Source/WebCore/platform/graphics/Pattern.h @@ -35,10 +35,10 @@ #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> -#if PLATFORM(CG) +#if USE(CG) typedef struct CGPattern* CGPatternRef; typedef CGPatternRef PlatformPatternPtr; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include <cairo.h> typedef cairo_pattern_t* PlatformPatternPtr; #elif USE(SKIA) diff --git a/Source/WebCore/platform/graphics/RoundedIntRect.cpp b/Source/WebCore/platform/graphics/RoundedIntRect.cpp index 4e80c9a..e919c4f 100644 --- a/Source/WebCore/platform/graphics/RoundedIntRect.cpp +++ b/Source/WebCore/platform/graphics/RoundedIntRect.cpp @@ -30,6 +30,8 @@ #include "IntRect.h" #include <algorithm> +using namespace std; + namespace WebCore { bool RoundedIntRect::Radii::isZero() const @@ -60,17 +62,17 @@ void RoundedIntRect::Radii::scale(float factor) void RoundedIntRect::Radii::expand(int topWidth, int bottomWidth, int leftWidth, int rightWidth) { - m_topLeft.setWidth(std::max(0, m_topLeft.width() + leftWidth)); - m_topLeft.setHeight(std::max(0, m_topLeft.height() + topWidth)); + m_topLeft.setWidth(max(0, m_topLeft.width() + leftWidth)); + m_topLeft.setHeight(max(0, m_topLeft.height() + topWidth)); - m_topRight.setWidth(std::max(0, m_topRight.width() + rightWidth)); - m_topRight.setHeight(std::max(0, m_topRight.height() + topWidth)); + m_topRight.setWidth(max(0, m_topRight.width() + rightWidth)); + m_topRight.setHeight(max(0, m_topRight.height() + topWidth)); - m_bottomLeft.setWidth(std::max(0, m_bottomLeft.width() + leftWidth)); - m_bottomLeft.setHeight(std::max(0, m_bottomLeft.height() + bottomWidth)); + m_bottomLeft.setWidth(max(0, m_bottomLeft.width() + leftWidth)); + m_bottomLeft.setHeight(max(0, m_bottomLeft.height() + bottomWidth)); - m_bottomRight.setWidth(std::max(0, m_bottomRight.width() + rightWidth)); - m_bottomRight.setHeight(std::max(0, m_bottomRight.height() + bottomWidth)); + m_bottomRight.setWidth(max(0, m_bottomRight.width() + rightWidth)); + m_bottomRight.setHeight(max(0, m_bottomRight.height() + bottomWidth)); } void RoundedIntRect::Radii::includeLogicalEdges(const RoundedIntRect::Radii& edges, bool isHorizontal, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) @@ -138,4 +140,12 @@ void RoundedIntRect::excludeLogicalEdges(bool isHorizontal, bool excludeLogicalL m_radii.excludeLogicalEdges(isHorizontal, excludeLogicalLeftEdge, excludeLogicalRightEdge); } +bool RoundedIntRect::isRenderable() const +{ + return m_radii.topLeft().width() + m_radii.topRight().width() <= m_rect.width() + && m_radii.bottomLeft().width() + m_radii.bottomRight().width() <= m_rect.width() + && m_radii.topLeft().height() + m_radii.topRight().height() <= m_rect.height() + && m_radii.bottomLeft().height() + m_radii.bottomRight().height() <= m_rect.height(); +} + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/RoundedIntRect.h b/Source/WebCore/platform/graphics/RoundedIntRect.h index c3c972f..74ee892 100644 --- a/Source/WebCore/platform/graphics/RoundedIntRect.h +++ b/Source/WebCore/platform/graphics/RoundedIntRect.h @@ -93,11 +93,24 @@ public: void includeLogicalEdges(const Radii& edges, bool isHorizontal, bool includeLogicalLeftEdge, bool includeLogicalRightEdge); void excludeLogicalEdges(bool isHorizontal, bool excludeLogicalLeftEdge, bool excludeLogicalRightEdge); + bool isRenderable() const; + private: IntRect m_rect; Radii m_radii; }; +inline bool operator==(const RoundedIntRect::Radii& a, const RoundedIntRect::Radii& b) +{ + return a.topLeft() == b.topLeft() && a.topRight() == b.topRight() && a.bottomLeft() == b.bottomLeft() && a.bottomRight() == b.bottomRight(); +} + +inline bool operator==(const RoundedIntRect& a, const RoundedIntRect& b) +{ + return a.rect() == b.rect() && a.radii() == b.radii(); +} + + } // namespace WebCore #endif // RoundedIntRect_h diff --git a/Source/WebCore/platform/graphics/ShadowBlur.cpp b/Source/WebCore/platform/graphics/ShadowBlur.cpp index 0df51a4..2f25221 100644 --- a/Source/WebCore/platform/graphics/ShadowBlur.cpp +++ b/Source/WebCore/platform/graphics/ShadowBlur.cpp @@ -54,6 +54,8 @@ class ScratchBuffer { public: ScratchBuffer() : m_purgeTimer(this, &ScratchBuffer::timerFired) + , m_lastRadius(0) + , m_lastWasInset(false) #if !ASSERT_DISABLED , m_bufferInUse(false) #endif @@ -77,6 +79,41 @@ public: return m_imageBuffer.get(); } + void setLastShadowValues(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) + { + m_lastWasInset = false; + m_lastRadius = radius; + m_lastColor = color; + m_lastColorSpace = colorSpace; + m_lastShadowRect = shadowRect; + m_lastRadii = radii; + } + + void setLastInsetShadowValues(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& bounds, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) + { + m_lastWasInset = true; + m_lastInsetBounds = bounds; + m_lastRadius = radius; + m_lastColor = color; + m_lastColorSpace = colorSpace; + m_lastShadowRect = shadowRect; + m_lastRadii = radii; + } + + bool matchesLastShadow(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) const + { + if (m_lastWasInset) + return false; + return m_lastRadius == radius && m_lastColor == color && m_lastColorSpace == colorSpace && shadowRect == m_lastShadowRect && radii == m_lastRadii; + } + + bool matchesLastInsetShadow(float radius, const Color& color, ColorSpace colorSpace, const FloatRect& bounds, const FloatRect& shadowRect, const RoundedIntRect::Radii& radii) const + { + if (!m_lastWasInset) + return false; + return m_lastRadius == radius && m_lastColor == color && m_lastColorSpace == colorSpace && m_lastInsetBounds == bounds && shadowRect == m_lastShadowRect && radii == m_lastRadii; + } + void scheduleScratchBufferPurge() { #if !ASSERT_DISABLED @@ -100,10 +137,20 @@ private: void clearScratchBuffer() { m_imageBuffer = 0; + m_lastRadius = 0; } OwnPtr<ImageBuffer> m_imageBuffer; Timer<ScratchBuffer> m_purgeTimer; + + FloatRect m_lastInsetBounds; + FloatRect m_lastShadowRect; + RoundedIntRect::Radii m_lastRadii; + Color m_lastColor; + ColorSpace m_lastColorSpace; + float m_lastRadius; + bool m_lastWasInset; + #if !ASSERT_DISABLED bool m_bufferInUse; #endif @@ -147,14 +194,7 @@ static const int blurSumShift = 15; void ShadowBlur::blurLayerImage(unsigned char* imageData, const IntSize& size, int rowStride) { - const int channels[4] = -#if CPU(BIG_ENDIAN) - { 0, 3, 2, 0 }; -#elif CPU(MIDDLE_ENDIAN) - { 1, 2, 3, 1 }; -#else - { 3, 0, 1, 3 }; -#endif + const int channels[4] = { 3, 0, 1, 3 }; int diameter; if (m_shadowsIgnoreTransforms) @@ -356,40 +396,10 @@ IntRect ShadowBlur::calculateLayerBoundingRect(GraphicsContext* context, const F return enclosingIntRect(layerRect); } -GraphicsContext* ShadowBlur::beginShadowLayer(GraphicsContext* graphicsContext, const IntRect& layerRect) -{ - adjustBlurRadius(graphicsContext); - - // Don't paint if we are totally outside the clip region. - if (layerRect.isEmpty()) - return 0; - - m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); - GraphicsContext* layerContext = m_layerImage->context(); - - layerContext->save(); // Balanced by restore() in endShadowLayer(). - - // Always clear the surface first. FIXME: we could avoid the clear on first allocation. - // Add a pixel to avoid later edge aliasing when rotated. - layerContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); - layerContext->translate(m_layerContextTranslation); - - return layerContext; -} - -void ShadowBlur::endShadowLayer(GraphicsContext* graphicsContext) +void ShadowBlur::drawShadowBuffer(GraphicsContext* graphicsContext) { if (!m_layerImage) return; - - m_layerImage->context()->restore(); - - if (m_type == BlurShadow) { - IntRect blurRect = enclosingIntRect(FloatRect(FloatPoint(), m_layerSize)); - RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); - blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); - m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); - } graphicsContext->save(); @@ -406,11 +416,6 @@ void ShadowBlur::endShadowLayer(GraphicsContext* graphicsContext) graphicsContext->fillRect(FloatRect(m_layerOrigin, m_sourceRect.size())); graphicsContext->restore(); - - m_layerImage = 0; - - // Schedule a purge of the scratch buffer. We do not need to destroy the surface. - ScratchBuffer::shared().scheduleScratchBufferPurge(); } static void computeSliceSizesFromRadii(int twiceRadius, const RoundedIntRect::Radii& radii, int& leftSlice, int& rightSlice, int& topSlice, int& bottomSlice) @@ -442,6 +447,8 @@ void ShadowBlur::drawRectShadow(GraphicsContext* graphicsContext, const FloatRec if (layerRect.isEmpty()) return; + adjustBlurRadius(graphicsContext); + // drawRectShadowWithTiling does not work with rotations. // https://bugs.webkit.org/show_bug.cgi?id=45042 if (!graphicsContext->getCTM().isIdentityOrTranslationOrFlipped() || m_type != BlurShadow) { @@ -466,6 +473,8 @@ void ShadowBlur::drawInsetShadow(GraphicsContext* graphicsContext, const FloatRe if (layerRect.isEmpty()) return; + adjustBlurRadius(graphicsContext); + // drawInsetShadowWithTiling does not work with rotations. // https://bugs.webkit.org/show_bug.cgi?id=45042 if (!graphicsContext->getCTM().isIdentityOrTranslationOrFlipped() || m_type != BlurShadow) { @@ -486,34 +495,81 @@ void ShadowBlur::drawInsetShadow(GraphicsContext* graphicsContext, const FloatRe void ShadowBlur::drawRectShadowWithoutTiling(GraphicsContext* graphicsContext, const FloatRect& shadowedRect, const RoundedIntRect::Radii& radii, const IntRect& layerRect) { - GraphicsContext* shadowContext = beginShadowLayer(graphicsContext, layerRect); - if (!shadowContext) + m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); + if (!m_layerImage) return; - Path path; - path.addRoundedRect(shadowedRect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + FloatRect bufferRelativeShadowedRect = shadowedRect; + bufferRelativeShadowedRect.move(m_layerContextTranslation); + if (!ScratchBuffer::shared().matchesLastShadow(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeShadowedRect, radii)) { + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); + + // Add a pixel to avoid later edge aliasing when rotated. + shadowContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); + shadowContext->translate(m_layerContextTranslation); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + if (radii.isZero()) + shadowContext->fillRect(shadowedRect); + else { + Path path; + path.addRoundedRect(shadowedRect, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + shadowContext->fillPath(path); + } + + blurShadowBuffer(expandedIntSize(m_layerSize)); - shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); - shadowContext->fillPath(path); + shadowContext->restore(); + + ScratchBuffer::shared().setLastShadowValues(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeShadowedRect, radii); + } - endShadowLayer(graphicsContext); + drawShadowBuffer(graphicsContext); + m_layerImage = 0; + ScratchBuffer::shared().scheduleScratchBufferPurge(); } void ShadowBlur::drawInsetShadowWithoutTiling(GraphicsContext* graphicsContext, const FloatRect& rect, const FloatRect& holeRect, const RoundedIntRect::Radii& holeRadii, const IntRect& layerRect) { - GraphicsContext* shadowContext = beginShadowLayer(graphicsContext, layerRect); - if (!shadowContext) + m_layerImage = ScratchBuffer::shared().getScratchBuffer(layerRect.size()); + if (!m_layerImage) return; - Path path; - path.addRect(rect); - path.addRoundedRect(holeRect, holeRadii.topLeft(), holeRadii.topRight(), holeRadii.bottomLeft(), holeRadii.bottomRight()); + FloatRect bufferRelativeRect = rect; + bufferRelativeRect.move(m_layerContextTranslation); + + FloatRect bufferRelativeHoleRect = holeRect; + bufferRelativeHoleRect.move(m_layerContextTranslation); - shadowContext->setFillRule(RULE_EVENODD); - shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); - shadowContext->fillPath(path); + if (!ScratchBuffer::shared().matchesLastInsetShadow(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeRect, bufferRelativeHoleRect, holeRadii)) { + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); - endShadowLayer(graphicsContext); + // Add a pixel to avoid later edge aliasing when rotated. + shadowContext->clearRect(FloatRect(0, 0, m_layerSize.width() + 1, m_layerSize.height() + 1)); + shadowContext->translate(m_layerContextTranslation); + + Path path; + path.addRect(rect); + if (holeRadii.isZero()) + path.addRect(holeRect); + else + path.addRoundedRect(holeRect, holeRadii.topLeft(), holeRadii.topRight(), holeRadii.bottomLeft(), holeRadii.bottomRight()); + + shadowContext->setFillRule(RULE_EVENODD); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + shadowContext->fillPath(path); + + blurShadowBuffer(expandedIntSize(m_layerSize)); + + shadowContext->restore(); + + ScratchBuffer::shared().setLastInsetShadowValues(m_blurRadius, Color::black, ColorSpaceDeviceRGB, bufferRelativeRect, bufferRelativeHoleRect, holeRadii); + } + + drawShadowBuffer(graphicsContext); + m_layerImage = 0; + ScratchBuffer::shared().scheduleScratchBufferPurge(); } /* @@ -557,23 +613,35 @@ void ShadowBlur::drawInsetShadowWithTiling(GraphicsContext* graphicsContext, con const float twiceRadius = roundedRadius * 2; m_layerImage = ScratchBuffer::shared().getScratchBuffer(templateSize); + if (!m_layerImage) + return; // Draw the rectangle with hole. FloatRect templateBounds(0, 0, templateSize.width(), templateSize.height()); FloatRect templateHole = FloatRect(roundedRadius, roundedRadius, templateSize.width() - twiceRadius, templateSize.height() - twiceRadius); - Path path; - path.addRect(templateBounds); - path.addRoundedRect(templateHole, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); - // Draw shadow into a new ImageBuffer. - GraphicsContext* shadowContext = m_layerImage->context(); - shadowContext->save(); - shadowContext->clearRect(templateBounds); - shadowContext->setFillRule(RULE_EVENODD); - shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); - shadowContext->fillPath(path); - blurAndColorShadowBuffer(templateSize); - shadowContext->restore(); + if (!ScratchBuffer::shared().matchesLastInsetShadow(m_blurRadius, m_color, m_colorSpace, templateBounds, templateHole, radii)) { + // Draw shadow into a new ImageBuffer. + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); + shadowContext->clearRect(templateBounds); + shadowContext->setFillRule(RULE_EVENODD); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + + Path path; + path.addRect(templateBounds); + if (radii.isZero()) + path.addRect(templateHole); + else + path.addRoundedRect(templateHole, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + + shadowContext->fillPath(path); + + blurAndColorShadowBuffer(templateSize); + shadowContext->restore(); + + ScratchBuffer::shared().setLastInsetShadowValues(m_blurRadius, m_color, m_colorSpace, templateBounds, templateHole, radii); + } FloatRect boundingRect = rect; boundingRect.move(m_offset); @@ -599,7 +667,6 @@ void ShadowBlur::drawInsetShadowWithTiling(GraphicsContext* graphicsContext, con graphicsContext->restore(); m_layerImage = 0; - // Schedule a purge of the scratch buffer. ScratchBuffer::shared().scheduleScratchBufferPurge(); } @@ -612,20 +679,31 @@ void ShadowBlur::drawRectShadowWithTiling(GraphicsContext* graphicsContext, cons const float twiceRadius = roundedRadius * 2; m_layerImage = ScratchBuffer::shared().getScratchBuffer(templateSize); + if (!m_layerImage) + return; - // Draw the rectangle. FloatRect templateShadow = FloatRect(roundedRadius, roundedRadius, templateSize.width() - twiceRadius, templateSize.height() - twiceRadius); - Path path; - path.addRoundedRect(templateShadow, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); - // Draw shadow into the ImageBuffer. - GraphicsContext* shadowContext = m_layerImage->context(); - shadowContext->save(); - shadowContext->clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height())); - shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); - shadowContext->fillPath(path); - blurAndColorShadowBuffer(templateSize); - shadowContext->restore(); + if (!ScratchBuffer::shared().matchesLastShadow(m_blurRadius, m_color, m_colorSpace, templateShadow, radii)) { + // Draw shadow into the ImageBuffer. + GraphicsContext* shadowContext = m_layerImage->context(); + shadowContext->save(); + shadowContext->clearRect(FloatRect(0, 0, templateSize.width(), templateSize.height())); + shadowContext->setFillColor(Color::black, ColorSpaceDeviceRGB); + + if (radii.isZero()) + shadowContext->fillRect(templateShadow); + else { + Path path; + path.addRoundedRect(templateShadow, radii.topLeft(), radii.topRight(), radii.bottomLeft(), radii.bottomRight()); + shadowContext->fillPath(path); + } + + blurAndColorShadowBuffer(templateSize); + shadowContext->restore(); + + ScratchBuffer::shared().setLastShadowValues(m_blurRadius, m_color, m_colorSpace, templateShadow, radii); + } FloatRect shadowBounds = shadowedRect; shadowBounds.move(m_offset.width(), m_offset.height()); @@ -636,7 +714,6 @@ void ShadowBlur::drawRectShadowWithTiling(GraphicsContext* graphicsContext, cons graphicsContext->restore(); m_layerImage = 0; - // Schedule a purge of the scratch buffer. ScratchBuffer::shared().scheduleScratchBufferPurge(); } @@ -714,14 +791,20 @@ void ShadowBlur::drawLayerPieces(GraphicsContext* graphicsContext, const FloatRe } +void ShadowBlur::blurShadowBuffer(const IntSize& templateSize) +{ + if (m_type != BlurShadow) + return; + + IntRect blurRect(IntPoint(), templateSize); + RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); + blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); + m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); +} + void ShadowBlur::blurAndColorShadowBuffer(const IntSize& templateSize) { - { - IntRect blurRect(IntPoint(), templateSize); - RefPtr<ByteArray> layerData = m_layerImage->getUnmultipliedImageData(blurRect); - blurLayerImage(layerData->data(), blurRect.size(), blurRect.width() * 4); - m_layerImage->putUnmultipliedImageData(layerData.get(), blurRect.size(), blurRect, IntPoint()); - } + blurShadowBuffer(templateSize); // Mask the image with the shadow color. GraphicsContext* shadowContext = m_layerImage->context(); diff --git a/Source/WebCore/platform/graphics/ShadowBlur.h b/Source/WebCore/platform/graphics/ShadowBlur.h index e52d6dc..4ba8e23 100644 --- a/Source/WebCore/platform/graphics/ShadowBlur.h +++ b/Source/WebCore/platform/graphics/ShadowBlur.h @@ -53,8 +53,7 @@ public: void drawInsetShadow(GraphicsContext*, const FloatRect&, const FloatRect& holeRect, const RoundedIntRect::Radii& holeRadii); private: - GraphicsContext* beginShadowLayer(GraphicsContext*, const IntRect& layerRect); - void endShadowLayer(GraphicsContext*); + void drawShadowBuffer(GraphicsContext*); void adjustBlurRadius(GraphicsContext*); void blurLayerImage(unsigned char*, const IntSize&, int stride); @@ -75,6 +74,7 @@ private: void drawLayerPieces(GraphicsContext*, const FloatRect& shadowBounds, const RoundedIntRect::Radii&, float roundedRadius, const IntSize& templateSize, ShadowDirection); + void blurShadowBuffer(const IntSize& templateSize); void blurAndColorShadowBuffer(const IntSize& templateSize); enum ShadowType { diff --git a/Source/WebCore/platform/graphics/SimpleFontData.h b/Source/WebCore/platform/graphics/SimpleFontData.h index dfb4be3..67e864a 100644 --- a/Source/WebCore/platform/graphics/SimpleFontData.h +++ b/Source/WebCore/platform/graphics/SimpleFontData.h @@ -48,7 +48,7 @@ typedef struct OpaqueATSUStyle* ATSUStyle; #include <usp10.h> #endif -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include <cairo.h> #endif @@ -115,7 +115,7 @@ public: float spaceWidth() const { return m_spaceWidth; } -#if PLATFORM(CG) || PLATFORM(CAIRO) || PLATFORM(WX) +#if USE(CG) || USE(CAIRO) || PLATFORM(WX) || USE(SKIA_ON_MAC_CHROME) float syntheticBoldOffset() const { return m_syntheticBoldOffset; } #endif @@ -252,7 +252,7 @@ private: mutable OwnPtr<DerivedFontData> m_derivedFontData; -#if PLATFORM(CG) || PLATFORM(CAIRO) || PLATFORM(WX) +#if USE(CG) || USE(CAIRO) || PLATFORM(WX) || USE(SKIA_ON_MAC_CHROME) float m_syntheticBoldOffset; #endif diff --git a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp index 80a6dcb..d54f3df 100644 --- a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp +++ b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp @@ -43,7 +43,7 @@ #define ntohs(x) std_ntohs(x) #endif -#if PLATFORM(WIN) +#if OS(WINDOWS) #if CPU(BIG_ENDIAN) #define ntohs(x) ((uint16_t)(x)) #define htons(x) ((uint16_t)(x)) @@ -61,7 +61,7 @@ (((uint32_t)(x) & 0x0000ff00) << 8) | (((uint32_t)(x) & 0x000000ff) << 24))) #define htonl(x) ntohl(x) #endif -#endif // PLATFORM(WIN) +#endif // OS(WINDOWS) namespace WebCore { diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp index eb96532..681003f 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp @@ -74,6 +74,8 @@ MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(MediaPlayer* play , m_cachedHasVideo(false) , m_cachedHasCaptions(false) , m_ignoreLoadStateChanges(false) + , m_haveReportedFirstVideoFrame(false) + , m_playWhenFramesAvailable(false) { LOG(Media, "MediaPlayerPrivateAVFoundation::MediaPlayerPrivateAVFoundation(%p)", this); } @@ -248,6 +250,25 @@ void MediaPlayerPrivateAVFoundation::prepareToPlay() checkPlayability(); } +void MediaPlayerPrivateAVFoundation::play() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::play(%p)", this); + + // If the file has video, don't request playback until the first frame of video is ready to display + // or the audio may start playing before we can render video. + if (!m_cachedHasVideo || hasAvailableVideoFrame()) + platformPlay(); + else + m_playWhenFramesAvailable = true; +} + +void MediaPlayerPrivateAVFoundation::pause() +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::pause(%p)", this); + m_playWhenFramesAvailable = false; + platformPause(); +} + void MediaPlayerPrivateAVFoundation::paint(GraphicsContext*, const IntRect&) { // This is the base class, only need to remember that a frame has been drawn. @@ -285,6 +306,8 @@ void MediaPlayerPrivateAVFoundation::setRate(float rate) { LOG(Media, "MediaPlayerPrivateAVFoundation::setRate(%p) - seting to %f", this, rate); m_requestedRate = rate; + + updateRate(); } bool MediaPlayerPrivateAVFoundation::paused() const @@ -464,12 +487,22 @@ void MediaPlayerPrivateAVFoundation::updateStates() if (isReadyForVideoSetup() && currentRenderingMode() != preferredRenderingMode()) setUpVideoRendering(); + if (!m_haveReportedFirstVideoFrame && m_cachedHasVideo && hasAvailableVideoFrame()) { + m_haveReportedFirstVideoFrame = true; + m_player->firstVideoFrameAvailable(); + } + if (m_networkState != oldNetworkState) m_player->networkStateChanged(); if (m_readyState != oldReadyState) m_player->readyStateChanged(); + if (m_playWhenFramesAvailable && hasAvailableVideoFrame()) { + m_playWhenFramesAvailable = false; + platformPlay(); + } + LOG(Media, "MediaPlayerPrivateAVFoundation::updateStates(%p) - exiting with networkState = %i, readyState = %i", this, static_cast<int>(m_networkState), static_cast<int>(m_readyState)); } @@ -566,6 +599,14 @@ void MediaPlayerPrivateAVFoundation::timeChanged(double time) } } +void MediaPlayerPrivateAVFoundation::seekCompleted(bool finished) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::seekCompleted(%p) - finished = %d", this, finished); + + if (finished) + m_seekTo = invalidTime; +} + void MediaPlayerPrivateAVFoundation::didEnd() { // Hang onto the current time and use it as duration from now on since we are definitely at @@ -629,12 +670,22 @@ void MediaPlayerPrivateAVFoundation::clearMainThreadPendingFlag() void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, double time) { - LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %d", this, static_cast<int>(type)); + scheduleMainThreadNotification(Notification(type, time)); +} + +void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification::Type type, bool finished) +{ + scheduleMainThreadNotification(Notification(type, finished)); +} + +void MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(Notification notification) +{ + LOG(Media, "MediaPlayerPrivateAVFoundation::scheduleMainThreadNotification(%p) - notification %d", this, static_cast<int>(notification.type())); m_queueMutex.lock(); // It is important to always process the properties in the order that we are notified, // so always go through the queue because notifications happen on different threads. - m_queuedNotifications.append(Notification(type, time)); + m_queuedNotifications.append(notification); bool delayDispatch = m_delayCallbacks || !isMainThread(); if (delayDispatch && !m_mainThreadCallPending) { @@ -714,6 +765,9 @@ void MediaPlayerPrivateAVFoundation::dispatchNotification() case Notification::PlayerTimeChanged: timeChanged(notification.time()); break; + case Notification::SeekCompleted: + seekCompleted(notification.finished()); + break; case Notification::AssetMetadataLoaded: metadataLoaded(); break; diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h index a768ab4..becba61 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h @@ -48,6 +48,7 @@ public: virtual void loadedTimeRangesChanged(); virtual void seekableTimeRangesChanged(); virtual void timeChanged(double); + virtual void seekCompleted(bool); virtual void didEnd(); class Notification { @@ -66,31 +67,45 @@ public: AssetMetadataLoaded, AssetPlayabilityKnown, PlayerRateChanged, - PlayerTimeChanged + PlayerTimeChanged, + SeekCompleted, }; Notification() : m_type(None) , m_time(0) + , m_finished(false) { } Notification(Type type, double time) : m_type(type) , m_time(time) + , m_finished(false) + { + } + + Notification(Type type, bool finished) + : m_type(type) + , m_time(0) + , m_finished(finished) { } Type type() { return m_type; } bool isValid() { return m_type != None; } double time() { return m_time; } + bool finished() { return m_finished; } private: Type m_type; double m_time; + bool m_finished; }; + void scheduleMainThreadNotification(Notification); void scheduleMainThreadNotification(Notification::Type, double time = 0); + void scheduleMainThreadNotification(Notification::Type, bool completed); void dispatchNotification(); void clearMainThreadPendingFlag(); @@ -105,8 +120,8 @@ protected: virtual void prepareToPlay(); virtual PlatformMedia platformMedia() const = 0; - virtual void play() = 0; - virtual void pause() = 0; + virtual void play(); + virtual void pause(); virtual IntSize naturalSize() const; virtual bool hasVideo() const { return m_cachedHasVideo; } @@ -169,7 +184,10 @@ protected: }; virtual AVAssetStatus assetStatus() const = 0; + virtual void platformPlay() = 0; + virtual void platformPause() = 0; virtual void checkPlayability() = 0; + virtual void updateRate() = 0; virtual float rate() const = 0; virtual void seekToTime(float time) = 0; virtual unsigned totalBytes() const = 0; @@ -254,6 +272,8 @@ private: bool m_cachedHasVideo; bool m_cachedHasCaptions; bool m_ignoreLoadStateChanges; + bool m_haveReportedFirstVideoFrame; + bool m_playWhenFramesAvailable; }; } diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h index cc00c15..7f214b8 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.h @@ -73,8 +73,8 @@ private: virtual PlatformMedia platformMedia() const; - virtual void play(); - virtual void pause(); + virtual void platformPlay(); + virtual void platformPause(); virtual float currentTime() const; virtual void setVolume(float); virtual void setClosedCaptionsVisible(bool); @@ -93,6 +93,7 @@ private: virtual MediaPlayerPrivateAVFoundation::AVAssetStatus assetStatus() const; virtual void checkPlayability(); + virtual void updateRate(); virtual float rate() const; virtual void seekToTime(float time); virtual unsigned totalBytes() const; diff --git a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm index 55eb433..c4efb9f 100644 --- a/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm +++ b/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm @@ -100,6 +100,7 @@ enum MediaPlayerAVFoundationObservationContext { -(void)playableKnown; -(void)metadataLoaded; -(void)timeChanged:(double)time; +-(void)seekCompleted:(BOOL)finished; -(void)didEnd:(NSNotification *)notification; -(void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary *)change context:(MediaPlayerAVFoundationObservationContext)context; @end @@ -200,7 +201,7 @@ void MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer() if (!m_imageGenerator) return; - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying", this, m_imageGenerator.get()); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::destroyContextVideoRenderer(%p) - destroying %p", this, m_imageGenerator.get()); m_imageGenerator = 0; } @@ -213,7 +214,7 @@ void MediaPlayerPrivateAVFoundationObjC::createVideoLayer() if (!m_videoLayer) { m_videoLayer.adoptNS([[AVPlayerLayer alloc] init]); [m_videoLayer.get() setPlayer:m_avPlayer.get()]; - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoLayer(%p) - returning", this, m_videoLayer.get()); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::createVideoLayer(%p) - returning %p", this, m_videoLayer.get()); } } @@ -327,9 +328,9 @@ MediaPlayerPrivateAVFoundation::ItemStatus MediaPlayerPrivateAVFoundationObjC::p return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusFailed; if ([m_avPlayerItem.get() isPlaybackLikelyToKeepUp]) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp; - if ([m_avPlayerItem.get() isPlaybackBufferFull]) + if (buffered()->contain(duration())) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferFull; - if ([m_avPlayerItem.get() isPlaybackBufferEmpty]) + if (buffered()->contain(currentTime())) return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty; return MediaPlayerPrivateAVFoundation::MediaPlayerAVPlayerItemStatusReadyToPlay; @@ -350,9 +351,9 @@ PlatformLayer* MediaPlayerPrivateAVFoundationObjC::platformLayer() const return m_videoLayer.get(); } -void MediaPlayerPrivateAVFoundationObjC::play() +void MediaPlayerPrivateAVFoundationObjC::platformPlay() { - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::play(%p)", this); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformPlay(%p)", this); if (!metaDataAvailable()) return; @@ -361,9 +362,9 @@ void MediaPlayerPrivateAVFoundationObjC::play() setDelayCallbacks(false); } -void MediaPlayerPrivateAVFoundationObjC::pause() +void MediaPlayerPrivateAVFoundationObjC::platformPause() { - LOG(Media, "MediaPlayerPrivateAVFoundationObjC::pause(%p)", this); + LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformPause(%p)", this); if (!metaDataAvailable()) return; @@ -408,14 +409,10 @@ void MediaPlayerPrivateAVFoundationObjC::seekToTime(float time) // setCurrentTime generates several event callbacks, update afterwards. setDelayCallbacks(true); - float now = currentTime(); - if (time != now) - [m_avPlayerItem.get() seekToTime:CMTimeMakeWithSeconds(time, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; - else { - // Force a call to the "time changed" notifier manually because a seek to the current time is a noop - // so the seek will never seem to complete. - [m_objcObserver.get() timeChanged:now]; - } + WebCoreAVFMovieObserver *observer = m_objcObserver.get(); + [m_avPlayerItem.get() seekToTime:CMTimeMakeWithSeconds(time, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) { + [observer seekCompleted:finished]; + }]; setDelayCallbacks(false); } @@ -437,6 +434,13 @@ void MediaPlayerPrivateAVFoundationObjC::setClosedCaptionsVisible(bool closedCap [m_avPlayer.get() setClosedCaptionDisplayEnabled:closedCaptionsVisible]; } +void MediaPlayerPrivateAVFoundationObjC::updateRate() +{ + setDelayCallbacks(true); + [m_avPlayer.get() setRate:requestedRate()]; + setDelayCallbacks(false); +} + float MediaPlayerPrivateAVFoundationObjC::rate() const { if (!metaDataAvailable()) @@ -621,12 +625,16 @@ void MediaPlayerPrivateAVFoundationObjC::getSupportedTypes(HashSet<String>& supp MediaPlayer::SupportsType MediaPlayerPrivateAVFoundationObjC::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 if it supports an - // extended MIME type until rdar://6220037 is fixed. - if (mimeTypeCache().contains(type)) - return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported; + if (!mimeTypeCache().contains(type)) + return MediaPlayer::IsNotSupported; + + // The spec says: + // "Implementors are encouraged to return "maybe" unless the type can be confidently established as being supported or not." + if (codecs.isEmpty()) + return MediaPlayer::MayBeSupported; - return MediaPlayer::IsNotSupported; + NSString *typeString = [NSString stringWithFormat:@"%@; codecs=\"%@\"", (NSString *)type, (NSString *)codecs]; + return [AVURLAsset isPlayableExtendedMIMEType:typeString] ? MediaPlayer::IsSupported : MediaPlayer::MayBeSupported;; } bool MediaPlayerPrivateAVFoundationObjC::isAvailable() @@ -758,6 +766,14 @@ NSArray* itemKVOProperties() m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerTimeChanged, time); } +- (void)seekCompleted:(BOOL)finished +{ + if (!m_callback) + return; + + m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::SeekCompleted, static_cast<bool>(finished)); +} + - (void)didEnd:(NSNotification *)unusedNotification { UNUSED_PARAM(unusedNotification); diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp index 427c7bf..8fb4c9f 100644 --- a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp +++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp @@ -255,6 +255,7 @@ GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) , m_contentsLayerHasBackgroundColor(false) , m_uncommittedChanges(NoChange) , m_contentsScale(1) + , m_allowTiledLayer(true) { m_layer = PlatformCALayer::create(PlatformCALayer::LayerTypeWebLayer, this); @@ -492,6 +493,17 @@ void GraphicsLayerCA::setAcceleratesDrawing(bool acceleratesDrawing) noteLayerPropertyChanged(AcceleratesDrawingChanged); } +void GraphicsLayerCA::setAllowTiledLayer(bool allowTiledLayer) +{ + if (allowTiledLayer == m_allowTiledLayer) + return; + + m_allowTiledLayer = allowTiledLayer; + + // Handling this as a SizeChanged will cause use to switch in or out of tiled layer as needed + noteLayerPropertyChanged(SizeChanged); +} + void GraphicsLayerCA::setBackgroundColor(const Color& color) { if (m_backgroundColorSet && m_backgroundColor == color) @@ -2005,7 +2017,7 @@ FloatSize GraphicsLayerCA::constrainedSize() const bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const { - if (!m_drawsContent) + if (!m_drawsContent || !m_allowTiledLayer) return false; // FIXME: catch zero-size height or width here (or earlier)? diff --git a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h index 2c39c0a..3f2d3e4 100644 --- a/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h +++ b/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h @@ -122,6 +122,9 @@ public: virtual void syncCompositingState(); virtual void syncCompositingStateForThisLayerOnly(); + bool allowTiledLayer() const { return m_allowTiledLayer; } + virtual void setAllowTiledLayer(bool b); + protected: virtual void setOpacityInternal(float); @@ -399,6 +402,8 @@ private: float clampedContentsScaleForScale(float) const; float m_contentsScale; + + bool m_allowTiledLayer; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp b/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp index 0ef5fd0..e5ff5ba 100644 --- a/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp +++ b/Source/WebCore/platform/graphics/ca/TransformationMatrixCA.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "TransformationMatrix.h" -#if PLATFORM(CA) +#if USE(CA) #include "FloatConversion.h" #include <QuartzCore/CATransform3D.h> @@ -66,4 +66,4 @@ TransformationMatrix::operator CATransform3D() const } -#endif // PLATFORM(CA) +#endif // USE(CA) diff --git a/Source/WebCore/platform/graphics/ca/win/AbstractCACFLayerTreeHost.h b/Source/WebCore/platform/graphics/ca/win/AbstractCACFLayerTreeHost.h new file mode 100644 index 0000000..13c6746 --- /dev/null +++ b/Source/WebCore/platform/graphics/ca/win/AbstractCACFLayerTreeHost.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009, 2011 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 AbstractCACFLayerTreeHost_h +#define AbstractCACFLayerTreeHost_h + +#if USE(ACCELERATED_COMPOSITING) + +#include <wtf/Forward.h> + +namespace WebCore { + +class PlatformCALayer; + +class AbstractCACFLayerTreeHost { +public: + virtual PlatformCALayer* rootLayer() const = 0; + virtual void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>) = 0; + virtual void layerTreeDidChange() = 0; + virtual void flushPendingLayerChangesNow() = 0; + +protected: + virtual ~AbstractCACFLayerTreeHost() { } +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // AbstractCACFLayerTreeHost_h diff --git a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h index 6d91a73..507af0f 100644 --- a/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h +++ b/Source/WebCore/platform/graphics/ca/win/CACFLayerTreeHost.h @@ -28,6 +28,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "AbstractCACFLayerTreeHost.h" #include "COMPtr.h" #include "Timer.h" @@ -50,9 +51,7 @@ namespace WebCore { class CACFLayerTreeHostClient; class PlatformCALayer; -class CACFLayerTreeHost : public RefCounted<CACFLayerTreeHost> { - friend PlatformCALayer; - +class CACFLayerTreeHost : public RefCounted<CACFLayerTreeHost>, private AbstractCACFLayerTreeHost { public: static PassRefPtr<CACFLayerTreeHost> create(); virtual ~CACFLayerTreeHost(); @@ -66,24 +65,31 @@ public: virtual void paint(); virtual void resize() = 0; void flushPendingGraphicsLayerChangesSoon(); - void flushPendingLayerChangesNow(); + + // AbstractCACFLayerTreeHost + virtual void flushPendingLayerChangesNow(); protected: CACFLayerTreeHost(); CGRect bounds() const; - PlatformCALayer* rootLayer() const; HWND window() const { return m_window; } void notifyAnimationsStarted(); + // AbstractCACFLayerTreeHost + virtual PlatformCALayer* rootLayer() const; + virtual bool createRenderer() = 0; virtual void destroyRenderer(); virtual void contextDidChange(); private: void initialize(); - void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>); - void layerTreeDidChange(); + + // AbstractCACFLayerTreeHost + virtual void addPendingAnimatedLayer(PassRefPtr<PlatformCALayer>); + virtual void layerTreeDidChange(); + virtual void flushContext() = 0; virtual CFTimeInterval lastCommitTime() const = 0; diff --git a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp index 3fd857b..ec2a9ff 100644 --- a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp +++ b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.cpp @@ -28,8 +28,7 @@ #if USE(ACCELERATED_COMPOSITING) -#include "CACFLayerTreeHost.h" -#include "WebCoreInstanceHandle.h" +#include "AbstractCACFLayerTreeHost.h" #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> @@ -47,7 +46,7 @@ LayerChangesFlusher::LayerChangesFlusher() { } -void LayerChangesFlusher::flushPendingLayerChangesSoon(CACFLayerTreeHost* host) +void LayerChangesFlusher::flushPendingLayerChangesSoon(AbstractCACFLayerTreeHost* host) { if (!m_hostsWithChangesToFlush.add(host).second || m_hook) return; @@ -55,7 +54,7 @@ void LayerChangesFlusher::flushPendingLayerChangesSoon(CACFLayerTreeHost* host) setHook(); } -void LayerChangesFlusher::cancelPendingFlush(CACFLayerTreeHost* host) +void LayerChangesFlusher::cancelPendingFlush(AbstractCACFLayerTreeHost* host) { m_hostsWithChangesToFlush.remove(host); @@ -80,9 +79,8 @@ LRESULT LayerChangesFlusher::hookFired(int code, WPARAM wParam, LPARAM lParam) ASSERT(m_hook); // Calling out to the hosts can cause m_hostsWithChangesToFlush to be modified, so we copy it - // into a Vector first. We have to hold a reference to them because otherwise they could be - // destroyed while we're calling out to them. - Vector<RefPtr<CACFLayerTreeHost> > hosts; + // into a Vector first. + Vector<AbstractCACFLayerTreeHost*> hosts; copyToVector(m_hostsWithChangesToFlush, hosts); m_hostsWithChangesToFlush.clear(); @@ -108,7 +106,7 @@ void LayerChangesFlusher::setHook() DWORD threadID = ::GetCurrentThreadId(); - m_hook = ::SetWindowsHookExW(WH_GETMESSAGE, hookCallback, instanceHandle(), threadID); + m_hook = ::SetWindowsHookExW(WH_GETMESSAGE, hookCallback, 0, threadID); ASSERT_WITH_MESSAGE(m_hook, "::SetWindowsHookExW failed with error %lu", ::GetLastError()); // Post a message to the message queue to prevent ::GetMessage from blocking, which will ensure diff --git a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h index 6a98a99..1e7ab31 100644 --- a/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h +++ b/Source/WebCore/platform/graphics/ca/win/LayerChangesFlusher.h @@ -34,15 +34,15 @@ namespace WebCore { -class CACFLayerTreeHost; +class AbstractCACFLayerTreeHost; class LayerChangesFlusher { WTF_MAKE_NONCOPYABLE(LayerChangesFlusher); public: static LayerChangesFlusher& shared(); - void flushPendingLayerChangesSoon(CACFLayerTreeHost*); - void cancelPendingFlush(CACFLayerTreeHost*); + void flushPendingLayerChangesSoon(AbstractCACFLayerTreeHost*); + void cancelPendingFlush(AbstractCACFLayerTreeHost*); private: LayerChangesFlusher(); @@ -53,7 +53,7 @@ private: void setHook(); void removeHook(); - HashSet<CACFLayerTreeHost*> m_hostsWithChangesToFlush; + HashSet<AbstractCACFLayerTreeHost*> m_hostsWithChangesToFlush; HHOOK m_hook; bool m_isCallingHosts; }; diff --git a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp index b5a26f4..5d20928 100644 --- a/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp +++ b/Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp @@ -29,7 +29,7 @@ #include "PlatformCALayer.h" -#include "CACFLayerTreeHost.h" +#include "AbstractCACFLayerTreeHost.h" #include "Font.h" #include "GraphicsContext.h" #include "PlatformCALayerWinInternal.h" @@ -65,14 +65,14 @@ static CFStringRef toCACFFilterType(PlatformCALayer::FilterType type) } } -static CACFLayerTreeHost* layerTreeHostForLayer(const PlatformCALayer* layer) +static AbstractCACFLayerTreeHost* layerTreeHostForLayer(const PlatformCALayer* layer) { - // We need the CACFLayerTreeHost associated with this layer, which is stored in the UserData of the CACFContext + // We need the AbstractCACFLayerTreeHost associated with this layer, which is stored in the UserData of the CACFContext void* userData = wkCACFLayerGetContextUserData(layer->platformLayer()); if (!userData) return 0; - return static_cast<CACFLayerTreeHost*>(userData); + return static_cast<AbstractCACFLayerTreeHost*>(userData); } static PlatformCALayerWinInternal* intern(const PlatformCALayer* layer) @@ -156,7 +156,7 @@ PlatformLayer* PlatformCALayer::platformLayer() const PlatformCALayer* PlatformCALayer::rootLayer() const { - CACFLayerTreeHost* host = layerTreeHostForLayer(this); + AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this); return host ? host->rootLayer() : 0; } @@ -167,7 +167,7 @@ void PlatformCALayer::setNeedsDisplay(const FloatRect* dirtyRect) void PlatformCALayer::setNeedsCommit() { - CACFLayerTreeHost* host = layerTreeHostForLayer(this); + AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this); if (host) host->layerTreeDidChange(); } @@ -270,7 +270,7 @@ void PlatformCALayer::addAnimationForKey(const String& key, PlatformCAAnimation* setNeedsCommit(); // Tell the host about it so we can fire the start animation event - CACFLayerTreeHost* host = layerTreeHostForLayer(this); + AbstractCACFLayerTreeHost* host = layerTreeHostForLayer(this); if (host) host->addPendingAnimatedLayer(this); } @@ -283,7 +283,7 @@ void PlatformCALayer::removeAnimationForKey(const String& key) RetainPtr<CFStringRef> s(AdoptCF, key.createCFString()); CACFLayerRemoveAnimation(m_layer.get(), s.get()); - // We don't "remove" a layer from CACFLayerTreeHost when it loses an animation. + // We don't "remove" a layer from AbstractCACFLayerTreeHost when it loses an animation. // There may be other active animations on the layer and if an animation // callback is fired on a layer without any animations no harm is done. diff --git a/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp b/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp index e672c2d..c4c3374 100644 --- a/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp +++ b/Source/WebCore/platform/graphics/ca/win/WKCACFViewLayerTreeHost.cpp @@ -31,6 +31,7 @@ #include "PlatformCALayer.h" #include "SoftLinking.h" #include <wtf/CurrentTime.h> +#include <wtf/Threading.h> typedef struct _CACFLayer* CACFLayerRef; @@ -42,7 +43,13 @@ SOFT_LINK_DEBUG_LIBRARY(WebKitQuartzCoreAdditions) SOFT_LINK_LIBRARY(WebKitQuartzCoreAdditions) #endif -SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCreate, WKCACFViewRef, __cdecl, (), ()) +enum WKCACFViewDrawingDestination { + kWKCACFViewDrawingDestinationWindow = 0, + kWKCACFViewDrawingDestinationImage, +}; +typedef enum WKCACFViewDrawingDestination WKCACFViewDrawingDestination; + +SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCreate, WKCACFViewRef, __cdecl, (WKCACFViewDrawingDestination destination), (destination)) SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewSetLayer, void, __cdecl, (WKCACFViewRef view, CACFLayerRef layer), (view, layer)) SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewUpdate, void, __cdecl, (WKCACFViewRef view, HWND window, const CGRect* bounds), (view, window, bounds)) SOFT_LINK(WebKitQuartzCoreAdditions, WKCACFViewCanDraw, bool, __cdecl, (WKCACFViewRef view), (view)) @@ -63,7 +70,7 @@ PassRefPtr<WKCACFViewLayerTreeHost> WKCACFViewLayerTreeHost::create() } WKCACFViewLayerTreeHost::WKCACFViewLayerTreeHost() - : m_view(AdoptCF, WKCACFViewCreate()) + : m_view(AdoptCF, WKCACFViewCreate(kWKCACFViewDrawingDestinationWindow)) , m_viewNeedsUpdate(true) { } @@ -98,6 +105,12 @@ void WKCACFViewLayerTreeHost::contextDidChangeCallback(WKCACFViewRef view, void* void WKCACFViewLayerTreeHost::contextDidChange() { + // This should only be called on a background thread when no changes have actually + // been committed to the context, eg. when a video frame has been added to an image + // queue, so return without triggering animations etc. + if (!isMainThread()) + return; + // Tell the WKCACFView to start rendering now that we have some contents to render. updateViewIfNeeded(); diff --git a/Source/WebCore/platform/graphics/cairo/CairoPath.h b/Source/WebCore/platform/graphics/cairo/CairoPath.h deleted file mode 100644 index da7affb..0000000 --- a/Source/WebCore/platform/graphics/cairo/CairoPath.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> - Copyright (C) 2010 Igalia S.L. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - aint with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef CairoPath_h -#define CairoPath_h - -#include <cairo.h> - -namespace WebCore { - -// This is necessary since cairo_path_fixed_t isn't exposed in Cairo's public API. -class CairoPath { -public: - CairoPath() - { - static cairo_surface_t* pathSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); - m_cr = cairo_create(pathSurface); - } - - ~CairoPath() - { - cairo_destroy(m_cr); - } - - cairo_t* context() { return m_cr; } - -private: - cairo_t* m_cr; -}; - -} // namespace WebCore - -#endif // CairoPath_h diff --git a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp index ee159a1..758bce9 100644 --- a/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp +++ b/Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp @@ -27,13 +27,13 @@ #include "CairoUtilities.h" #include "AffineTransform.h" -#include "CairoPath.h" #include "Color.h" #include "FloatPoint.h" #include "FloatRect.h" #include "IntRect.h" #include "OwnPtrCairo.h" #include "Path.h" +#include "PlatformPathCairo.h" #include "RefPtrCairo.h" #include <wtf/Vector.h> diff --git a/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp index 0f90ce4..d968ee9 100644 --- a/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp @@ -42,11 +42,10 @@ using WTF::max; namespace WebCore { -static cairo_surface_t* scratchBuffer = 0; +static RefPtr<cairo_surface_t> gScratchBuffer; static void purgeScratchBuffer() { - cairo_surface_destroy(scratchBuffer); - scratchBuffer = 0; + gScratchBuffer.clear(); } // ContextShadow needs a scratch image as the buffer for the blur filter. @@ -68,20 +67,20 @@ static cairo_surface_t* getScratchBuffer(const IntSize& size) { int width = size.width(); int height = size.height(); - int scratchWidth = scratchBuffer ? cairo_image_surface_get_width(scratchBuffer) : 0; - int scratchHeight = scratchBuffer ? cairo_image_surface_get_height(scratchBuffer) : 0; + int scratchWidth = gScratchBuffer.get() ? cairo_image_surface_get_width(gScratchBuffer.get()) : 0; + int scratchHeight = gScratchBuffer.get() ? cairo_image_surface_get_height(gScratchBuffer.get()) : 0; // We do not need to recreate the buffer if the current buffer is large enough. - if (scratchBuffer && scratchWidth >= width && scratchHeight >= height) - return scratchBuffer; + if (gScratchBuffer.get() && scratchWidth >= width && scratchHeight >= height) + return gScratchBuffer.get(); purgeScratchBuffer(); // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests. width = (1 + (width >> 5)) << 5; height = (1 + (height >> 5)) << 5; - scratchBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - return scratchBuffer; + gScratchBuffer = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height)); + return gScratchBuffer.get(); } PlatformContext ContextShadow::beginShadowLayer(GraphicsContext* context, const FloatRect& layerArea) diff --git a/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h index b90bb8c..3a49d5c 100644 --- a/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h +++ b/Source/WebCore/platform/graphics/cairo/DrawErrorUnderline.h @@ -21,7 +21,7 @@ * */ -#if PLATFORM(CAIRO) +#if USE(CAIRO) #ifndef DrawErrorUnderline_h #define DrawErrorUnderline_h diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp new file mode 100644 index 0000000..c90d8ab --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2011 Igalia S.L. + * + * 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 "GraphicsContext3D.h" +#include "PlatformContextCairo.h" + +#if ENABLE(WEBGL) + +#include "Image.h" +#include "RefPtrCairo.h" +#include <cairo.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +bool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned int type, bool premultiplyAlpha, bool ignoreGammaAndColorProfile, Vector<uint8_t>& outputVector) +{ + if (!image) + return false; + // We need this to stay in scope because the native image is just a shallow copy of the data. + ImageSource decoder(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, + ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); + AlphaOp alphaOp = AlphaDoNothing; + RefPtr<cairo_surface_t> imageSurface; + if (image->data()) { + decoder.setData(image->data(), true); + if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) + return false; + imageSurface = decoder.createFrameAtIndex(0); + } else { + imageSurface = image->nativeImageForCurrentFrame(); + if (!premultiplyAlpha) + alphaOp = AlphaDoUnmultiply; + } + + if (!imageSurface) + return false; + + int width = cairo_image_surface_get_width(imageSurface.get()); + int height = cairo_image_surface_get_height(imageSurface.get()); + if (!width || !height) + return false; + + if (cairo_image_surface_get_format(imageSurface.get()) != CAIRO_FORMAT_ARGB32) + return false; + + unsigned int srcUnpackAlignment = 1; + size_t bytesPerRow = cairo_image_surface_get_stride(imageSurface.get()); + size_t bitsPerPixel = 32; + unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width; + if (padding) { + srcUnpackAlignment = padding + 1; + while (bytesPerRow % srcUnpackAlignment) + ++srcUnpackAlignment; + } + + outputVector.resize(width * height * 4); + return packPixels(cairo_image_surface_get_data(imageSurface.get()), SourceFormatBGRA8, + width, height, srcUnpackAlignment, format, type, alphaOp, outputVector.data()); +} + +void GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, int canvasWidth, int canvasHeight, PlatformContextCairo* context) +{ + if (!imagePixels || imageWidth <= 0 || imageHeight <= 0 || canvasWidth <= 0 || canvasHeight <= 0 || !context) + return; + + cairo_t *cr = context->cr(); + context->save(); + + cairo_rectangle(cr, 0, 0, canvasWidth, canvasHeight); + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + + RefPtr<cairo_surface_t> imageSurface = adoptRef(cairo_image_surface_create_for_data( + const_cast<unsigned char*>(imagePixels), CAIRO_FORMAT_ARGB32, imageWidth, imageHeight, imageWidth * 4)); + + // OpenGL keeps the pixels stored bottom up, so we need to flip the image here. + cairo_translate(cr, 0, imageHeight); + cairo_scale(cr, 1, -1); + + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface(cr, imageSurface.get(), 0, 0); + cairo_rectangle(cr, 0, 0, canvasWidth, -canvasHeight); + + cairo_fill(cr); + context->restore(); +} + +void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) +{ +} + +} // namespace WebCore + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 0fc94df..4cd0844 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -32,10 +32,9 @@ #include "config.h" #include "GraphicsContext.h" -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include "AffineTransform.h" -#include "CairoPath.h" #include "CairoUtilities.h" #include "ContextShadow.h" #include "FloatConversion.h" @@ -48,6 +47,7 @@ #include "Path.h" #include "Pattern.h" #include "PlatformContextCairo.h" +#include "PlatformPathCairo.h" #include "RefPtrCairo.h" #include "SimpleFontData.h" #include <cairo.h> @@ -201,8 +201,9 @@ static void strokeCurrentCairoPath(GraphicsContext* context, cairo_t* cairoCont } GraphicsContext::GraphicsContext(cairo_t* cr) + : m_updatingControlTints(false) { - m_data = new GraphicsContextPlatformPrivate(new PlatformContextCairo(cr)); + m_data = new GraphicsContextPlatformPrivateToplevel(new PlatformContextCairo(cr)); } void GraphicsContext::platformInit(PlatformContextCairo* platformContext) @@ -234,24 +235,13 @@ PlatformContextCairo* GraphicsContext::platformContext() const void GraphicsContext::savePlatformState() { - cairo_save(platformContext()->cr()); + platformContext()->save(); m_data->save(); m_data->shadowStack.append(m_data->shadow); - m_data->maskImageStack.append(ImageMaskInformation()); } void GraphicsContext::restorePlatformState() { - cairo_t* cr = platformContext()->cr(); - - const ImageMaskInformation& maskInformation = m_data->maskImageStack.last(); - if (maskInformation.isValid()) { - const FloatRect& maskRect = maskInformation.maskRect(); - cairo_pop_group_to_source(cr); - cairo_mask_surface(cr, maskInformation.maskSurface(), maskRect.x(), maskRect.y()); - } - m_data->maskImageStack.removeLast(); - if (m_data->shadowStack.isEmpty()) m_data->shadow = ContextShadow(); else { @@ -259,7 +249,7 @@ void GraphicsContext::restorePlatformState() m_data->shadowStack.removeLast(); } - cairo_restore(cr); + platformContext()->restore(); m_data->restore(); } @@ -765,7 +755,7 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint& origin, float wi cairo_restore(cr); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { FloatRect result; double x = frect.x(); @@ -1190,33 +1180,6 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const return InterpolationDefault; } -void GraphicsContext::pushImageMask(cairo_surface_t* surface, const FloatRect& rect) -{ - // We must call savePlatformState at least once before we can use image masking, - // since we actually apply the mask in restorePlatformState. - ASSERT(!m_data->maskImageStack.isEmpty()); - m_data->maskImageStack.last().update(surface, rect); - - // Cairo doesn't support the notion of an image clip, so we push a group here - // and then paint it to the surface with an image mask (which is an immediate - // operation) during restorePlatformState. - - // We want to allow the clipped elements to composite with the surface as it - // is now, but they are isolated in another group. To make this work, we're - // going to blit the current surface contents onto the new group once we push it. - cairo_t* cr = platformContext()->cr(); - cairo_surface_t* currentTarget = cairo_get_target(cr); - cairo_surface_flush(currentTarget); - - // Pushing a new group ensures that only things painted after this point are clipped. - cairo_push_group(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - - cairo_set_source_surface(cr, currentTarget, 0, 0); - cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); - cairo_fill(cr); -} - } // namespace WebCore -#endif // PLATFORM(CAIRO) +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 2bc290b..8fd056d 100644 --- a/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/Source/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -47,25 +47,6 @@ typedef struct _GdkExposeEvent GdkExposeEvent; namespace WebCore { -// In Cairo image masking is immediate, so to emulate image clipping we must save masking -// details as part of the context state and apply it during platform restore. -class ImageMaskInformation { -public: - void update(cairo_surface_t* maskSurface, const FloatRect& maskRect) - { - m_maskSurface = maskSurface; - m_maskRect = maskRect; - } - - bool isValid() const { return m_maskSurface; } - cairo_surface_t* maskSurface() const { return m_maskSurface.get(); } - const FloatRect& maskRect() const { return m_maskRect; } - -private: - RefPtr<cairo_surface_t> m_maskSurface; - FloatRect m_maskRect; -}; - class GraphicsContextPlatformPrivate { public: GraphicsContextPlatformPrivate(PlatformContextCairo* newPlatformContext) @@ -81,7 +62,7 @@ public: { } - ~GraphicsContextPlatformPrivate() + virtual ~GraphicsContextPlatformPrivate() { } @@ -121,7 +102,6 @@ public: Vector<float> layers; ContextShadow shadow; Vector<ContextShadow> shadowStack; - Vector<ImageMaskInformation> maskImageStack; #if PLATFORM(GTK) GdkEventExpose* expose; @@ -142,7 +122,7 @@ public: { } - ~GraphicsContextPlatformPrivateToplevel() + virtual ~GraphicsContextPlatformPrivateToplevel() { delete platformContext; } diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 1d5d492..8aa6531 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -55,11 +55,10 @@ static inline cairo_surface_t* copySurface(cairo_surface_t* surface) int height = cairo_image_surface_get_height(surface); cairo_surface_t* newsurface = cairo_image_surface_create(format, width, height); - cairo_t* cr = cairo_create(newsurface); - cairo_set_source_surface(cr, surface, 0, 0); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_paint(cr); - cairo_destroy(cr); + RefPtr<cairo_t> cr = adoptRef(cairo_create(newsurface)); + cairo_set_source_surface(cr.get(), surface, 0, 0); + cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE); + cairo_paint(cr.get()); return newsurface; } @@ -117,7 +116,7 @@ PassRefPtr<Image> ImageBuffer::copyImage() const void ImageBuffer::clip(GraphicsContext* context, const FloatRect& maskRect) const { - context->pushImageMask(m_data.m_surface, maskRect); + context->platformContext()->pushImageMask(m_data.m_surface, maskRect); } void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferData.h b/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h index 42867d1..5ca7262 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h @@ -23,9 +23,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "PlatformContextCairo.h" typedef struct _cairo_surface cairo_surface_t; @@ -42,6 +39,4 @@ public: PlatformContextCairo m_platformContext; }; -} // namespace WebCore - -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp index d3a52ce..ce7d8b2 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -28,7 +28,7 @@ #include "config.h" #include "BitmapImage.h" -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include "AffineTransform.h" #include "CairoUtilities.h" @@ -205,4 +205,4 @@ void BitmapImage::checkForSolidColor() } -#endif // PLATFORM(CAIRO) +#endif // USE(CAIRO) diff --git a/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp b/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp new file mode 100644 index 0000000..92d79f9 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/OpenGLShims.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#if ENABLE(WEBGL) + +#define DISABLE_SHIMS +#include "OpenGLShims.h" + +#include <dlfcn.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +#define ASSIGN_FUNCTION_TABLE_ENTRY(FunctionName, success) \ + openGLFunctionTable()->FunctionName = reinterpret_cast<FunctionName##Type>(lookupOpenGLFunctionAddress(#FunctionName, success)) + +namespace WebCore { + +typedef void* (*glGetProcAddressType) (const char* procName); +static void* getProcAddress(const char* procName) +{ + static bool initialized = false; + static glGetProcAddressType getProcAddressFunction = 0; + + if (!initialized) { + getProcAddressFunction = reinterpret_cast<glGetProcAddressType>(dlsym(RTLD_DEFAULT, "glXGetProcAddress")); + if (!getProcAddressFunction) + getProcAddressFunction = reinterpret_cast<glGetProcAddressType>(dlsym(RTLD_DEFAULT, "glXGetProcAddressARB")); + } + + if (!getProcAddressFunction) + return dlsym(RTLD_DEFAULT, procName); + return getProcAddressFunction(procName); +} + +static void* lookupOpenGLFunctionAddress(const char* functionName, bool& success) +{ + if (!success) + return 0; + + void* target = getProcAddress(functionName); + if (target) + return target; + + String fullFunctionName(functionName); + fullFunctionName.append("ARB"); + target = getProcAddress(fullFunctionName.utf8().data()); + if (target) + return target; + + fullFunctionName = functionName; + fullFunctionName.append("EXT"); + target = getProcAddress(fullFunctionName.utf8().data()); + + // A null address is still a failure case. + if (!target) + success = false; + + return target; +} + +OpenGLFunctionTable* openGLFunctionTable() +{ + static OpenGLFunctionTable table; + return &table; +} + +bool initializeOpenGLShims() +{ + static bool success = true; + static bool initialized = false; + if (initialized) + return success; + + initialized = true; + ASSIGN_FUNCTION_TABLE_ENTRY(glActiveTexture, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glAttachShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBindAttribLocation, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBindBuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBindFramebuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBindRenderbuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlendColor, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlendEquation, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlendEquationSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlendFuncSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBlitFramebuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBufferData, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glBufferSubData, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glCheckFramebufferStatus, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glCompileShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glCreateProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glCreateShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteBuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteFramebuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteRenderbuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDeleteShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDetachShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glDisableVertexAttribArray, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glEnableVertexAttribArray, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glFramebufferRenderbuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glFramebufferTexture2D, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGenBuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGenerateMipmap, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGenFramebuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGenRenderbuffers, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetActiveAttrib, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetActiveUniform, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetAttachedShaders, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetAttribLocation, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetBufferParameteriv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetFramebufferAttachmentParameteriv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetProgramInfoLog, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetProgramiv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetRenderbufferParameteriv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetShaderInfoLog, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetShaderiv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetShaderSource, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetUniformfv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetUniformiv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetUniformLocation, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetVertexAttribfv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetVertexAttribiv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glGetVertexAttribPointerv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsBuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsFramebuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsRenderbuffer, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glIsShader, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glLinkProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glRenderbufferStorage, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glRenderbufferStorageMultisample, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glSampleCoverage, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glShaderSource, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glStencilFuncSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glStencilMaskSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glStencilOpSeparate, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform1f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform1fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform1i, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform1iv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform2f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform2fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform2i, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform2iv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform3f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform3fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform3i, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform3iv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform4f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform4fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform4i, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniform4iv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniformMatrix2fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniformMatrix3fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUniformMatrix4fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glUseProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glValidateProgram, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib1f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib1fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib2f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib2fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib3f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib3fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib4f, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttrib4fv, success); + ASSIGN_FUNCTION_TABLE_ENTRY(glVertexAttribPointer, success); + + if (!success) + LOG_ERROR("Could not initialize OpenGL shims"); + return success; +} + +} // namespace WebCore + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/cairo/OpenGLShims.h b/Source/WebCore/platform/graphics/cairo/OpenGLShims.h new file mode 100644 index 0000000..a431b03 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/OpenGLShims.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2010 Tieto Corporation. + * Copyright (C) 2011 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <GL/gl.h> + +typedef struct _OpenGLFunctionTable OpenGLFunctionTable; + +namespace WebCore { +bool initializeOpenGLShims(); +OpenGLFunctionTable* openGLFunctionTable(); +} + +typedef void (*glActiveTextureType) (GLenum); +typedef void (*glAttachShaderType) (GLuint, GLuint); +typedef void (*glBindAttribLocationType) (GLuint, GLuint, const char*); +typedef void (*glBindBufferType) (GLenum, GLuint); +typedef void (*glBindFramebufferType) (GLenum, GLuint); +typedef void (*glBindRenderbufferType) (GLenum, GLuint); +typedef void (*glBlendColorType) (GLclampf, GLclampf, GLclampf, GLclampf); +typedef void (*glBlendEquationType) (GLenum); +typedef void (*glBlendEquationSeparateType)(GLenum, GLenum); +typedef void (*glBlendFuncSeparateType)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (*glBlitFramebufferType) (GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum); +typedef void (*glBufferDataType) (GLenum, GLsizeiptr, const GLvoid*, GLenum); +typedef void (*glBufferSubDataType) (GLenum, GLintptr, GLsizeiptr, const GLvoid*); +typedef GLenum (*glCheckFramebufferStatusType) (GLenum); +typedef void (*glCompileShaderType) (GLuint); +typedef GLuint (*glCreateProgramType) (); +typedef GLuint (*glCreateShaderType) (GLenum); +typedef void (*glDeleteBuffersType) (GLsizei, const GLuint*); +typedef void (*glDeleteFramebuffersType) (GLsizei n, const GLuint*); +typedef void (*glDeleteProgramType) (GLuint); +typedef void (*glDeleteRenderbuffersType) (GLsizei n, const GLuint*); +typedef void (*glDeleteShaderType) (GLuint); +typedef void (*glDetachShaderType) (GLuint, GLuint); +typedef void (*glDisableVertexAttribArrayType) (GLuint); +typedef void (*glEnableVertexAttribArrayType) (GLuint); +typedef void (*glFramebufferRenderbufferType) (GLenum, GLenum, GLenum, GLuint); +typedef void (*glFramebufferTexture2DType) (GLenum, GLenum, GLenum, GLuint, GLint); +typedef void (*glGenBuffersType) (GLsizei, GLuint*); +typedef void (*glGenerateMipmapType) (GLenum target); +typedef void (*glGenFramebuffersType) (GLsizei, GLuint*); +typedef void (*glGenRenderbuffersType) (GLsizei, GLuint*); +typedef void (*glGetActiveAttribType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +typedef void (*glGetActiveUniformType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +typedef void (*glGetAttachedShadersType) (GLuint, GLsizei, GLsizei*, GLuint*); +typedef GLint (*glGetAttribLocationType) (GLuint, const char*); +typedef void (*glGetBufferParameterivType) (GLenum, GLenum, GLint*); +typedef void (*glGetFramebufferAttachmentParameterivType) (GLenum, GLenum, GLenum, GLint* params); +typedef void (*glGetProgramInfoLogType) (GLuint, GLsizei, GLsizei*, char*); +typedef void (*glGetProgramivType) (GLuint, GLenum, GLint*); +typedef void (*glGetRenderbufferParameterivType) (GLenum, GLenum, GLint*); +typedef void (*glGetShaderInfoLogType) (GLuint, GLsizei, GLsizei*, char*); +typedef void (*glGetShaderivType) (GLuint, GLenum, GLint*); +typedef void (*glGetShaderSourceType) (GLuint, GLsizei, GLsizei*, char*); +typedef GLint (*glGetUniformLocationType) (GLuint, const char*); +typedef void (*glGetUniformfvType) (GLuint, GLint, GLfloat*); +typedef void (*glGetUniformivType) (GLuint, GLint, GLint*); +typedef void (*glGetVertexAttribfvType) (GLuint, GLenum, GLfloat*); +typedef void (*glGetVertexAttribivType) (GLuint, GLenum, GLint*); +typedef void (*glGetVertexAttribPointervType) (GLuint, GLenum, GLvoid**); +typedef GLboolean (*glIsBufferType) (GLuint); +typedef GLboolean (*glIsFramebufferType) (GLuint); +typedef GLboolean (*glIsProgramType) (GLuint); +typedef GLboolean (*glIsRenderbufferType) (GLuint); +typedef GLboolean (*glIsShaderType) (GLuint); +typedef void (*glLinkProgramType) (GLuint); +typedef void (*glRenderbufferStorageType) (GLenum, GLenum, GLsizei, GLsizei); +typedef void (*glRenderbufferStorageMultisampleType) (GLenum, GLsizei, GLenum, GLsizei, GLsizei); +typedef void (*glSampleCoverageType) (GLclampf, GLboolean); +typedef void (*glShaderSourceType) (GLuint, GLsizei, const char**, const GLint*); +typedef void (*glStencilFuncSeparateType) (GLenum, GLenum, GLint, GLuint); +typedef void (*glStencilMaskSeparateType) (GLenum, GLuint); +typedef void (*glStencilOpSeparateType) (GLenum, GLenum, GLenum, GLenum); +typedef void (*glUniform1fType) (GLint, GLfloat); +typedef void (*glUniform1fvType) (GLint, GLsizei, const GLfloat*); +typedef void (*glUniform1iType) (GLint, GLint); +typedef void (*glUniform1ivType) (GLint, GLsizei, const GLint*); +typedef void (*glUniform2fType) (GLint, GLfloat, GLfloat); +typedef void (*glUniform2fvType) (GLint, GLsizei, const GLfloat*); +typedef void (*glUniform2iType) (GLint, GLint, GLint); +typedef void (*glUniform2ivType) (GLint, GLsizei, const GLint*); +typedef void (*glUniform3fType) (GLint, GLfloat, GLfloat, GLfloat); +typedef void (*glUniform3fvType) (GLint, GLsizei, const GLfloat*); +typedef void (*glUniform3iType) (GLint, GLint, GLint, GLint); +typedef void (*glUniform3ivType) (GLint, GLsizei, const GLint*); +typedef void (*glUniform4fType) (GLint, GLfloat, GLfloat, GLfloat, GLfloat); +typedef void (*glUniform4fvType) (GLint, GLsizei, const GLfloat*); +typedef void (*glUniform4iType) (GLint, GLint, GLint, GLint, GLint); +typedef void (*glUniform4ivType) (GLint, GLsizei, const GLint*); +typedef void (*glUniformMatrix2fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (*glUniformMatrix3fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (*glUniformMatrix4fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (*glUseProgramType) (GLuint); +typedef void (*glValidateProgramType) (GLuint); +typedef void (*glVertexAttrib1fType) (GLuint, const GLfloat); +typedef void (*glVertexAttrib1fvType) (GLuint, const GLfloat*); +typedef void (*glVertexAttrib2fType) (GLuint, const GLfloat, const GLfloat); +typedef void (*glVertexAttrib2fvType) (GLuint, const GLfloat*); +typedef void (*glVertexAttrib3fType) (GLuint, const GLfloat, const GLfloat, const GLfloat); +typedef void (*glVertexAttrib3fvType) (GLuint, const GLfloat*); +typedef void (*glVertexAttrib4fType) (GLuint, const GLfloat, const GLfloat, const GLfloat, const GLfloat); +typedef void (*glVertexAttrib4fvType) (GLuint, const GLfloat*); +typedef void (*glVertexAttribPointerType) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*); + +#define FUNCTION_TABLE_ENTRY(FunctionName) FunctionName##Type FunctionName + +typedef struct _OpenGLFunctionTable { + FUNCTION_TABLE_ENTRY(glActiveTexture); + FUNCTION_TABLE_ENTRY(glAttachShader); + FUNCTION_TABLE_ENTRY(glBindAttribLocation); + FUNCTION_TABLE_ENTRY(glBindBuffer); + FUNCTION_TABLE_ENTRY(glBindFramebuffer); + FUNCTION_TABLE_ENTRY(glBindRenderbuffer); + FUNCTION_TABLE_ENTRY(glBlendColor); + FUNCTION_TABLE_ENTRY(glBlendEquation); + FUNCTION_TABLE_ENTRY(glBlendEquationSeparate); + FUNCTION_TABLE_ENTRY(glBlendFuncSeparate); + FUNCTION_TABLE_ENTRY(glBlitFramebuffer); + FUNCTION_TABLE_ENTRY(glBufferData); + FUNCTION_TABLE_ENTRY(glBufferSubData); + FUNCTION_TABLE_ENTRY(glCheckFramebufferStatus); + FUNCTION_TABLE_ENTRY(glCompileShader); + FUNCTION_TABLE_ENTRY(glCreateProgram); + FUNCTION_TABLE_ENTRY(glCreateShader); + FUNCTION_TABLE_ENTRY(glDeleteBuffers); + FUNCTION_TABLE_ENTRY(glDeleteFramebuffers); + FUNCTION_TABLE_ENTRY(glDeleteProgram); + FUNCTION_TABLE_ENTRY(glDeleteRenderbuffers); + FUNCTION_TABLE_ENTRY(glDeleteShader); + FUNCTION_TABLE_ENTRY(glDetachShader); + FUNCTION_TABLE_ENTRY(glDisableVertexAttribArray); + FUNCTION_TABLE_ENTRY(glEnableVertexAttribArray); + FUNCTION_TABLE_ENTRY(glFramebufferRenderbuffer); + FUNCTION_TABLE_ENTRY(glFramebufferTexture2D); + FUNCTION_TABLE_ENTRY(glGenBuffers); + FUNCTION_TABLE_ENTRY(glGenerateMipmap); + FUNCTION_TABLE_ENTRY(glGenFramebuffers); + FUNCTION_TABLE_ENTRY(glGenRenderbuffers); + FUNCTION_TABLE_ENTRY(glGetActiveAttrib); + FUNCTION_TABLE_ENTRY(glGetActiveUniform); + FUNCTION_TABLE_ENTRY(glGetAttachedShaders); + FUNCTION_TABLE_ENTRY(glGetAttribLocation); + FUNCTION_TABLE_ENTRY(glGetBufferParameteriv); + FUNCTION_TABLE_ENTRY(glGetFramebufferAttachmentParameteriv); + FUNCTION_TABLE_ENTRY(glGetProgramInfoLog); + FUNCTION_TABLE_ENTRY(glGetProgramiv); + FUNCTION_TABLE_ENTRY(glGetRenderbufferParameteriv); + FUNCTION_TABLE_ENTRY(glGetShaderInfoLog); + FUNCTION_TABLE_ENTRY(glGetShaderiv); + FUNCTION_TABLE_ENTRY(glGetShaderSource); + FUNCTION_TABLE_ENTRY(glGetUniformfv); + FUNCTION_TABLE_ENTRY(glGetUniformiv); + FUNCTION_TABLE_ENTRY(glGetUniformLocation); + FUNCTION_TABLE_ENTRY(glGetVertexAttribfv); + FUNCTION_TABLE_ENTRY(glGetVertexAttribiv); + FUNCTION_TABLE_ENTRY(glGetVertexAttribPointerv); + FUNCTION_TABLE_ENTRY(glIsBuffer); + FUNCTION_TABLE_ENTRY(glIsFramebuffer); + FUNCTION_TABLE_ENTRY(glIsProgram); + FUNCTION_TABLE_ENTRY(glIsRenderbuffer); + FUNCTION_TABLE_ENTRY(glIsShader); + FUNCTION_TABLE_ENTRY(glLinkProgram); + FUNCTION_TABLE_ENTRY(glRenderbufferStorage); + FUNCTION_TABLE_ENTRY(glRenderbufferStorageMultisample); + FUNCTION_TABLE_ENTRY(glSampleCoverage); + FUNCTION_TABLE_ENTRY(glShaderSource); + FUNCTION_TABLE_ENTRY(glStencilFuncSeparate); + FUNCTION_TABLE_ENTRY(glStencilMaskSeparate); + FUNCTION_TABLE_ENTRY(glStencilOpSeparate); + FUNCTION_TABLE_ENTRY(glUniform1f); + FUNCTION_TABLE_ENTRY(glUniform1fv); + FUNCTION_TABLE_ENTRY(glUniform1i); + FUNCTION_TABLE_ENTRY(glUniform1iv); + FUNCTION_TABLE_ENTRY(glUniform2f); + FUNCTION_TABLE_ENTRY(glUniform2fv); + FUNCTION_TABLE_ENTRY(glUniform2i); + FUNCTION_TABLE_ENTRY(glUniform2iv); + FUNCTION_TABLE_ENTRY(glUniform3f); + FUNCTION_TABLE_ENTRY(glUniform3fv); + FUNCTION_TABLE_ENTRY(glUniform3i); + FUNCTION_TABLE_ENTRY(glUniform3iv); + FUNCTION_TABLE_ENTRY(glUniform4f); + FUNCTION_TABLE_ENTRY(glUniform4fv); + FUNCTION_TABLE_ENTRY(glUniform4i); + FUNCTION_TABLE_ENTRY(glUniform4iv); + FUNCTION_TABLE_ENTRY(glUniformMatrix2fv); + FUNCTION_TABLE_ENTRY(glUniformMatrix3fv); + FUNCTION_TABLE_ENTRY(glUniformMatrix4fv); + FUNCTION_TABLE_ENTRY(glUseProgram); + FUNCTION_TABLE_ENTRY(glValidateProgram); + FUNCTION_TABLE_ENTRY(glVertexAttrib1f); + FUNCTION_TABLE_ENTRY(glVertexAttrib1fv); + FUNCTION_TABLE_ENTRY(glVertexAttrib2f); + FUNCTION_TABLE_ENTRY(glVertexAttrib2fv); + FUNCTION_TABLE_ENTRY(glVertexAttrib3f); + FUNCTION_TABLE_ENTRY(glVertexAttrib3fv); + FUNCTION_TABLE_ENTRY(glVertexAttrib4f); + FUNCTION_TABLE_ENTRY(glVertexAttrib4fv); + FUNCTION_TABLE_ENTRY(glVertexAttribPointer); +} OpenGLFunctionTable; + +// We disable the shims for OpenGLShims.cpp, so that we can set them. +#ifndef DISABLE_SHIMS +#define LOOKUP_GL_FUNCTION(Function) WebCore::openGLFunctionTable()->Function +#define glActiveTexture LOOKUP_GL_FUNCTION(glActiveTexture) +#define glAttachShader LOOKUP_GL_FUNCTION(glAttachShader) +#define glBindAttribLocation LOOKUP_GL_FUNCTION(glBindAttribLocation) +#define glBindBuffer LOOKUP_GL_FUNCTION(glBindBuffer) +#define glBindFramebufferEXT LOOKUP_GL_FUNCTION(glBindFramebuffer) +#define glBindRenderbufferEXT LOOKUP_GL_FUNCTION(glBindRenderbuffer) +#define glBlendColor LOOKUP_GL_FUNCTION(glBlendColor) +#define glBlendEquation LOOKUP_GL_FUNCTION(glBlendEquation) +#define glBlendEquationSeparate LOOKUP_GL_FUNCTION(glBlendEquationSeparate) +#define glBlendFuncSeparate LOOKUP_GL_FUNCTION(glBlendFuncSeparate) +#define glBlitFramebufferEXT LOOKUP_GL_FUNCTION(glBlitFramebuffer) +#define glBufferData LOOKUP_GL_FUNCTION(glBufferData) +#define glBufferSubData LOOKUP_GL_FUNCTION(glBufferSubData) +#define glCheckFramebufferStatusEXT LOOKUP_GL_FUNCTION(glCheckFramebufferStatus) +#define glCompileShader LOOKUP_GL_FUNCTION(glCompileShader) +#define glCreateProgram LOOKUP_GL_FUNCTION(glCreateProgram) +#define glCreateShader LOOKUP_GL_FUNCTION(glCreateShader) +#define glDeleteBuffers LOOKUP_GL_FUNCTION(glDeleteBuffers) +#define glDeleteFramebuffersEXT LOOKUP_GL_FUNCTION(glDeleteFramebuffers) +#define glDeleteProgram LOOKUP_GL_FUNCTION(glDeleteProgram) +#define glDeleteRenderbuffersEXT LOOKUP_GL_FUNCTION(glDeleteRenderbuffers) +#define glDeleteShader LOOKUP_GL_FUNCTION(glDeleteShader) +#define glDetachShader LOOKUP_GL_FUNCTION(glDetachShader) +#define glDisableVertexAttribArray LOOKUP_GL_FUNCTION(glDisableVertexAttribArray) +#define glEnableVertexAttribArray LOOKUP_GL_FUNCTION(glEnableVertexAttribArray) +#define glFramebufferRenderbufferEXT LOOKUP_GL_FUNCTION(glFramebufferRenderbuffer) +#define glFramebufferTexture2DEXT LOOKUP_GL_FUNCTION(glFramebufferTexture2D) +#define glGenBuffers LOOKUP_GL_FUNCTION(glGenBuffers) +#define glGenerateMipmapEXT LOOKUP_GL_FUNCTION(glGenerateMipmap) +#define glGenFramebuffersEXT LOOKUP_GL_FUNCTION(glGenFramebuffers) +#define glGenRenderbuffersEXT LOOKUP_GL_FUNCTION(glGenRenderbuffers) +#define glGetActiveAttrib LOOKUP_GL_FUNCTION(glGetActiveAttrib) +#define glGetActiveUniform LOOKUP_GL_FUNCTION(glGetActiveUniform) +#define glGetAttachedShaders LOOKUP_GL_FUNCTION(glGetAttachedShaders) +#define glGetAttribLocation LOOKUP_GL_FUNCTION(glGetAttribLocation) +#define glGetBufferParameteriv LOOKUP_GL_FUNCTION(glGetBufferParameteriv) +#define glGetBufferParameterivEXT LOOKUP_GL_FUNCTION(glGetBufferParameteriv) +#define glGetFramebufferAttachmentParameterivEXT LOOKUP_GL_FUNCTION(glGetFramebufferAttachmentParameteriv) +#define glGetProgramInfoLog LOOKUP_GL_FUNCTION(glGetProgramInfoLog) +#define glGetProgramiv LOOKUP_GL_FUNCTION(glGetProgramiv) +#define glGetRenderbufferParameterivEXT LOOKUP_GL_FUNCTION(glGetRenderbufferParameteriv) +#define glGetShaderInfoLog LOOKUP_GL_FUNCTION(glGetShaderInfoLog) +#define glGetShaderiv LOOKUP_GL_FUNCTION(glGetShaderiv) +#define glGetShaderSource LOOKUP_GL_FUNCTION(glGetShaderSource) +#define glGetUniformfv LOOKUP_GL_FUNCTION(glGetUniformfv) +#define glGetUniformiv LOOKUP_GL_FUNCTION(glGetUniformiv) +#define glGetUniformLocation LOOKUP_GL_FUNCTION(glGetUniformLocation) +#define glGetVertexAttribfv LOOKUP_GL_FUNCTION(glGetVertexAttribfv) +#define glGetVertexAttribiv LOOKUP_GL_FUNCTION(glGetVertexAttribiv) +#define glGetVertexAttribPointerv LOOKUP_GL_FUNCTION(glGetVertexAttribPointerv) +#define glIsBuffer LOOKUP_GL_FUNCTION(glIsBuffer) +#define glIsFramebufferEXT LOOKUP_GL_FUNCTION(glIsFramebuffer) +#define glIsProgram LOOKUP_GL_FUNCTION(glIsProgram) +#define glIsRenderbufferEXT LOOKUP_GL_FUNCTION(glIsRenderbuffer) +#define glIsShader LOOKUP_GL_FUNCTION(glIsShader) +#define glLinkProgram LOOKUP_GL_FUNCTION(glLinkProgram) +#define glRenderbufferStorageEXT LOOKUP_GL_FUNCTION(glRenderbufferStorage) +#define glRenderbufferStorageMultisampleEXT LOOKUP_GL_FUNCTION(glRenderbufferStorageMultisample) +#define glSampleCoverage LOOKUP_GL_FUNCTION(glSampleCoverage) +#define glShaderSource LOOKUP_GL_FUNCTION(glShaderSource) +#define glStencilFuncSeparate LOOKUP_GL_FUNCTION(glStencilFuncSeparate) +#define glStencilMaskSeparate LOOKUP_GL_FUNCTION(glStencilMaskSeparate) +#define glStencilOpSeparate LOOKUP_GL_FUNCTION(glStencilOpSeparate) +#define glUniform1f LOOKUP_GL_FUNCTION(glUniform1f) +#define glUniform1fv LOOKUP_GL_FUNCTION(glUniform1fv) +#define glUniform1i LOOKUP_GL_FUNCTION(glUniform1i) +#define glUniform1iv LOOKUP_GL_FUNCTION(glUniform1iv) +#define glUniform2f LOOKUP_GL_FUNCTION(glUniform2f) +#define glUniform2fv LOOKUP_GL_FUNCTION(glUniform2fv) +#define glUniform2i LOOKUP_GL_FUNCTION(glUniform2i) +#define glUniform2iv LOOKUP_GL_FUNCTION(glUniform2iv) +#define glUniform3f LOOKUP_GL_FUNCTION(glUniform3f) +#define glUniform3fv LOOKUP_GL_FUNCTION(glUniform3fv) +#define glUniform3i LOOKUP_GL_FUNCTION(glUniform3i) +#define glUniform3iv LOOKUP_GL_FUNCTION(glUniform3iv) +#define glUniform4f LOOKUP_GL_FUNCTION(glUniform4f) +#define glUniform4fv LOOKUP_GL_FUNCTION(glUniform4fv) +#define glUniform4i LOOKUP_GL_FUNCTION(glUniform4i) +#define glUniform4iv LOOKUP_GL_FUNCTION(glUniform4iv) +#define glUniformMatrix2fv LOOKUP_GL_FUNCTION(glUniformMatrix2fv) +#define glUniformMatrix3fv LOOKUP_GL_FUNCTION(glUniformMatrix3fv) +#define glUniformMatrix4fv LOOKUP_GL_FUNCTION(glUniformMatrix4fv) +#define glUseProgram LOOKUP_GL_FUNCTION(glUseProgram) +#define glValidateProgram LOOKUP_GL_FUNCTION(glValidateProgram) +#define glVertexAttrib1f LOOKUP_GL_FUNCTION(glVertexAttrib1f) +#define glVertexAttrib1fv LOOKUP_GL_FUNCTION(glVertexAttrib1fv) +#define glVertexAttrib2f LOOKUP_GL_FUNCTION(glVertexAttrib2f) +#define glVertexAttrib2fv LOOKUP_GL_FUNCTION(glVertexAttrib2fv) +#define glVertexAttrib3f LOOKUP_GL_FUNCTION(glVertexAttrib3f) +#define glVertexAttrib3fv LOOKUP_GL_FUNCTION(glVertexAttrib3fv) +#define glVertexAttrib4f LOOKUP_GL_FUNCTION(glVertexAttrib4f) +#define glVertexAttrib4fv LOOKUP_GL_FUNCTION(glVertexAttrib4fv) +#define glVertexAttribPointer LOOKUP_GL_FUNCTION(glVertexAttribPointer) +#endif diff --git a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp index 533df10..d62c33f 100644 --- a/Source/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -27,10 +27,10 @@ #include "Path.h" #include "AffineTransform.h" -#include "CairoPath.h" #include "FloatRect.h" #include "GraphicsContext.h" #include "OwnPtrCairo.h" +#include "PlatformPathCairo.h" #include "PlatformString.h" #include "StrokeStyleApplier.h" #include <cairo.h> diff --git a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp index ba75162..061ee06 100644 --- a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp @@ -35,4 +35,51 @@ PlatformContextCairo::PlatformContextCairo(cairo_t* cr) { } +void PlatformContextCairo::restore() +{ + const ImageMaskInformation& maskInformation = m_maskImageStack.last(); + if (maskInformation.isValid()) { + const FloatRect& maskRect = maskInformation.maskRect(); + cairo_pop_group_to_source(m_cr.get()); + cairo_mask_surface(m_cr.get(), maskInformation.maskSurface(), maskRect.x(), maskRect.y()); + } + m_maskImageStack.removeLast(); + + cairo_restore(m_cr.get()); +} + +void PlatformContextCairo::save() +{ + m_maskImageStack.append(ImageMaskInformation()); + + cairo_save(m_cr.get()); +} + +void PlatformContextCairo::pushImageMask(cairo_surface_t* surface, const FloatRect& rect) +{ + // We must call savePlatformState at least once before we can use image masking, + // since we actually apply the mask in restorePlatformState. + ASSERT(!m_maskImageStack.isEmpty()); + m_maskImageStack.last().update(surface, rect); + + // Cairo doesn't support the notion of an image clip, so we push a group here + // and then paint it to the surface with an image mask (which is an immediate + // operation) during restorePlatformState. + + // We want to allow the clipped elements to composite with the surface as it + // is now, but they are isolated in another group. To make this work, we're + // going to blit the current surface contents onto the new group once we push it. + cairo_surface_t* currentTarget = cairo_get_target(m_cr.get()); + cairo_surface_flush(currentTarget); + + // Pushing a new group ensures that only things painted after this point are clipped. + cairo_push_group(m_cr.get()); + cairo_set_operator(m_cr.get(), CAIRO_OPERATOR_SOURCE); + + cairo_set_source_surface(m_cr.get(), currentTarget, 0, 0); + cairo_rectangle(m_cr.get(), rect.x(), rect.y(), rect.width(), rect.height()); + cairo_fill(m_cr.get()); +} + + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h index c6cceda..937417a 100644 --- a/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h +++ b/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h @@ -31,6 +31,25 @@ namespace WebCore { +// In Cairo image masking is immediate, so to emulate image clipping we must save masking +// details as part of the context state and apply them during platform restore. +class ImageMaskInformation { +public: + void update(cairo_surface_t* maskSurface, const FloatRect& maskRect) + { + m_maskSurface = maskSurface; + m_maskRect = maskRect; + } + + bool isValid() const { return m_maskSurface; } + cairo_surface_t* maskSurface() const { return m_maskSurface.get(); } + const FloatRect& maskRect() const { return m_maskRect; } + +private: + RefPtr<cairo_surface_t> m_maskSurface; + FloatRect m_maskRect; +}; + // Much like PlatformContextSkia in the Skia port, this class holds information that // would normally be private to GraphicsContext, except that we want to allow access // to it in Font and Image code. This allows us to separate the concerns of Cairo-specific @@ -40,11 +59,17 @@ class PlatformContextCairo { WTF_MAKE_NONCOPYABLE(PlatformContextCairo); public: PlatformContextCairo(cairo_t*); + cairo_t* cr() { return m_cr.get(); } void setCr(cairo_t* cr) { m_cr = cr; } + void save(); + void restore(); + void pushImageMask(cairo_surface_t*, const FloatRect&); + private: RefPtr<cairo_t> m_cr; + Vector<ImageMaskInformation> m_maskImageStack; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp new file mode 100644 index 0000000..3a7d512 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "PlatformPathCairo.h" + +#include <cairo.h> + +namespace WebCore { + +static cairo_surface_t* getPathSurface() +{ + return cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); +} + +static cairo_surface_t* gPathSurface = getPathSurface(); + +CairoPath::CairoPath() + : m_cr(adoptRef(cairo_create(gPathSurface))) +{ +} + +} diff --git a/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h new file mode 100644 index 0000000..938b942 --- /dev/null +++ b/Source/WebCore/platform/graphics/cairo/PlatformPathCairo.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + * Copyright (C) 2010 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PlatformPathCairo_h +#define PlatformPathCairo_h + +#include "RefPtrCairo.h" + +namespace WebCore { + +// This is necessary since cairo_path_fixed_t isn't exposed in Cairo's public API. +class CairoPath { +public: + CairoPath(); + + ~CairoPath() {} + + cairo_t* context() { return m_cr.get(); } + +private: + RefPtr<cairo_t> m_cr; +}; + +} // namespace WebCore + +#endif // PlatformPathCairo_h diff --git a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp index 1792002..90bc3b1 100644 --- a/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/RefPtrCairo.cpp @@ -61,7 +61,7 @@ template<> void refIfNotNull(cairo_font_face_t* ptr) template<> void derefIfNotNull(cairo_font_face_t* ptr) { if (LIKELY(ptr != 0)) - cairo_font_face_reference(ptr); + cairo_font_face_destroy(ptr); } template<> void refIfNotNull(cairo_scaled_font_t* ptr) diff --git a/Source/WebCore/platform/graphics/cg/ColorCG.cpp b/Source/WebCore/platform/graphics/cg/ColorCG.cpp index c9b05da..55a3017 100644 --- a/Source/WebCore/platform/graphics/cg/ColorCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ColorCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "Color.h" -#if PLATFORM(CG) +#if USE(CG) #include "GraphicsContextCG.h" #include <wtf/Assertions.h> @@ -146,4 +146,4 @@ CGColorRef cachedCGColor(const Color& color, ColorSpace colorSpace) } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp b/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp index f9c3353..5e7aab3 100644 --- a/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp +++ b/Source/WebCore/platform/graphics/cg/FloatPointCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "FloatPoint.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -44,4 +44,4 @@ FloatPoint::operator CGPoint() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp b/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp index a1ce367..131b7ac 100644 --- a/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp +++ b/Source/WebCore/platform/graphics/cg/FloatRectCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "FloatRect.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -44,4 +44,4 @@ FloatRect::operator CGRect() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp b/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp index 383af21..a035c7a 100644 --- a/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp +++ b/Source/WebCore/platform/graphics/cg/FloatSizeCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "FloatSize.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -44,4 +44,4 @@ FloatSize::operator CGSize() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index 187d296..57abe71 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -29,8 +29,9 @@ #if ENABLE(WEBGL) #include "GraphicsContext3D.h" -#include "GraphicsContextCG.h" +#include "BitmapImage.h" +#include "GraphicsContextCG.h" #include "Image.h" #include <CoreGraphics/CGBitmapContext.h> @@ -99,7 +100,8 @@ bool GraphicsContext3D::getImageData(Image* image, return false; CGImageRef cgImage; RetainPtr<CGImageRef> decodedImage; - if (image->data()) { + bool hasAlpha = image->isBitmapImage() ? static_cast<BitmapImage*>(image)->frameHasAlphaAtIndex(0) : true; + if ((ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && image->data()) { ImageSource decoder(ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); decoder.setData(image->data(), true); @@ -196,11 +198,6 @@ bool GraphicsContext3D::getImageData(Image* image, AlphaFormat alphaFormat = AlphaFormatNone; switch (CGImageGetAlphaInfo(cgImage)) { case kCGImageAlphaPremultipliedFirst: - // This is a special case for texImage2D with HTMLCanvasElement input, - // in which case image->data() should be null, or indexed color models, - // where we need premultiplied alpha to create the bitmap context - // successfully. - ASSERT(!image->data() || model == kCGColorSpaceModelIndexed); if (!premultiplyAlpha) neededAlphaOp = AlphaDoUnmultiply; alphaFormat = AlphaFormatFirst; @@ -216,9 +213,6 @@ bool GraphicsContext3D::getImageData(Image* image, alphaFormat = AlphaFormatFirst; break; case kCGImageAlphaPremultipliedLast: - // This is a special case for texImage2D with HTMLCanvasElement input, - // in which case image->data() should be null. - ASSERT(!image->data()); if (!premultiplyAlpha) neededAlphaOp = AlphaDoUnmultiply; alphaFormat = AlphaFormatLast; diff --git a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 7799137..c7626b9 100644 --- a/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -756,9 +756,6 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, color, colorSpace); - Path path; - path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); - bool drawOwnShadow = !isAcceleratedContext() && hasBlurredShadow(m_state) && !m_state.shadowsIgnoreTransforms; // Don't use ShadowBlur for canvas yet. if (drawOwnShadow) { float shadowBlur = m_state.shadowsUseLegacyRadius ? radiusToLegacyRadius(m_state.shadowBlur) : m_state.shadowBlur; @@ -771,7 +768,15 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef contextShadow.drawRectShadow(this, rect, RoundedIntRect::Radii(topLeft, topRight, bottomLeft, bottomRight)); } - fillPath(path); + bool equalWidths = (topLeft.width() == topRight.width() && topRight.width() == bottomLeft.width() && bottomLeft.width() == bottomRight.width()); + bool equalHeights = (topLeft.height() == bottomLeft.height() && bottomLeft.height() == topRight.height() && topRight.height() == bottomRight.height()); + if (equalWidths && equalHeights && topLeft.width() * 2 == rect.width() && topLeft.height() * 2 == rect.height()) + CGContextFillEllipseInRect(context, rect); + else { + Path path; + path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); + fillPath(path); + } if (drawOwnShadow) CGContextRestoreGState(context); @@ -791,7 +796,7 @@ void GraphicsContext::fillRectWithRoundedHole(const IntRect& rect, const Rounded path.addRect(rect); if (!roundedHoleRect.radii().isZero()) - path.addRoundedRect(roundedHoleRect.rect(), roundedHoleRect.radii().topLeft(), roundedHoleRect.radii().topRight(), roundedHoleRect.radii().bottomLeft(), roundedHoleRect.radii().bottomRight()); + path.addRoundedRect(roundedHoleRect); else path.addRect(roundedHoleRect.rect()); @@ -1167,8 +1172,11 @@ AffineTransform GraphicsContext::getCTM() const return AffineTransform(t.a, t.b, t.c, t.d, t.tx, t.ty); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode roundingMode) { +#if PLATFORM(CHROMIUM) + return rect; +#else // It is not enough just to round to pixels in device space. The rotation part of the // affine transform matrix to device space can mess with this conversion if we have a // rotating image like the hands of the world clock widget. We just need the scale, so @@ -1192,8 +1200,13 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) deviceOrigin.x = roundf(deviceOrigin.x); deviceOrigin.y = roundf(deviceOrigin.y); - deviceLowerRight.x = roundf(deviceLowerRight.x); - deviceLowerRight.y = roundf(deviceLowerRight.y); + if (roundingMode == RoundAllSides) { + deviceLowerRight.x = roundf(deviceLowerRight.x); + deviceLowerRight.y = roundf(deviceLowerRight.y); + } else { + deviceLowerRight.x = deviceOrigin.x + roundf(rect.width() * deviceScaleX); + deviceLowerRight.y = deviceOrigin.y + roundf(rect.height() * deviceScaleY); + } // Don't let the height or width round to 0 unless either was originally 0 if (deviceOrigin.y == deviceLowerRight.y && rect.height()) @@ -1204,6 +1217,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x / deviceScaleX, deviceOrigin.y / deviceScaleY); FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x / deviceScaleX, deviceLowerRight.y / deviceScaleY); return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); +#endif } void GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool printing) @@ -1232,7 +1246,7 @@ void GraphicsContext::drawLineForText(const FloatPoint& point, float width, bool // We try to round all parameters to integer boundaries in device space. If rounding pixels in device space // makes our thickness more than double, then there must be a shrinking-scale factor and rounding to pixels // in device space will make the underlines too thick. - CGRect lineRect = roundToDevicePixels(FloatRect(x, y, lineLength, adjustedThickness)); + CGRect lineRect = roundToDevicePixels(FloatRect(x, y, lineLength, adjustedThickness), RoundOriginAndDimensions); if (lineRect.size.height < thickness * 2.0) { x = lineRect.origin.x; y = lineRect.origin.y; diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 3c8f959..95ce8c1 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -42,10 +42,6 @@ #include <wtf/Threading.h> #include <math.h> -#if USE(IOSURFACE_CANVAS_BACKING_STORE) -#include <IOSurface/IOSurface.h> -#endif - #if PLATFORM(MAC) || PLATFORM(CHROMIUM) #include "WebCoreSystemInterface.h" #endif @@ -56,6 +52,7 @@ namespace WebCore { #if USE(IOSURFACE_CANVAS_BACKING_STORE) static const int maxIOSurfaceDimension = 4096; +static const int minIOSurfaceArea = 50 * 100; static RetainPtr<IOSurfaceRef> createIOSurface(const IntSize& size) { @@ -100,14 +97,6 @@ static void releaseImageData(void*, const void* data, size_t) fastFree(const_cast<void*>(data)); } -ImageBufferData::ImageBufferData(const IntSize&) - : m_data(0) -#if USE(IOSURFACE_CANVAS_BACKING_STORE) - , m_surface(0) -#endif -{ -} - ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success) : m_data(size) , m_size(size) @@ -117,7 +106,7 @@ ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, Render if (size.width() < 0 || size.height() < 0) return; #if USE(IOSURFACE_CANVAS_BACKING_STORE) - if (size.width() >= maxIOSurfaceDimension || size.height() >= maxIOSurfaceDimension) + if (size.width() >= maxIOSurfaceDimension || size.height() >= maxIOSurfaceDimension || size.width() * size.height() < minIOSurfaceArea) m_accelerateRendering = false; #else ASSERT(renderingMode == Unaccelerated); @@ -262,208 +251,32 @@ void ImageBuffer::clip(GraphicsContext* contextToClip, const FloatRect& rect) co CGContextTranslateCTM(platformContextToClip, -rect.x(), -rect.y() - rect.height()); } -template <Multiply multiplied> -PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size, bool accelerateRendering) -{ - RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); - unsigned char* data = result->data(); - - if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) - memset(data, 0, result->length()); - - int originx = rect.x(); - int destx = 0; - if (originx < 0) { - destx = -originx; - originx = 0; - } - int endx = rect.maxX(); - if (endx > size.width()) - endx = size.width(); - int numColumns = endx - originx; - - int originy = rect.y(); - int desty = 0; - if (originy < 0) { - desty = -originy; - originy = 0; - } - int endy = rect.maxY(); - if (endy > size.height()) - endy = size.height(); - int numRows = endy - originy; - - unsigned destBytesPerRow = 4 * rect.width(); - unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; - - unsigned srcBytesPerRow; - unsigned char* srcRows; - - if (!accelerateRendering) { - srcBytesPerRow = 4 * size.width(); - srcRows = reinterpret_cast<unsigned char*>(imageData.m_data) + originy * srcBytesPerRow + originx * 4; - - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha) { - destRows[basex] = (srcRows[basex] * 255) / alpha; - destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; - destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; - destRows[basex + 3] = alpha; - } else - reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; - } - srcRows += srcBytesPerRow; - destRows += destBytesPerRow; - } - } else { -#if USE(IOSURFACE_CANVAS_BACKING_STORE) - IOSurfaceRef surface = imageData.m_surface.get(); - IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0); - srcBytesPerRow = IOSurfaceGetBytesPerRow(surface); - srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4; - - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha) { - destRows[basex] = (srcRows[basex + 2] * 255) / alpha; - destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; - destRows[basex + 2] = (srcRows[basex] * 255) / alpha; - destRows[basex + 3] = alpha; - } else { - destRows[basex] = srcRows[basex + 2]; - destRows[basex + 1] = srcRows[basex + 1]; - destRows[basex + 2] = srcRows[basex]; - destRows[basex + 3] = alpha; - } - } - srcRows += srcBytesPerRow; - destRows += destBytesPerRow; - } - IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0); -#else - ASSERT_NOT_REACHED(); -#endif - } - - return result.release(); -} - PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { if (m_accelerateRendering) CGContextFlush(context()->platformContext()); - return getImageData<Unmultiplied>(rect, m_data, m_size, m_accelerateRendering); + return m_data.getData(rect, m_size, m_accelerateRendering, true); } PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const { if (m_accelerateRendering) CGContextFlush(context()->platformContext()); - return getImageData<Premultiplied>(rect, m_data, m_size, m_accelerateRendering); -} - -template <Multiply multiplied> -void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size, bool accelerateRendering) -{ - ASSERT(sourceRect.width() > 0); - ASSERT(sourceRect.height() > 0); - - int originx = sourceRect.x(); - int destx = destPoint.x() + sourceRect.x(); - ASSERT(destx >= 0); - ASSERT(destx < size.width()); - ASSERT(originx >= 0); - ASSERT(originx <= sourceRect.maxX()); - - int endx = destPoint.x() + sourceRect.maxX(); - ASSERT(endx <= size.width()); - - int numColumns = endx - destx; - - int originy = sourceRect.y(); - int desty = destPoint.y() + sourceRect.y(); - ASSERT(desty >= 0); - ASSERT(desty < size.height()); - ASSERT(originy >= 0); - ASSERT(originy <= sourceRect.maxY()); - - int endy = destPoint.y() + sourceRect.maxY(); - ASSERT(endy <= size.height()); - int numRows = endy - desty; - - unsigned srcBytesPerRow = 4 * sourceSize.width(); - unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; - unsigned destBytesPerRow; - unsigned char* destRows; - - if (!accelerateRendering) { - destBytesPerRow = 4 * size.width(); - destRows = reinterpret_cast<unsigned char*>(imageData.m_data) + desty * destBytesPerRow + destx * 4; - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha != 255) { - destRows[basex] = (srcRows[basex] * alpha + 254) / 255; - destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; - destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; - destRows[basex + 3] = alpha; - } else - reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; - } - destRows += destBytesPerRow; - srcRows += srcBytesPerRow; - } - } else { -#if USE(IOSURFACE_CANVAS_BACKING_STORE) - IOSurfaceRef surface = imageData.m_surface.get(); - IOSurfaceLock(surface, 0, 0); - destBytesPerRow = IOSurfaceGetBytesPerRow(surface); - destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + desty * destBytesPerRow + destx * 4; - - for (int y = 0; y < numRows; ++y) { - for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - unsigned char alpha = srcRows[basex + 3]; - if (multiplied == Unmultiplied && alpha != 255) { - destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; - destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; - destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255; - destRows[basex + 3] = alpha; - } else { - destRows[basex] = srcRows[basex + 2]; - destRows[basex + 1] = srcRows[basex + 1]; - destRows[basex + 2] = srcRows[basex]; - destRows[basex + 3] = alpha; - } - } - destRows += destBytesPerRow; - srcRows += srcBytesPerRow; - } - IOSurfaceUnlock(surface, 0, 0); -#else - ASSERT_NOT_REACHED(); -#endif - } + return m_data.getData(rect, m_size, m_accelerateRendering, false); } void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) { if (m_accelerateRendering) CGContextFlush(context()->platformContext()); - putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size, m_accelerateRendering); + m_data.putData(source, sourceSize, sourceRect, destPoint, m_size, m_accelerateRendering, true); } void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) { if (m_accelerateRendering) CGContextFlush(context()->platformContext()); - putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size, m_accelerateRendering); + m_data.putData(source, sourceSize, sourceRect, destPoint, m_size, m_accelerateRendering, false); } static inline CFStringRef jpegUTI() diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp new file mode 100644 index 0000000..f067b66 --- /dev/null +++ b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageBufferData.h" + +#include <wtf/Assertions.h> + +#if USE(ACCELERATE) +#include <Accelerate/Accelerate.h> +#endif + +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +#include <IOSurface/IOSurface.h> +#include <dispatch/dispatch.h> +#endif + +#if USE(ACCELERATE) +struct ScanlineData { + vImagePixelCount scanlineWidth; + unsigned char* srcData; + size_t srcRowBytes; + unsigned char* destData; + size_t destRowBytes; +}; +#endif + +namespace WebCore { + +ImageBufferData::ImageBufferData(const IntSize&) +: m_data(0) +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +, m_surface(0) +#endif +{ +} + +#if USE(ACCELERATE) +// The vImage unpremultiply routine had a rounding bug before 10.6.7 <rdar://problem/8631548> +static bool haveVImageRoundingErrorFix() +{ + SInt32 version; + static bool result = (Gestalt(gestaltSystemVersion, &version) == noErr && version > 0x1066); + return result; +} + +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +static void convertScanline(void* data, size_t tileNumber, bool premultiply) +{ + ScanlineData* scanlineData = static_cast<ScanlineData*>(data); + + vImage_Buffer src; + src.data = scanlineData->srcData + tileNumber * scanlineData->srcRowBytes; + src.height = 1; + src.width = scanlineData->scanlineWidth; + src.rowBytes = scanlineData->srcRowBytes; + + vImage_Buffer dest; + dest.data = scanlineData->destData + tileNumber * scanlineData->destRowBytes; + dest.height = 1; + dest.width = scanlineData->scanlineWidth; + dest.rowBytes = scanlineData->destRowBytes; + + if (premultiply) { + if (kvImageNoError != vImagePremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) + return; + } else { + if (kvImageNoError != vImageUnpremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) + return; + } + + // Swap channels 1 and 3, to convert BGRA<->RGBA. IOSurfaces is BGRA, ImageData expects RGBA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&dest, &dest, map, kvImageDoNotTile); +} + +static void unpremultitplyScanline(void* data, size_t tileNumber) +{ + convertScanline(data, tileNumber, false); +} + +static void premultitplyScanline(void* data, size_t tileNumber) +{ + convertScanline(data, tileNumber, true); +} +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) +#endif // USE(ACCELERATE) + +PassRefPtr<ByteArray> ImageBufferData::getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const +{ + RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); + unsigned char* data = result->data(); + + if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) + memset(data, 0, result->length()); + + int originx = rect.x(); + int destx = 0; + if (originx < 0) { + destx = -originx; + originx = 0; + } + int endx = rect.maxX(); + if (endx > size.width()) + endx = size.width(); + int width = endx - originx; + + int originy = rect.y(); + int desty = 0; + if (originy < 0) { + desty = -originy; + originy = 0; + } + int endy = rect.maxY(); + if (endy > size.height()) + endy = size.height(); + int height = endy - originy; + + if (width <= 0 || height <= 0) + return result.release(); + + unsigned destBytesPerRow = 4 * rect.width(); + unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; + + unsigned srcBytesPerRow; + unsigned char* srcRows; + + if (!accelerateRendering) { + srcBytesPerRow = 4 * size.width(); + srcRows = reinterpret_cast<unsigned char*>(m_data) + originy * srcBytesPerRow + originx * 4; + +#if USE(ACCELERATE) + if (unmultiplied && haveVImageRoundingErrorFix()) { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dst; + dst.height = height; + dst.width = width; + dst.rowBytes = destBytesPerRow; + dst.data = destRows; + + vImageUnpremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); + return result.release(); + } +#endif + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha) { + destRows[basex] = (srcRows[basex] * 255) / alpha; + destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; + destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; + destRows[basex + 3] = alpha; + } else + reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + } + srcRows += srcBytesPerRow; + destRows += destBytesPerRow; + } + } else { +#if USE(IOSURFACE_CANVAS_BACKING_STORE) + IOSurfaceRef surface = m_surface.get(); + IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0); + srcBytesPerRow = IOSurfaceGetBytesPerRow(surface); + srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4; + +#if USE(ACCELERATE) + if (unmultiplied) { + ScanlineData scanlineData; + scanlineData.scanlineWidth = width; + scanlineData.srcData = srcRows; + scanlineData.srcRowBytes = srcBytesPerRow; + scanlineData.destData = destRows; + scanlineData.destRowBytes = destBytesPerRow; + + dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, unpremultitplyScanline); + } else { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dest; + dest.height = height; + dest.width = width; + dest.rowBytes = destBytesPerRow; + dest.data = destRows; + + // Swap pixel channels from BGRA to RGBA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); + } +#else + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha) { + destRows[basex] = (srcRows[basex + 2] * 255) / alpha; + destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; + destRows[basex + 2] = (srcRows[basex] * 255) / alpha; + destRows[basex + 3] = alpha; + } else { + destRows[basex] = srcRows[basex + 2]; + destRows[basex + 1] = srcRows[basex + 1]; + destRows[basex + 2] = srcRows[basex]; + destRows[basex + 3] = alpha; + } + } + srcRows += srcBytesPerRow; + destRows += destBytesPerRow; + } +#endif // USE(ACCELERATE) + IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0); +#else + ASSERT_NOT_REACHED(); +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) + } + + return result.release(); +} + +void ImageBufferData::putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied) +{ + ASSERT(sourceRect.width() > 0); + ASSERT(sourceRect.height() > 0); + + int originx = sourceRect.x(); + int destx = destPoint.x() + sourceRect.x(); + ASSERT(destx >= 0); + ASSERT(destx < size.width()); + ASSERT(originx >= 0); + ASSERT(originx <= sourceRect.maxX()); + + int endx = destPoint.x() + sourceRect.maxX(); + ASSERT(endx <= size.width()); + + int width = endx - destx; + + int originy = sourceRect.y(); + int desty = destPoint.y() + sourceRect.y(); + ASSERT(desty >= 0); + ASSERT(desty < size.height()); + ASSERT(originy >= 0); + ASSERT(originy <= sourceRect.maxY()); + + int endy = destPoint.y() + sourceRect.maxY(); + ASSERT(endy <= size.height()); + int height = endy - desty; + + if (width <= 0 || height <= 0) + return; + + unsigned srcBytesPerRow = 4 * sourceSize.width(); + unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; + unsigned destBytesPerRow; + unsigned char* destRows; + + if (!accelerateRendering) { + destBytesPerRow = 4 * size.width(); + destRows = reinterpret_cast<unsigned char*>(m_data) + desty * destBytesPerRow + destx * 4; + +#if USE(ACCELERATE) + if (haveVImageRoundingErrorFix() && unmultiplied) { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dst; + dst.height = height; + dst.width = width; + dst.rowBytes = destBytesPerRow; + dst.data = destRows; + + vImagePremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); + return; + } +#endif + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha != 255) { + destRows[basex] = (srcRows[basex] * alpha + 254) / 255; + destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; + destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; + destRows[basex + 3] = alpha; + } else + reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + } + destRows += destBytesPerRow; + srcRows += srcBytesPerRow; + } + } else { +#if USE(IOSURFACE_CANVAS_BACKING_STORE) + IOSurfaceRef surface = m_surface.get(); + IOSurfaceLock(surface, 0, 0); + destBytesPerRow = IOSurfaceGetBytesPerRow(surface); + destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + desty * destBytesPerRow + destx * 4; + +#if USE(ACCELERATE) + if (unmultiplied) { + ScanlineData scanlineData; + scanlineData.scanlineWidth = width; + scanlineData.srcData = srcRows; + scanlineData.srcRowBytes = srcBytesPerRow; + scanlineData.destData = destRows; + scanlineData.destRowBytes = destBytesPerRow; + + dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, premultitplyScanline); + } else { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dest; + dest.height = height; + dest.width = width; + dest.rowBytes = destBytesPerRow; + dest.data = destRows; + + // Swap pixel channels from RGBA to BGRA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); + } +#else + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha != 255) { + destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; + destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; + destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255; + destRows[basex + 3] = alpha; + } else { + destRows[basex] = srcRows[basex + 2]; + destRows[basex + 1] = srcRows[basex + 1]; + destRows[basex + 2] = srcRows[basex]; + destRows[basex + 3] = alpha; + } + } + destRows += destBytesPerRow; + srcRows += srcBytesPerRow; + } +#endif // USE(ACCELERATE) + + IOSurfaceUnlock(surface, 0, 0); +#else + ASSERT_NOT_REACHED(); +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) + } +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferData.h b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h index 1f706ec..54169e6 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011 Apple Inc. All rights reserved. * Copyright (C) 2008 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,13 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "Image.h" +#include <wtf/ByteArray.h> #include <wtf/RefPtr.h> #include <wtf/RetainPtr.h> +#if (PLATFORM(MAC) && USE(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)) +#define WTF_USE_IOSURFACE_CANVAS_BACKING_STORE 1 +#endif + typedef struct __IOSurface *IOSurfaceRef; typedef struct CGColorSpace *CGColorSpaceRef; typedef struct CGDataProvider *CGDataProviderRef; @@ -50,8 +53,9 @@ public: unsigned m_bytesPerRow; CGColorSpaceRef m_colorSpace; RetainPtr<IOSurfaceRef> m_surface; -}; -} // namespace WebCore + PassRefPtr<ByteArray> getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const; + void putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied); +}; -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/cg/ImageCG.cpp b/Source/WebCore/platform/graphics/cg/ImageCG.cpp index 08f65bd..635a804 100644 --- a/Source/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "BitmapImage.h" -#if PLATFORM(CG) +#if USE(CG) #include "AffineTransform.h" #include "FloatConversion.h" @@ -154,6 +154,19 @@ CGImageRef BitmapImage::getCGImageRef() return frameAtIndex(0); } +CGImageRef BitmapImage::getFirstCGImageRefOfSize(const IntSize& size) +{ + size_t count = frameCount(); + for (size_t i = 0; i < count; ++i) { + CGImageRef cgImage = frameAtIndex(i); + if (IntSize(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage)) == size) + return cgImage; + } + + // Fallback to the default CGImageRef if we can't find the right size + return getCGImageRef(); +} + void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); @@ -186,7 +199,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F // containing only the portion we want to display. We need to do this because high-quality // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed // into the destination rect. See <rdar://problem/6112909>. - shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); + shouldUseSubimage = (interpolationQuality != kCGInterpolationNone) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); float xScale = srcRect.width() / destRect.width(); float yScale = srcRect.height() / destRect.height(); if (shouldUseSubimage) { @@ -255,6 +268,11 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const // Avoid a hang under CGContextDrawTiledImage on release builds. return; +#if !ASSERT_DISABLED + if (this->isBitmapImage()) + ASSERT(static_cast<BitmapImage*>(this)->notSolidColor()); +#endif + CGContextRef context = ctxt->platformContext(); ctxt->save(); CGContextClipToRect(context, destRect); @@ -346,4 +364,4 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp index 068ea5b..1a630d4 100644 --- a/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "ImageSource.h" -#if PLATFORM(CG) +#if USE(CG) #include "ImageSourceCG.h" #include "IntPoint.h" @@ -356,4 +356,4 @@ bool ImageSource::frameHasAlphaAtIndex(size_t) } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/IntPointCG.cpp b/Source/WebCore/platform/graphics/cg/IntPointCG.cpp index 95dbe5f..4a1096b 100644 --- a/Source/WebCore/platform/graphics/cg/IntPointCG.cpp +++ b/Source/WebCore/platform/graphics/cg/IntPointCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "IntPoint.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -43,4 +43,4 @@ IntPoint::operator CGPoint() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/IntRectCG.cpp b/Source/WebCore/platform/graphics/cg/IntRectCG.cpp index 73fd63f..18edeb0 100644 --- a/Source/WebCore/platform/graphics/cg/IntRectCG.cpp +++ b/Source/WebCore/platform/graphics/cg/IntRectCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "IntRect.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -48,4 +48,4 @@ IntRect enclosingIntRect(const CGRect& rect) } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp b/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp index d8e8c83..c844cbc 100644 --- a/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp +++ b/Source/WebCore/platform/graphics/cg/IntSizeCG.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "IntSize.h" -#if PLATFORM(CG) +#if USE(CG) || USE(SKIA_ON_MAC_CHROME) #include <ApplicationServices/ApplicationServices.h> @@ -43,4 +43,4 @@ IntSize::operator CGSize() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp index 8bf04f1..a7d465f 100644 --- a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp +++ b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "PDFDocumentImage.h" -#if PLATFORM(CG) +#if USE(CG) #include "GraphicsContext.h" #include "ImageObserver.h" @@ -188,4 +188,4 @@ void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h index ecd57be..c69a222 100644 --- a/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h +++ b/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h @@ -31,7 +31,7 @@ #include "FloatRect.h" #include "GraphicsTypes.h" -#if PLATFORM(CG) +#if USE(CG) #include <ApplicationServices/ApplicationServices.h> @@ -78,6 +78,6 @@ namespace WebCore { } -#endif // PLATFORM(CG) +#endif // USE(CG) #endif // PDFDocumentImage_h diff --git a/Source/WebCore/platform/graphics/cg/PathCG.cpp b/Source/WebCore/platform/graphics/cg/PathCG.cpp index b8fc7d4..3b9725a 100644 --- a/Source/WebCore/platform/graphics/cg/PathCG.cpp +++ b/Source/WebCore/platform/graphics/cg/PathCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "Path.h" -#if PLATFORM(CG) +#if USE(CG) #include "AffineTransform.h" #include "FloatRect.h" @@ -309,4 +309,4 @@ void Path::transform(const AffineTransform& transform) } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp b/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp index ec40836..b49a2ab 100644 --- a/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp +++ b/Source/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp @@ -27,7 +27,7 @@ #include "AffineTransform.h" #include "TransformationMatrix.h" -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGAffineTransform.h> #include "FloatConversion.h" @@ -66,4 +66,4 @@ AffineTransform::operator CGAffineTransform() const } -#endif // PLATFORM(CG) +#endif // USE(CG) diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp index 4cb119a..26ad37a 100644 --- a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp @@ -36,6 +36,7 @@ #include "DrawingBuffer.h" #include "GraphicsContext3D.h" +#include "LayerRendererChromium.h" namespace WebCore { @@ -54,6 +55,8 @@ Canvas2DLayerChromium::~Canvas2DLayerChromium() { if (m_textureId) layerRendererContext()->deleteTexture(m_textureId); + if (m_drawingBuffer && layerRenderer()) + layerRenderer()->removeChildContext(m_drawingBuffer->graphicsContext3D().get()); } void Canvas2DLayerChromium::updateCompositorResources() @@ -103,8 +106,28 @@ unsigned Canvas2DLayerChromium::textureId() const void Canvas2DLayerChromium::setDrawingBuffer(DrawingBuffer* drawingBuffer) { if (drawingBuffer != m_drawingBuffer) { + if (m_drawingBuffer && layerRenderer()) + layerRenderer()->removeChildContext(m_drawingBuffer->graphicsContext3D().get()); + m_drawingBuffer = drawingBuffer; m_textureChanged = true; + + if (drawingBuffer && layerRenderer()) + layerRenderer()->addChildContext(m_drawingBuffer->graphicsContext3D().get()); + } +} + +void Canvas2DLayerChromium::setLayerRenderer(LayerRendererChromium* newLayerRenderer) +{ + if (layerRenderer() != newLayerRenderer) { + if (m_drawingBuffer->graphicsContext3D()) { + if (layerRenderer()) + layerRenderer()->removeChildContext(m_drawingBuffer->graphicsContext3D().get()); + if (newLayerRenderer) + newLayerRenderer->addChildContext(m_drawingBuffer->graphicsContext3D().get()); + } + + LayerChromium::setLayerRenderer(newLayerRenderer); } } diff --git a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h index 81b118c..4224ab1 100644 --- a/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h @@ -52,6 +52,8 @@ public: unsigned textureId() const; void setDrawingBuffer(DrawingBuffer*); + virtual void setLayerRenderer(LayerRendererChromium*); + private: explicit Canvas2DLayerChromium(DrawingBuffer*, GraphicsLayerChromium* owner); DrawingBuffer* m_drawingBuffer; diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index 4ea9c92..aff2981 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -41,6 +41,14 @@ #include "RenderLayerBacking.h" #include "TextStream.h" +// Maximum size the width or height of this layer can be before enabling tiling +// when m_tilingOption == AutoTile. +static int maxUntiledSize = 512; +// When tiling is enabled, use tiles of this dimension squared. +static int defaultTileSize = 256; + +using namespace std; + namespace WebCore { PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChromium* owner) @@ -50,240 +58,171 @@ PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChrom ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner) : LayerChromium(owner) - , m_contentsTexture(0) - , m_skipsDraw(false) + , m_tilingOption(ContentLayerChromium::AutoTile) { } ContentLayerChromium::~ContentLayerChromium() { - cleanupResources(); -} - -void ContentLayerChromium::cleanupResources() -{ + m_tiler.clear(); LayerChromium::cleanupResources(); - m_contentsTexture.clear(); } -bool ContentLayerChromium::requiresClippedUpdateRect() -{ - // To avoid allocating excessively large textures, switch into "large layer mode" if - // one of the layer's dimensions is larger than 2000 pixels or the size of - // surface it's rendering into. This is a temporary measure until layer tiling is implemented. - static const int maxLayerSize = 2000; - return (bounds().width() > max(maxLayerSize, ccLayerImpl()->targetRenderSurface()->contentRect().width()) - || bounds().height() > max(maxLayerSize, ccLayerImpl()->targetRenderSurface()->contentRect().height()) - || !layerRenderer()->checkTextureSize(bounds())); -} +class ContentLayerPainter : public TilePaintInterface { +public: + explicit ContentLayerPainter(GraphicsLayerChromium* owner) + : m_owner(owner) + { + } -void ContentLayerChromium::paintContentsIfDirty() -{ - RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); - if (!backing || backing->paintingGoesToWindow()) - return; + virtual void paint(GraphicsContext& context, const IntRect& contentRect) + { + context.save(); + context.clearRect(contentRect); + context.clip(contentRect); + m_owner->paintGraphicsLayerContents(context, contentRect); + context.restore(); + } +private: + GraphicsLayerChromium* m_owner; +}; +void ContentLayerChromium::paintContentsIfDirty(const IntRect& targetSurfaceRect) +{ ASSERT(drawsContent()); - ASSERT(layerRenderer()); - IntRect dirtyRect; - IntRect boundsRect(IntPoint(0, 0), bounds()); - IntPoint paintingOffset; - - // FIXME: Remove this test when tiled layers are implemented. - if (requiresClippedUpdateRect()) { - // Calculate the region of this layer that is currently visible. - const IntRect clipRect = ccLayerImpl()->targetRenderSurface()->contentRect(); - - TransformationMatrix layerOriginTransform = ccLayerImpl()->drawTransform(); - layerOriginTransform.translate3d(-0.5 * bounds().width(), -0.5 * bounds().height(), 0); - - // We compute the visible portion of the layer by back-mapping the current RenderSurface - // content area to the layer. To do that, we invert the drawing matrix of the layer - // and project the content area rectangle to it. If the layer transform is not invertible - // then we skip rendering the layer. - if (!layerOriginTransform.isInvertible()) { - m_skipsDraw = true; - return; - } - TransformationMatrix targetToLayerMatrix = layerOriginTransform.inverse(); - FloatQuad mappedClipToLayer = targetToLayerMatrix.projectQuad(FloatRect(clipRect)); - IntRect visibleRectInLayerCoords = mappedClipToLayer.enclosingBoundingBox(); - visibleRectInLayerCoords.intersect(IntRect(0, 0, bounds().width(), bounds().height())); - - // If this is still too large to render, then skip the layer completely. - if (!layerRenderer()->checkTextureSize(visibleRectInLayerCoords.size())) { - m_skipsDraw = true; - return; - } - - // If we need to resize the upload buffer we have to repaint everything. - if (m_canvas.size() != visibleRectInLayerCoords.size()) { - resizeUploadBuffer(visibleRectInLayerCoords.size()); - m_dirtyRect = boundsRect; - } - // If the visible portion of the layer is different from the last upload. - if (visibleRectInLayerCoords != m_visibleRectInLayerCoords) - m_dirtyRect = boundsRect; - m_visibleRectInLayerCoords = visibleRectInLayerCoords; - - // Calculate the portion of the dirty rectangle that is visible. m_dirtyRect is in layer space. - IntRect visibleDirtyRectInLayerSpace = enclosingIntRect(m_dirtyRect); - visibleDirtyRectInLayerSpace.intersect(visibleRectInLayerCoords); - - // What the rectangles mean: - // dirtyRect: The region of this layer that will be updated. - // m_uploadUpdateRect: The region of the layer's texture that will be uploaded into. - dirtyRect = visibleDirtyRectInLayerSpace; - m_uploadUpdateRect = dirtyRect; - IntSize visibleRectOffsetInLayerCoords(visibleRectInLayerCoords.x(), visibleRectInLayerCoords.y()); - paintingOffset = IntPoint(visibleRectOffsetInLayerCoords); - m_uploadUpdateRect.move(-visibleRectOffsetInLayerCoords); - } else { - dirtyRect = IntRect(m_dirtyRect); - // If the texture needs to be reallocated then we must redraw the entire - // contents of the layer. - if (m_canvas.size() != bounds()) { - resizeUploadBuffer(bounds()); - dirtyRect = boundsRect; - } else { - // Clip the dirtyRect to the size of the layer to avoid drawing - // outside the bounds of the backing texture. - dirtyRect.intersect(boundsRect); - } - m_uploadUpdateRect = dirtyRect; - } + createTilerIfNeeded(); - if (dirtyRect.isEmpty()) - return; + ContentLayerPainter painter(m_owner); + updateLayerSize(layerBounds().size()); - PlatformCanvas::Painter painter(&m_canvas); - painter.context()->save(); - painter.context()->translate(-paintingOffset.x(), -paintingOffset.y()); - painter.context()->clearRect(dirtyRect); - painter.context()->clip(dirtyRect); + IntRect layerRect = visibleLayerRect(targetSurfaceRect); + if (layerRect.isEmpty()) + return; + m_tiler->invalidateRect(enclosingIntRect(m_dirtyRect)); + m_tiler->update(painter, layerRect); + m_dirtyRect = FloatRect(); +} - m_owner->paintGraphicsLayerContents(*painter.context(), dirtyRect); - painter.context()->restore(); +void ContentLayerChromium::setLayerRenderer(LayerRendererChromium* layerRenderer) +{ + LayerChromium::setLayerRenderer(layerRenderer); + createTilerIfNeeded(); + m_tiler->setLayerRenderer(layerRenderer); } -void ContentLayerChromium::resizeUploadBuffer(const IntSize& size) +TransformationMatrix ContentLayerChromium::tilingTransform() { - m_canvas.resize(size); + TransformationMatrix transform = ccLayerImpl()->drawTransform(); + // Tiler draws from the upper left corner. The draw transform + // specifies the middle of the layer. + IntSize size = bounds(); + transform.translate(-size.width() / 2.0, -size.height() / 2.0); + + return transform; } -void ContentLayerChromium::updateTextureIfNeeded() +IntRect ContentLayerChromium::visibleLayerRect(const IntRect& targetSurfaceRect) +{ + if (targetSurfaceRect.isEmpty()) + return targetSurfaceRect; + + const IntRect layerBoundRect = layerBounds(); + const TransformationMatrix transform = tilingTransform(); + + // Is this layer fully contained within the target surface? + IntRect layerInSurfaceSpace = transform.mapRect(layerBoundRect); + if (targetSurfaceRect.contains(layerInSurfaceSpace)) + return layerBoundRect; + + // If the layer doesn't fill up the entire surface, then find the part of + // the surface rect where the layer could be visible. This avoids trying to + // project surface rect points that are behind the projection point. + IntRect minimalSurfaceRect = targetSurfaceRect; + minimalSurfaceRect.intersect(layerInSurfaceSpace); + + // Project the corners of the target surface rect into the layer space. + // This bounding rectangle may be larger than it needs to be (being + // axis-aligned), but is a reasonable filter on the space to consider. + // Non-invertible transforms will create an empty rect here. + const TransformationMatrix surfaceToLayer = transform.inverse(); + IntRect layerRect = surfaceToLayer.projectQuad(FloatQuad(FloatRect(minimalSurfaceRect))).enclosingBoundingBox(); + layerRect.intersect(layerBoundRect); + return layerRect; +} + +IntRect ContentLayerChromium::layerBounds() const { - PlatformCanvas::AutoLocker locker(&m_canvas); - updateTexture(locker.pixels(), m_canvas.size()); + return IntRect(IntPoint(0, 0), bounds()); } -void ContentLayerChromium::updateTexture(const uint8_t* pixels, const IntSize& size) +void ContentLayerChromium::updateLayerSize(const IntSize& layerSize) { - if (!pixels) + if (!m_tiler) return; - GraphicsContext3D* context = layerRendererContext(); - if (!m_contentsTexture) - m_contentsTexture = LayerTexture::create(context, layerRenderer()->textureManager()); + const IntSize tileSize(min(defaultTileSize, layerSize.width()), min(defaultTileSize, layerSize.height())); + const bool autoTiled = layerSize.width() > maxUntiledSize || layerSize.height() > maxUntiledSize; - // If we have to allocate a new texture we have to upload the full contents. - if (!m_contentsTexture->isValid(size, GraphicsContext3D::RGBA)) - m_uploadUpdateRect = IntRect(IntPoint(0, 0), size); + bool isTiled; + if (m_tilingOption == AlwaysTile) + isTiled = true; + else if (m_tilingOption == NeverTile) + isTiled = false; + else + isTiled = autoTiled; - if (!m_contentsTexture->reserve(size, GraphicsContext3D::RGBA)) { - m_skipsDraw = true; - return; - } - - IntRect srcRect = IntRect(IntPoint(0, 0), size); - if (requiresClippedUpdateRect()) - srcRect = m_visibleRectInLayerCoords; - - const size_t destStride = m_uploadUpdateRect.width() * 4; - const size_t srcStride = srcRect.width() * 4; - - const uint8_t* uploadPixels = pixels + srcStride * m_uploadUpdateRect.y(); - Vector<uint8_t> uploadBuffer; - if (srcStride != destStride || m_uploadUpdateRect.x()) { - uploadBuffer.resize(m_uploadUpdateRect.height() * destStride); - for (int row = 0; row < m_uploadUpdateRect.height(); ++row) { - size_t srcOffset = (m_uploadUpdateRect.y() + row) * srcStride + m_uploadUpdateRect.x() * 4; - ASSERT(srcOffset + destStride <= static_cast<size_t>(size.width() * size.height() * 4)); - size_t destOffset = row * destStride; - ASSERT(destOffset + destStride <= uploadBuffer.size()); - memcpy(uploadBuffer.data() + destOffset, pixels + srcOffset, destStride); - } - uploadPixels = uploadBuffer.data(); - } - - m_contentsTexture->bindTexture(); - GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, - m_uploadUpdateRect.x(), m_uploadUpdateRect.y(), m_uploadUpdateRect.width(), m_uploadUpdateRect.height(), - GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, - uploadPixels)); + m_tiler->setTileSize(isTiled ? tileSize : layerSize); +} - m_uploadUpdateRect = IntRect(); - m_dirtyRect.setSize(FloatSize()); - // Large layers always stay dirty, because they need to update when the content rect changes. - m_contentsDirty = requiresClippedUpdateRect(); +void ContentLayerChromium::draw(const IntRect& targetSurfaceRect) +{ + const TransformationMatrix transform = tilingTransform(); + IntRect layerRect = visibleLayerRect(targetSurfaceRect); + if (!layerRect.isEmpty()) + m_tiler->draw(layerRect, transform, ccLayerImpl()->drawOpacity()); + m_tiler->unreserveTextures(); } -void ContentLayerChromium::draw() +void ContentLayerChromium::createTilerIfNeeded() { - if (m_skipsDraw) + if (m_tiler) return; + m_tiler = LayerTilerChromium::create(layerRenderer(), IntSize(defaultTileSize, defaultTileSize), LayerTilerChromium::HasBorderTexels); +} - ASSERT(layerRenderer()); +void ContentLayerChromium::updateCompositorResources() +{ + m_tiler->uploadCanvas(); +} - const ContentLayerChromium::Program* program = layerRenderer()->contentLayerProgram(); - ASSERT(program && program->initialized()); - GraphicsContext3D* context = layerRendererContext(); - GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); - bindContentsTexture(); - layerRenderer()->useShader(program->program()); - GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); - GLC(context, context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); - - if (requiresClippedUpdateRect()) { - // Compute the offset between the layer's center point and the center of the visible portion - // of the layer. - FloatPoint visibleRectCenterOffset = FloatRect(m_visibleRectInLayerCoords).center(); - visibleRectCenterOffset.move(-0.5 * bounds().width(), -0.5 * bounds().height()); - - TransformationMatrix transform = ccLayerImpl()->drawTransform(); - transform.translate(visibleRectCenterOffset.x(), visibleRectCenterOffset.y()); - - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), - transform, m_visibleRectInLayerCoords.width(), - m_visibleRectInLayerCoords.height(), ccLayerImpl()->drawOpacity(), - program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation()); - } else { - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), - ccLayerImpl()->drawTransform(), bounds().width(), bounds().height(), - ccLayerImpl()->drawOpacity(), program->vertexShader().matrixLocation(), - program->fragmentShader().alphaLocation()); - } - unreserveContentsTexture(); +void ContentLayerChromium::setTilingOption(TilingOption option) +{ + m_tilingOption = option; + updateLayerSize(bounds()); } -void ContentLayerChromium::updateCompositorResources() +void ContentLayerChromium::bindContentsTexture() { - updateTextureIfNeeded(); + // This function is only valid for single texture layers, e.g. masks. + ASSERT(m_tilingOption == NeverTile); + ASSERT(m_tiler); + + LayerTexture* texture = m_tiler->getSingleTexture(); + ASSERT(texture); + + texture->bindTexture(); } void ContentLayerChromium::unreserveContentsTexture() { - if (!m_skipsDraw && m_contentsTexture) - m_contentsTexture->unreserve(); + m_tiler->unreserveTextures(); } -void ContentLayerChromium::bindContentsTexture() +void ContentLayerChromium::setIsMask(bool isMask) { - if (!m_skipsDraw && m_contentsTexture) - m_contentsTexture->bindTexture(); + setTilingOption(isMask ? NeverTile : AutoTile); } static void writeIndent(TextStream& ts, int indent) @@ -296,7 +235,7 @@ void ContentLayerChromium::dumpLayerProperties(TextStream& ts, int indent) const { LayerChromium::dumpLayerProperties(ts, indent); writeIndent(ts, indent); - ts << "skipsDraw: " << m_skipsDraw << "\n"; + ts << "skipsDraw: " << m_tiler->skipsDraw() << "\n"; } } diff --git a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h index cf296ab..c0cf582 100644 --- a/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -35,7 +35,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "LayerChromium.h" -#include "PlatformCanvas.h" +#include "LayerTilerChromium.h" #include "TextureManager.h" namespace WebCore { @@ -46,43 +46,43 @@ class LayerTexture; class ContentLayerChromium : public LayerChromium { friend class LayerRendererChromium; public: + enum TilingOption { AlwaysTile, NeverTile, AutoTile }; + static PassRefPtr<ContentLayerChromium> create(GraphicsLayerChromium* owner = 0); virtual ~ContentLayerChromium(); - virtual void paintContentsIfDirty(); + virtual void paintContentsIfDirty(const IntRect& targetSurfaceRect); virtual void updateCompositorResources(); + virtual void setIsMask(bool); virtual void unreserveContentsTexture(); virtual void bindContentsTexture(); - virtual void draw(); - virtual bool drawsContent() const { return m_owner && m_owner->drawsContent(); } - - typedef ProgramBinding<VertexShaderPosTex, FragmentShaderTexAlpha> Program; + virtual void draw(const IntRect& targetSurfaceRect); + virtual bool drawsContent() const { return m_owner && m_owner->drawsContent() && (!m_tiler || !m_tiler->skipsDraw()); } protected: explicit ContentLayerChromium(GraphicsLayerChromium* owner); - virtual void cleanupResources(); - bool requiresClippedUpdateRect(); - void resizeUploadBuffer(const IntSize&); - virtual const char* layerTypeAsString() const { return "ContentLayer"; } virtual void dumpLayerProperties(TextStream&, int indent) const; - OwnPtr<LayerTexture> m_contentsTexture; - bool m_skipsDraw; + virtual void setLayerRenderer(LayerRendererChromium*); + + virtual IntRect layerBounds() const; - // The portion of the upload buffer that has a pending update, in the coordinates of the texture. - IntRect m_uploadUpdateRect; + virtual TransformationMatrix tilingTransform(); - virtual void updateTextureIfNeeded(); - void updateTexture(const uint8_t* pixels, const IntSize&); + // For a given render surface rect that this layer will be transformed and + // drawn into, return the layer space rect that is visible in that surface. + IntRect visibleLayerRect(const IntRect&); -private: - PlatformCanvas m_canvas; + void updateLayerSize(const IntSize&); + void createTilerIfNeeded(); + void setTilingOption(TilingOption); - IntRect m_visibleRectInLayerCoords; + OwnPtr<LayerTilerChromium> m_tiler; + TilingOption m_tilingOption; }; } diff --git a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp index e559edb..bad0c6c 100644 --- a/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp @@ -76,7 +76,7 @@ DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, bool multisampleExtensionSupported, bool packedDepthStencilExtensionSupported) : m_context(context) - , m_size(size) + , m_size(-1, -1) , m_multisampleExtensionSupported(multisampleExtensionSupported) , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) , m_fbo(0) @@ -173,6 +173,29 @@ void DrawingBuffer::setGrContext(GrContext* context) // the SharedGraphicsContext3D object that is giving us the context. m_grContext = context; } + +void DrawingBuffer::getGrPlatformSurfaceDesc(GrPlatformSurfaceDesc* desc) +{ + desc->fSurfaceType = kTextureRenderTarget_GrPlatformSurfaceType; + + desc->fPlatformTexture = m_colorBuffer; + if (multisample()) { + desc->fRenderTargetFlags = kIsMultisampled_GrPlatformRenderTargetFlagBit | kGrCanResolve_GrPlatformRenderTargetFlagBit; + desc->fPlatformRenderTarget = m_multisampleFBO; + desc->fPlatformResolveDestination = m_fbo; + } else { + desc->fRenderTargetFlags = kNone_GrPlatformRenderTargetFlagBit; + desc->fPlatformRenderTarget = m_fbo; + desc->fPlatformResolveDestination = 0; + } + + desc->fWidth = m_size.width(); + desc->fHeight = m_size.height(); + desc->fConfig = kRGBA_8888_GrPixelConfig; + + desc->fStencilBits = (m_depthStencilBuffer || m_stencilBuffer) ? 8 : 0; +} + #endif } diff --git a/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h b/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h index 3b0fdbf..c542351 100644 --- a/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h +++ b/Source/WebCore/platform/graphics/chromium/Extensions3DChromium.h @@ -43,6 +43,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); virtual void ensureEnabled(const String&); + virtual bool isEnabled(const String&); virtual int getGraphicsResetStatusARB(); virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); @@ -66,6 +67,12 @@ public: // GL_CHROMIUM_copy_texture_to_parent_texture void copyTextureToParentTextureCHROMIUM(unsigned texture, unsigned parentTexture); + // Latch support + void getParentToChildLatchCHROMIUM(GC3Duint* latchId); + void getChildToParentLatchCHROMIUM(GC3Duint* latchId); + void waitLatchCHROMIUM(GC3Duint latchId); + void setLatchCHROMIUM(GC3Duint latchId); + private: // Instances of this class are strictly owned by the GraphicsContext3D implementation and do not // need to be instantiated by any other code. diff --git a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 3c254dc..ac1e1af 100644 --- a/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -43,7 +43,7 @@ #include "TransparencyWin.h" #include "UniscribeHelperTextRun.h" -#include "skia/ext/platform_canvas_win.h" +#include "skia/ext/platform_canvas.h" #include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency. #include <windows.h> @@ -165,7 +165,7 @@ void TransparencyAwareFontPainter::initializeForGDI() // Set up the DC, using the one from the transparency helper. if (m_transparency.platformContext()) { - m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint(); + m_hdc = skia::BeginPlatformPaint(m_transparency.platformContext()->canvas()); SetTextColor(m_hdc, skia::SkColorToCOLORREF(color)); SetBkMode(m_hdc, TRANSPARENT); } @@ -179,7 +179,7 @@ TransparencyAwareFontPainter::~TransparencyAwareFontPainter() if (m_createdTransparencyLayer) m_graphicsContext->endTransparencyLayer(); m_graphicsContext->restore(); - m_platformContext->canvas()->endPlatformPaint(); + skia::EndPlatformPaint(m_platformContext->canvas()); } // Specialization for simple GlyphBuffer painting. @@ -374,21 +374,14 @@ bool Font::canExpandAroundIdeographsInComplexText() return false; } -void Font::drawGlyphs(GraphicsContext* graphicsContext, - const SimpleFontData* font, - const GlyphBuffer& glyphBuffer, - int from, - int numGlyphs, - const FloatPoint& point) const -{ +static void drawGlyphsWin(GraphicsContext* graphicsContext, + const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, + int from, + int numGlyphs, + const FloatPoint& point) { graphicsContext->platformContext()->prepareForSoftwareDraw(); - SkColor color = graphicsContext->platformContext()->effectiveFillColor(); - unsigned char alpha = SkColorGetA(color); - // Skip 100% transparent text; no need to draw anything. - if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke) - return; - TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point); // We draw the glyphs in chunks to avoid having to do a heap allocation for @@ -449,6 +442,39 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, } } +void Font::drawGlyphs(GraphicsContext* graphicsContext, + const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, + int from, + int numGlyphs, + const FloatPoint& point) const +{ + SkColor color = graphicsContext->platformContext()->effectiveFillColor(); + unsigned char alpha = SkColorGetA(color); + // Skip 100% transparent text; no need to draw anything. + if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke && !graphicsContext->hasShadow()) + return; + if (!alpha || windowsCanHandleDrawTextShadow(graphicsContext) || !windowsCanHandleTextDrawingWithoutShadow(graphicsContext)) { + drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point); + return; + } + // Draw in two passes: skia for the shadow, GDI for foreground text + // pass1: shadow (will use skia) + graphicsContext->save(); + graphicsContext->setFillColor(Color::transparent, graphicsContext->fillColorSpace()); + drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point); + graphicsContext->restore(); + // pass2: foreground text (will use GDI) + FloatSize shadowOffset; + float shadowBlur; + Color shadowColor; + ColorSpace shadowColorSpace; + graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); + graphicsContext->setShadow(shadowOffset, shadowBlur, Color::transparent, shadowColorSpace); + drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point); + graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); +} + FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, @@ -516,7 +542,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, // the baseline, so we have to subtract off the ascent. state.draw(graphicsContext, hdc, lroundf(point.x()), lroundf(point.y() - fontMetrics().ascent()), from, to); - context->canvas()->endPlatformPaint(); + skia::EndPlatformPaint(context->canvas()); } void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const diff --git a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index c3edfac..1fb5957 100644 --- a/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -122,7 +122,7 @@ int FontPlatformData::emSizeInFontUnits() const if (m_emSizeInFontUnits) return m_emSizeInFontUnits; - SkAdvancedTypefaceMetrics* metrics = m_typeface->getAdvancedTypefaceMetrics(false); + SkAdvancedTypefaceMetrics* metrics = m_typeface->getAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo); m_emSizeInFontUnits = metrics->fEmSize; metrics->unref(); return m_emSizeInFontUnits; diff --git a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp index bea0572..a4798dd 100644 --- a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -250,17 +250,31 @@ int getAscent(HFONT hfont) return gotMetrics ? tm.tmAscent : kUndefinedAscent; } +WORD getSpaceGlyph(HFONT hfont) +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, hfont); + WCHAR space = L' '; + WORD spaceGlyph = 0; + GetGlyphIndices(dc, &space, 1, &spaceGlyph, 0); + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return spaceGlyph; +} + struct FontData { FontData() : hfont(0) , ascent(kUndefinedAscent) , scriptCache(0) + , spaceGlyph(0) { } HFONT hfont; int ascent; mutable SCRIPT_CACHE scriptCache; + WORD spaceGlyph; }; // Again, using hash_map does not earn us much here. page_cycler_test intl2 @@ -379,7 +393,8 @@ bool getDerivedFontData(const UChar* family, LOGFONT* logfont, int* ascent, HFONT* hfont, - SCRIPT_CACHE** scriptCache) + SCRIPT_CACHE** scriptCache, + WORD* spaceGlyph) { ASSERT(logfont); ASSERT(family); @@ -408,6 +423,7 @@ bool getDerivedFontData(const UChar* family, // cache it so that we won't have to call CreateFontIndirect once // more for HFONT next time. derived->ascent = getAscent(derived->hfont); + derived->spaceGlyph = getSpaceGlyph(derived->hfont); } else { derived = &iter->second; // Last time, GetAscent failed so that only HFONT was @@ -419,6 +435,7 @@ bool getDerivedFontData(const UChar* family, *hfont = derived->hfont; *ascent = derived->ascent; *scriptCache = &(derived->scriptCache); + *spaceGlyph = derived->spaceGlyph; return *ascent != kUndefinedAscent; } diff --git a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h index b637ede..d9de002 100644 --- a/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h +++ b/Source/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h @@ -78,7 +78,7 @@ const UChar* getFallbackFamily(const UChar* characters, int length, // intl2 page-cycler test is noticeably slower with one out param than // the current version although the subsequent 9 passes take about the // same time. -bool getDerivedFontData(const UChar* family, int style, LOGFONT*, int* ascent, HFONT*, SCRIPT_CACHE**); +bool getDerivedFontData(const UChar* family, int style, LOGFONT*, int* ascent, HFONT*, SCRIPT_CACHE**, WORD* spaceGlyph); enum { FontStyleNormal = 0, diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp index cc5a060..87d54b0 100644 --- a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp +++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.cpp @@ -38,6 +38,7 @@ #include "GraphicsContext3D.h" #include "internal_glu.h" #include "IntRect.h" +#include "LoopBlinnMathUtils.h" #include "LoopBlinnPathProcessor.h" #include "LoopBlinnSolidFillShader.h" #include "Path.h" @@ -60,7 +61,7 @@ namespace WebCore { const int pathTesselation = 30; typedef void (GLAPIENTRY *TESSCB)(); typedef WTF::Vector<float> FloatVector; -typedef WTF::Vector<double> DoubleVector; +typedef WTF::Vector<FloatPoint> FloatPointVector; struct PathAndTransform { PathAndTransform(const Path& p, const AffineTransform& t) @@ -186,7 +187,7 @@ class Cubic { FloatPoint d = -1.0f * p0 + 3.0f * p1s - 3.0f * p2s + p3s; return Cubic(p0, b, c, d); } - FloatPoint evaluate(float t) + inline FloatPoint evaluate(float t) { return m_a + t * (m_b + t * (m_c + t * m_d)); } @@ -198,6 +199,7 @@ GLES2Canvas::GLES2Canvas(SharedGraphicsContext3D* context, DrawingBuffer* drawin , m_context(context) , m_drawingBuffer(drawingBuffer) , m_state(0) + , m_pathIndexBuffer(0) , m_pathVertexBuffer(0) { m_flipMatrix.translate(-1.0f, 1.0f); @@ -209,6 +211,10 @@ GLES2Canvas::GLES2Canvas(SharedGraphicsContext3D* context, DrawingBuffer* drawin GLES2Canvas::~GLES2Canvas() { + if (m_pathIndexBuffer) + m_context->graphicsContext3D()->deleteBuffer(m_pathIndexBuffer); + if (m_pathVertexBuffer) + m_context->graphicsContext3D()->deleteBuffer(m_pathVertexBuffer); } void GLES2Canvas::bindFramebuffer() @@ -229,6 +235,13 @@ void GLES2Canvas::clearRect(const FloatRect& rect) } } +void GLES2Canvas::applyState() +{ + bindFramebuffer(); + m_context->applyCompositeOperator(m_state->m_compositeOp); + applyClipping(m_state->clippingEnabled()); +} + void GLES2Canvas::scissorClear(float x, float y, float width, float height) { int intX = static_cast<int>(x + 0.5f); @@ -250,10 +263,7 @@ void GLES2Canvas::fillPath(const Path& path) endShadowDraw(path.boundingRect()); } - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); - + applyState(); fillPathInternal(path, m_state->applyAlpha(m_state->m_fillColor)); } @@ -265,10 +275,7 @@ void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace endShadowDraw(rect); } - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); - + applyState(); fillRectInternal(rect, color); } @@ -546,38 +553,30 @@ Texture* GLES2Canvas::getTexture(NativeImagePtr ptr) #if USE(SKIA) // This is actually cross-platform code, but since its only caller is inside a // USE(SKIA), it will cause a warning-as-error on Chrome/Mac. -static void interpolateQuadratic(DoubleVector* vertices, const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2) +static void interpolateQuadratic(FloatPointVector* vertices, const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2) { float tIncrement = 1.0f / pathTesselation, t = tIncrement; Quadratic c = Quadratic::fromBezier(p0, p1, p2); - for (int i = 0; i < pathTesselation; ++i, t += tIncrement) { - FloatPoint p = c.evaluate(t); - vertices->append(p.x()); - vertices->append(p.y()); - vertices->append(1.0); - } + for (int i = 0; i < pathTesselation; ++i, t += tIncrement) + vertices->append(c.evaluate(t)); } -static void interpolateCubic(DoubleVector* vertices, const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3) +static void interpolateCubic(FloatPointVector* vertices, const FloatPoint& p0, const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3) { float tIncrement = 1.0f / pathTesselation, t = tIncrement; Cubic c = Cubic::fromBezier(p0, p1, p2, p3); - for (int i = 0; i < pathTesselation; ++i, t += tIncrement) { - FloatPoint p = c.evaluate(t); - vertices->append(p.x()); - vertices->append(p.y()); - vertices->append(1.0); - } + for (int i = 0; i < pathTesselation; ++i, t += tIncrement) + vertices->append(c.evaluate(t)); } #endif struct PolygonData { - PolygonData(FloatVector* vertices, WTF::Vector<short>* indices) + PolygonData(FloatPointVector* vertices, WTF::Vector<short>* indices) : m_vertices(vertices) , m_indices(indices) { } - FloatVector* m_vertices; + FloatPointVector* m_vertices; WTF::Vector<short>* m_indices; }; @@ -603,22 +602,24 @@ static void combineData(GLdouble coords[3], void* vertexData[4], GLfloat weight[4], void **outData, void* data) { PolygonData* polygonData = static_cast<PolygonData*>(data); - int index = polygonData->m_vertices->size() / 3; - polygonData->m_vertices->append(static_cast<float>(coords[0])); - polygonData->m_vertices->append(static_cast<float>(coords[1])); - polygonData->m_vertices->append(1.0f); + int index = polygonData->m_vertices->size(); + polygonData->m_vertices->append(FloatPoint(static_cast<float>(coords[0]), static_cast<float>(coords[1]))); *outData = reinterpret_cast<void*>(index); } typedef void (*TESSCB)(); -void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsigned* vertexBuffer, unsigned* indexBuffer) +void GLES2Canvas::tesselateAndFillPath(const Path& path, const Color& color) { - *vertexBuffer = m_context->graphicsContext3D()->createBuffer(); - checkGLError("createVertexBufferFromPath, createBuffer"); - *indexBuffer = m_context->graphicsContext3D()->createBuffer(); - checkGLError("createVertexBufferFromPath, createBuffer"); - DoubleVector inVertices; + if (!m_pathVertexBuffer) + m_pathVertexBuffer = m_context->graphicsContext3D()->createBuffer(); + if (!m_pathIndexBuffer) + m_pathIndexBuffer = m_context->graphicsContext3D()->createBuffer(); + + AffineTransform matrix(m_flipMatrix); + matrix *= m_state->m_ctm; + + FloatPointVector inVertices; WTF::Vector<size_t> contours; #if USE(SKIA) const SkPath* skPath = path.platformPath(); @@ -628,14 +629,10 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kMove_Verb: - inVertices.append(pts[0].fX); - inVertices.append(pts[0].fY); - inVertices.append(1.0); + inVertices.append(pts[0]); break; case SkPath::kLine_Verb: - inVertices.append(pts[1].fX); - inVertices.append(pts[1].fY); - inVertices.append(1.0); + inVertices.append(pts[1]); break; case SkPath::kQuad_Verb: interpolateQuadratic(&inVertices, pts[0], pts[1], pts[2]); @@ -644,7 +641,7 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig interpolateCubic(&inVertices, pts[0], pts[1], pts[2], pts[3]); break; case SkPath::kClose_Verb: - contours.append(inVertices.size() / 3); + contours.append(inVertices.size()); break; case SkPath::kDone_Verb: break; @@ -654,6 +651,21 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig ASSERT(!"Path extraction not implemented on this platform."); #endif + if (contours.size() == 1 && LoopBlinnMathUtils::isConvex(inVertices.begin(), inVertices.size())) { + m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_pathVertexBuffer); + m_context->graphicsContext3D()->bufferData(GraphicsContext3D::ARRAY_BUFFER, inVertices.size() * 2 * sizeof(float), inVertices.data(), GraphicsContext3D::STREAM_DRAW); + m_context->useFillSolidProgram(matrix, color); + m_context->graphicsContext3D()->drawArrays(GraphicsContext3D::TRIANGLE_FAN, 0, inVertices.size()); + return; + } + + OwnArrayPtr<double> inVerticesDouble = adoptArrayPtr(new double[inVertices.size() * 3]); + for (size_t i = 0; i < inVertices.size(); ++i) { + inVerticesDouble[i * 3 ] = inVertices[i].x(); + inVerticesDouble[i * 3 + 1] = inVertices[i].y(); + inVerticesDouble[i * 3 + 2] = 1.0; + } + GLUtesselator* tess = internal_gluNewTess(); internal_gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); internal_gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (TESSCB) &beginData); @@ -662,7 +674,7 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig internal_gluTessCallback(tess, GLU_TESS_EDGE_FLAG_DATA, (TESSCB) &edgeFlagData); internal_gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (TESSCB) &combineData); WTF::Vector<short> indices; - FloatVector vertices; + FloatPointVector vertices; vertices.reserveInitialCapacity(inVertices.size()); PolygonData data(&vertices, &indices); internal_gluTessBeginPolygon(tess, &data); @@ -671,26 +683,27 @@ void GLES2Canvas::createVertexBufferFromPath(const Path& path, int* count, unsig for (contour = contours.begin(); contour != contours.end(); ++contour) { internal_gluTessBeginContour(tess); for (; i < *contour; ++i) { - vertices.append(inVertices[i * 3]); - vertices.append(inVertices[i * 3 + 1]); - vertices.append(1.0f); - internal_gluTessVertex(tess, &inVertices[i * 3], reinterpret_cast<void*>(i)); + double* inVertex = &inVerticesDouble[i * 3]; + vertices.append(FloatPoint(inVertex[0], inVertex[1])); + internal_gluTessVertex(tess, inVertex, reinterpret_cast<void*>(i)); } internal_gluTessEndContour(tess); } internal_gluTessEndPolygon(tess); internal_gluDeleteTess(tess); - m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, *vertexBuffer); + m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_pathVertexBuffer); checkGLError("createVertexBufferFromPath, bindBuffer ARRAY_BUFFER"); - m_context->graphicsContext3D()->bufferData(GraphicsContext3D::ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GraphicsContext3D::STREAM_DRAW); + m_context->graphicsContext3D()->bufferData(GraphicsContext3D::ARRAY_BUFFER, vertices.size() * 2 * sizeof(float), vertices.data(), GraphicsContext3D::STREAM_DRAW); checkGLError("createVertexBufferFromPath, bufferData ARRAY_BUFFER"); - m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, *indexBuffer); + m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, m_pathIndexBuffer); checkGLError("createVertexBufferFromPath, bindBuffer ELEMENT_ARRAY_BUFFER"); m_context->graphicsContext3D()->bufferData(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(short), indices.data(), GraphicsContext3D::STREAM_DRAW); checkGLError("createVertexBufferFromPath, bufferData ELEMENT_ARRAY_BUFFER"); - *count = indices.size(); + + m_context->useFillSolidProgram(matrix, color); + m_context->graphicsContext3D()->drawElements(GraphicsContext3D::TRIANGLES, indices.size(), GraphicsContext3D::UNSIGNED_SHORT, 0); } void GLES2Canvas::fillPathInternal(const Path& path, const Color& color) @@ -723,29 +736,7 @@ void GLES2Canvas::fillPathInternal(const Path& path, const Color& color) m_context->useLoopBlinnInteriorProgram(byteSizeOfVertices + byteSizeOfTexCoords, matrix, color); m_context->drawArrays(GraphicsContext3D::TRIANGLES, 0, m_pathCache.numberOfInteriorVertices()); } else { - int count; - unsigned vertexBuffer, indexBuffer; - createVertexBufferFromPath(path, &count, &vertexBuffer, &indexBuffer); - - AffineTransform matrix(m_flipMatrix); - matrix *= m_state->m_ctm; - - m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vertexBuffer); - checkGLError("bindBuffer"); - m_context->graphicsContext3D()->bindBuffer(GraphicsContext3D::ELEMENT_ARRAY_BUFFER, indexBuffer); - checkGLError("bindBuffer"); - - m_context->useFillSolidProgram(matrix, color); - checkGLError("useFillSolidProgram"); - - m_context->graphicsContext3D()->drawElements(GraphicsContext3D::TRIANGLES, count, GraphicsContext3D::UNSIGNED_SHORT, 0); - checkGLError("drawArrays"); - - m_context->graphicsContext3D()->deleteBuffer(vertexBuffer); - checkGLError("deleteBuffer"); - - m_context->graphicsContext3D()->deleteBuffer(indexBuffer); - checkGLError("deleteBuffer"); + tesselateAndFillPath(path, color); } } @@ -787,9 +778,7 @@ void GLES2Canvas::beginShadowDraw() m_context->clearColor(Color(RGBA32(0))); m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); } else { - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); + applyState(); } } @@ -864,19 +853,14 @@ void GLES2Canvas::endShadowDraw(const FloatRect& boundingBox) std::swap(srcBuffer, dstBuffer); // Upsample srcBuffer -> main framebuffer using bicubic filtering. - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); + applyState(); m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, srcBuffer->colorBuffer()); FloatRect dstRect = srcRect; dstRect.scale(scaleFactor); drawTexturedQuadMitchell(srcBuffer->size(), flipRect(srcRect), dstRect, AffineTransform(), 1.0); } else { // Blur in Y directly to framebuffer. - bindFramebuffer(); - m_context->applyCompositeOperator(m_state->m_compositeOp); - applyClipping(m_state->clippingEnabled()); - + applyState(); convolveRect(srcBuffer->colorBuffer(), srcBuffer->size(), flipRect(srcRect), srcRect, imageIncrementY, kernel.get(), kernelWidth); } } diff --git a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h index f6a8bcf..635eb10 100644 --- a/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h +++ b/Source/WebCore/platform/graphics/chromium/GLES2Canvas.h @@ -100,14 +100,14 @@ public: DrawingBuffer* drawingBuffer() const { return m_drawingBuffer; } private: + void applyState(); void scissorClear(float x, float y, float width, float height); void drawTexturedRectTile(Texture* texture, int tile, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha); void drawTexturedQuad(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha); void drawTexturedQuadMitchell(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha); void convolveRect(unsigned texture, const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, float imageIncrement[2], const float* kernel, int kernelWidth); - void applyCompositeOperator(CompositeOperator); - void createVertexBufferFromPath(const Path&, int* count, unsigned* vertexBuffer, unsigned* indexBuffer); + void tesselateAndFillPath(const Path&, const Color&); void fillPathInternal(const Path&, const Color&); void fillRectInternal(const FloatRect&, const Color&); FloatRect flipRect(const FloatRect&); @@ -131,6 +131,7 @@ private: // Members for GPU-accelerated path rendering. LoopBlinnPathCache m_pathCache; + unsigned m_pathIndexBuffer; unsigned m_pathVertexBuffer; }; diff --git a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp index 067c54d..2301ca3 100644 --- a/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -283,6 +283,8 @@ void GraphicsLayerChromium::setMaskLayer(GraphicsLayer* maskLayer) GraphicsLayer::setMaskLayer(maskLayer); LayerChromium* maskLayerChromium = m_maskLayer ? m_maskLayer->platformLayer() : 0; + if (maskLayerChromium) + maskLayerChromium->setIsMask(true); m_layer->setMaskLayer(maskLayerChromium); } diff --git a/Source/WebCore/platform/graphics/chromium/ImageBufferData.h b/Source/WebCore/platform/graphics/chromium/ImageBufferDataSkia.h index 504b893..75c91ed 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/chromium/ImageBufferDataSkia.h @@ -28,9 +28,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "PlatformContextSkia.h" #include "skia/ext/platform_canvas.h" @@ -41,10 +38,8 @@ class ImageBufferData { public: ImageBufferData(const IntSize&); - skia::PlatformCanvas m_canvas; + OwnPtr<SkCanvas> m_canvas; PlatformContextSkia m_platformContext; }; -} // namespace WebCore - -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp index 60c1332..d72fb1e 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp @@ -34,6 +34,7 @@ #include "ImageLayerChromium.h" +#include "cc/CCLayerImpl.h" #include "Image.h" #include "LayerRendererChromium.h" #include "LayerTexture.h" @@ -47,42 +48,69 @@ PassRefPtr<ImageLayerChromium> ImageLayerChromium::create(GraphicsLayerChromium* ImageLayerChromium::ImageLayerChromium(GraphicsLayerChromium* owner) : ContentLayerChromium(owner) + , m_imageForCurrentFrame(0) , m_contents(0) { } void ImageLayerChromium::setContents(Image* contents) { - // Check if the image has changed. - if (m_contents == contents) + // setContents() currently gets called whenever there is any + // style change that affects the layer even if that change doesn't + // affect the actual contents of the image (e.g. a CSS animation). + // With this check in place we avoid unecessary texture uploads. + if ((m_contents == contents) && (m_contents->nativeImageForCurrentFrame() == m_imageForCurrentFrame)) return; + m_contents = contents; + m_imageForCurrentFrame = m_contents->nativeImageForCurrentFrame(); + m_dirtyRect = IntRect(IntPoint(0, 0), bounds()); setNeedsDisplay(); } -void ImageLayerChromium::paintContentsIfDirty() +void ImageLayerChromium::paintContentsIfDirty(const IntRect&) { ASSERT(layerRenderer()); - // FIXME: Remove this test when tiled layers are implemented. - if (requiresClippedUpdateRect()) { - // Use the base version of updateContents which draws a subset of the - // image to a bitmap, as the pixel contents can't be uploaded directly. - ContentLayerChromium::paintContentsIfDirty(); - return; + if (!m_dirtyRect.isEmpty()) { + m_decodedImage.updateFromImage(m_contents->nativeImageForCurrentFrame()); } - - m_decodedImage.updateFromImage(m_contents->nativeImageForCurrentFrame()); } -void ImageLayerChromium::updateTextureIfNeeded() +void ImageLayerChromium::updateCompositorResources() { - // FIXME: Remove this test when tiled layers are implemented. - if (requiresClippedUpdateRect()) { - ContentLayerChromium::updateTextureIfNeeded(); - return; + updateLayerSize(m_decodedImage.size()); + + IntRect paintRect(IntPoint(0, 0), m_decodedImage.size()); + if (!m_dirtyRect.isEmpty()) { + m_tiler->invalidateRect(paintRect); + m_dirtyRect = IntRect(); } - updateTexture(m_decodedImage.pixels(), m_decodedImage.size()); + m_tiler->updateFromPixels(paintRect, m_decodedImage.pixels()); +} + +IntRect ImageLayerChromium::layerBounds() const +{ + return IntRect(IntPoint(0, 0), m_decodedImage.size()); +} + +TransformationMatrix ImageLayerChromium::tilingTransform() +{ + // Tiler draws from the upper left corner. The draw transform + // specifies the middle of the layer. + TransformationMatrix transform = ccLayerImpl()->drawTransform(); + const IntRect sourceRect = layerBounds(); + const IntSize destSize = bounds(); + + transform.translate(-destSize.width() / 2.0, -destSize.height() / 2.0); + + // Tiler also draws at the original content size, so rescale the original + // image dimensions to the bounds that it is meant to be drawn at. + float scaleX = destSize.width() / static_cast<float>(sourceRect.size().width()); + float scaleY = destSize.height() / static_cast<float>(sourceRect.size().height()); + transform.scale3d(scaleX, scaleY, 1.0f); + + return transform; } } diff --git a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h index 6addabc..8ab76a8 100644 --- a/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/ImageLayerChromium.h @@ -37,7 +37,7 @@ #include "ContentLayerChromium.h" #include "PlatformImage.h" -#if PLATFORM(CG) +#if USE(CG) #include <wtf/RetainPtr.h> #endif @@ -50,7 +50,8 @@ class ImageLayerChromium : public ContentLayerChromium { public: static PassRefPtr<ImageLayerChromium> create(GraphicsLayerChromium* owner = 0); - virtual void paintContentsIfDirty(); + virtual void paintContentsIfDirty(const IntRect& targetSurfaceRect); + virtual void updateCompositorResources(); virtual bool drawsContent() const { return m_contents; } void setContents(Image* image); @@ -58,12 +59,14 @@ public: protected: virtual const char* layerTypeAsString() const { return "ImageLayer"; } -private: - virtual void updateTextureIfNeeded(); + virtual TransformationMatrix tilingTransform(); + virtual IntRect layerBounds() const; +private: ImageLayerChromium(GraphicsLayerChromium* owner); PlatformImage m_decodedImage; + NativeImagePtr m_imageForCurrentFrame; RefPtr<Image> m_contents; }; diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp index bc28239..fba1dc5 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -89,6 +89,9 @@ LayerChromium::~LayerChromium() // way for us to be destroyed while we still have a superlayer. ASSERT(!superlayer()); + if (m_ccLayerImpl) + m_ccLayerImpl->resetOwner(); + // Remove the superlayer reference from all sublayers. removeAllSublayers(); } diff --git a/Source/WebCore/platform/graphics/chromium/LayerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerChromium.h index 428ce61..5564f91 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerChromium.h @@ -50,11 +50,6 @@ #include <wtf/text/StringHash.h> #include <wtf/text/WTFString.h> - -namespace skia { -class PlatformCanvas; -} - namespace WebCore { class CCLayerImpl; @@ -113,6 +108,7 @@ public: void setNeedsDisplay(const FloatRect& dirtyRect); void setNeedsDisplay(); + virtual void invalidateRect(const FloatRect& dirtyRect) {} const FloatRect& dirtyRect() const { return m_dirtyRect; } void resetNeedsDisplay(); @@ -156,11 +152,13 @@ public: // These methods typically need to be overwritten by derived classes. virtual bool drawsContent() const { return false; } + virtual void paintContentsIfDirty(const IntRect&) { } virtual void paintContentsIfDirty() { } virtual void updateCompositorResources() { } + virtual void setIsMask(bool) {} virtual void unreserveContentsTexture() { } virtual void bindContentsTexture() { } - virtual void draw() { } + virtual void draw(const IntRect&) { } // These exists just for debugging (via drawDebugBorder()). void setBorderColor(const Color&); diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index fc15abd..27a67e9 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -34,8 +34,8 @@ #if USE(ACCELERATED_COMPOSITING) #include "LayerRendererChromium.h" -#include "cc/CCLayerImpl.h" #include "Canvas2DLayerChromium.h" +#include "Extensions3DChromium.h" #include "FloatQuad.h" #include "GeometryBinding.h" #include "GraphicsContext3D.h" @@ -50,7 +50,7 @@ #if USE(SKIA) #include "NativeImageSkia.h" #include "PlatformContextSkia.h" -#elif PLATFORM(CG) +#elif USE(CG) #include <CoreGraphics/CGBitmapContext.h> #endif @@ -88,35 +88,38 @@ static bool isScaleOrTranslation(const TransformationMatrix& m) } -bool LayerRendererChromium::compareLayerZ(const CCLayerImpl* a, const CCLayerImpl* b) +bool LayerRendererChromium::compareLayerZ(const RefPtr<CCLayerImpl>& a, const RefPtr<CCLayerImpl>& b) { return a->drawDepth() < b->drawDepth(); } -PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint) +PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint) { if (!context) return 0; - RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context, contentPaint, scrollbarPaint))); + RefPtr<LayerRendererChromium> layerRenderer(adoptRef(new LayerRendererChromium(context, contentPaint))); if (!layerRenderer->hardwareCompositing()) return 0; return layerRenderer.release(); } -LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint) +LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context, + PassOwnPtr<TilePaintInterface> contentPaint) : m_viewportScrollPosition(IntPoint(-1, -1)) , m_rootLayer(0) , m_rootLayerContentPaint(contentPaint) - , m_rootLayerScrollbarPaint(scrollbarPaint) , m_currentShader(0) , m_currentRenderSurface(0) , m_offscreenFramebufferId(0) , m_compositeOffscreen(false) , m_context(context) + , m_childContextsWereCopied(false) + , m_contextSupportsLatch(false) , m_defaultRenderSurface(0) { + m_contextSupportsLatch = m_context->getExtensions()->supports("GL_CHROMIUM_latch"); m_hardwareCompositing = initializeSharedObjects(); m_rootLayerContentTiler = LayerTilerChromium::create(this, IntSize(256, 256), LayerTilerChromium::NoBorderTexels); ASSERT(m_rootLayerContentTiler); @@ -150,40 +153,9 @@ void LayerRendererChromium::useShader(unsigned programId) } } -IntRect LayerRendererChromium::verticalScrollbarRect() const -{ - IntRect verticalScrollbar(IntPoint(m_viewportContentRect.maxX(), m_viewportContentRect.y()), IntSize(m_viewportVisibleRect.width() - m_viewportContentRect.width(), m_viewportVisibleRect.height())); - return verticalScrollbar; -} - -IntRect LayerRendererChromium::horizontalScrollbarRect() const -{ - IntRect horizontalScrollbar(IntPoint(m_viewportContentRect.x(), m_viewportContentRect.maxY()), IntSize(m_viewportVisibleRect.width(), m_viewportVisibleRect.height() - m_viewportContentRect.height())); - return horizontalScrollbar; -} - void LayerRendererChromium::invalidateRootLayerRect(const IntRect& dirtyRect) { m_rootLayerContentTiler->invalidateRect(dirtyRect); - - // Scrollbars never need to render beyond the fold, so clip to the viewport. - IntRect visibleDirtyRect = dirtyRect; - visibleDirtyRect.intersect(m_viewportVisibleRect); - - if (m_horizontalScrollbarTiler) { - IntRect scrollbar = horizontalScrollbarRect(); - if (visibleDirtyRect.intersects(scrollbar)) { - m_horizontalScrollbarTiler->setLayerPosition(scrollbar.location()); - m_horizontalScrollbarTiler->invalidateRect(visibleDirtyRect); - } - } - if (m_verticalScrollbarTiler) { - IntRect scrollbar = verticalScrollbarRect(); - if (visibleDirtyRect.intersects(scrollbar)) { - m_verticalScrollbarTiler->setLayerPosition(scrollbar.location()); - m_verticalScrollbarTiler->invalidateRect(visibleDirtyRect); - } - } } void LayerRendererChromium::updateRootLayerContents() @@ -192,43 +164,14 @@ void LayerRendererChromium::updateRootLayerContents() m_rootLayerContentTiler->update(*m_rootLayerContentPaint, m_viewportVisibleRect); } -void LayerRendererChromium::updateRootLayerScrollbars() -{ - TRACE_EVENT("LayerRendererChromium::updateRootLayerScrollbars", this, 0); - if (m_viewportVisibleRect.width() > m_viewportContentRect.width()) { - IntRect verticalScrollbar = verticalScrollbarRect(); - IntSize tileSize = verticalScrollbar.size().shrunkTo(IntSize(m_maxTextureSize, m_maxTextureSize)); - if (!m_verticalScrollbarTiler) - m_verticalScrollbarTiler = LayerTilerChromium::create(this, tileSize, LayerTilerChromium::NoBorderTexels); - else - m_verticalScrollbarTiler->setTileSize(tileSize); - m_verticalScrollbarTiler->setLayerPosition(verticalScrollbar.location()); - m_verticalScrollbarTiler->update(*m_rootLayerScrollbarPaint, m_viewportVisibleRect); - } else - m_verticalScrollbarTiler.clear(); - - if (m_viewportVisibleRect.height() > m_viewportContentRect.height()) { - IntRect horizontalScrollbar = horizontalScrollbarRect(); - IntSize tileSize = horizontalScrollbar.size().shrunkTo(IntSize(m_maxTextureSize, m_maxTextureSize)); - if (!m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler = LayerTilerChromium::create(this, tileSize, LayerTilerChromium::NoBorderTexels); - else - m_horizontalScrollbarTiler->setTileSize(tileSize); - m_horizontalScrollbarTiler->setLayerPosition(horizontalScrollbar.location()); - m_horizontalScrollbarTiler->update(*m_rootLayerScrollbarPaint, m_viewportVisibleRect); - } else - m_horizontalScrollbarTiler.clear(); -} - void LayerRendererChromium::drawRootLayer() { - m_rootLayerContentTiler->draw(m_viewportVisibleRect); - - if (m_verticalScrollbarTiler) - m_verticalScrollbarTiler->draw(m_viewportVisibleRect); + TransformationMatrix scroll; + scroll.translate(-m_viewportVisibleRect.x(), -m_viewportVisibleRect.y()); - if (m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler->draw(m_viewportVisibleRect); + m_rootLayerContentTiler->uploadCanvas(); + m_rootLayerContentTiler->draw(m_viewportVisibleRect, scroll, 1.0f); + m_rootLayerContentTiler->unreserveTextures(); } void LayerRendererChromium::setViewport(const IntRect& visibleRect, const IntRect& contentRect, const IntPoint& scrollPosition) @@ -243,12 +186,7 @@ void LayerRendererChromium::setViewport(const IntRect& visibleRect, const IntRec // Reset the current render surface to force an update of the viewport and // projection matrix next time useRenderSurface is called. m_currentRenderSurface = 0; - m_rootLayerContentTiler->invalidateEntireLayer(); - if (m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler->invalidateEntireLayer(); - if (m_verticalScrollbarTiler) - m_verticalScrollbarTiler->invalidateEntireLayer(); } } @@ -266,18 +204,56 @@ void LayerRendererChromium::updateAndDrawLayers() if (!m_rootLayer) return; - updateRootLayerScrollbars(); + LayerList renderSurfaceLayerList; - Vector<CCLayerImpl*> renderSurfaceLayerList; updateLayers(renderSurfaceLayerList); + // Before drawLayers: + if (hardwareCompositing() && m_contextSupportsLatch) { + // FIXME: The multithreaded compositor case will not work as long as + // copyTexImage2D resolves to the parent texture, because the main + // thread can execute WebGL calls on the child context at any time, + // potentially clobbering the parent texture that is being renderered + // by the compositor thread. + if (m_childContextsWereCopied) { + Extensions3DChromium* parentExt = static_cast<Extensions3DChromium*>(m_context->getExtensions()); + // For each child context: + // glWaitLatch(Offscreen->Compositor); + ChildContextMap::iterator i = m_childContexts.begin(); + for (; i != m_childContexts.end(); ++i) { + Extensions3DChromium* childExt = static_cast<Extensions3DChromium*>(i->first->getExtensions()); + GC3Duint latchId; + childExt->getChildToParentLatchCHROMIUM(&latchId); + parentExt->waitLatchCHROMIUM(latchId); + } + } + // Reset to false to indicate that we have consumed the dirty child + // contexts' parent textures. (This is only useful when the compositor + // is multithreaded.) + m_childContextsWereCopied = false; + } + drawLayers(renderSurfaceLayerList); + // After drawLayers: + if (hardwareCompositing() && m_contextSupportsLatch) { + Extensions3DChromium* parentExt = static_cast<Extensions3DChromium*>(m_context->getExtensions()); + // For each child context: + // glSetLatch(Compositor->Offscreen); + ChildContextMap::iterator i = m_childContexts.begin(); + for (; i != m_childContexts.end(); ++i) { + Extensions3DChromium* childExt = static_cast<Extensions3DChromium*>(i->first->getExtensions()); + GC3Duint latchId; + childExt->getParentToChildLatchCHROMIUM(&latchId); + parentExt->setLatchCHROMIUM(latchId); + } + } + if (isCompositingOffscreen()) copyOffscreenTextureToDisplay(); } -void LayerRendererChromium::updateLayers(Vector<CCLayerImpl*>& renderSurfaceLayerList) +void LayerRendererChromium::updateLayers(LayerList& renderSurfaceLayerList) { TRACE_EVENT("LayerRendererChromium::updateLayers", this, 0); m_rootLayer->createCCLayerImplIfNeeded(); @@ -289,8 +265,7 @@ void LayerRendererChromium::updateLayers(Vector<CCLayerImpl*>& renderSurfaceLaye rootDrawLayer->renderSurface()->m_contentRect = IntRect(IntPoint(0, 0), m_viewportVisibleRect.size()); - // Scissor out the scrollbars to avoid rendering on top of them. - IntRect rootScissorRect(m_viewportContentRect); + IntRect rootScissorRect(m_viewportVisibleRect); // The scissorRect should not include the scroll offset. rootScissorRect.move(-m_viewportScrollPosition.x(), -m_viewportScrollPosition.y()); rootDrawLayer->setScissorRect(rootScissorRect); @@ -309,10 +284,51 @@ void LayerRendererChromium::updateLayers(Vector<CCLayerImpl*>& renderSurfaceLaye paintContentsRecursive(m_rootLayer.get()); + // FIXME: Before updateCompositorResourcesRecursive, when the compositor runs in + // its own thread, and when the copyTexImage2D bug is fixed, insert + // a glWaitLatch(Compositor->Offscreen) on all child contexts here instead + // of after updateCompositorResourcesRecursive. + // Also uncomment the glSetLatch(Compositor->Offscreen) code in addChildContext. +// if (hardwareCompositing() && m_contextSupportsLatch) { +// // For each child context: +// // glWaitLatch(Compositor->Offscreen); +// ChildContextMap::iterator i = m_childContexts.begin(); +// for (; i != m_childContexts.end(); ++i) { +// Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions()); +// GC3Duint childToParentLatchId, parentToChildLatchId; +// ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId); +// ext->waitLatchCHROMIUM(parentToChildLatchId); +// } +// } + updateCompositorResourcesRecursive(m_rootLayer.get()); + + // After updateCompositorResourcesRecursive, set/wait latches for all child + // contexts. This will prevent the compositor from using any of the child + // parent textures while WebGL commands are executing from javascript *and* + // while the final parent texture is being blit'd. copyTexImage2D + // uses the parent texture as a temporary resolve buffer, so that's why the + // waitLatch is below, to block the compositor from using the parent texture + // until the next WebGL SwapBuffers (or copyTextureToParentTexture for + // Canvas2D). + if (hardwareCompositing() && m_contextSupportsLatch) { + m_childContextsWereCopied = true; + // For each child context: + // glSetLatch(Offscreen->Compositor); + // glWaitLatch(Compositor->Offscreen); + ChildContextMap::iterator i = m_childContexts.begin(); + for (; i != m_childContexts.end(); ++i) { + Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions()); + GC3Duint childToParentLatchId, parentToChildLatchId; + ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId); + ext->getChildToParentLatchCHROMIUM(&childToParentLatchId); + ext->setLatchCHROMIUM(childToParentLatchId); + ext->waitLatchCHROMIUM(parentToChildLatchId); + } + } } -void LayerRendererChromium::drawLayers(const Vector<CCLayerImpl*>& renderSurfaceLayerList) +void LayerRendererChromium::drawLayers(const LayerList& renderSurfaceLayerList) { TRACE_EVENT("LayerRendererChromium::drawLayers", this, 0); CCLayerImpl* rootDrawLayer = m_rootLayer->ccLayerImpl(); @@ -347,13 +363,14 @@ void LayerRendererChromium::drawLayers(const Vector<CCLayerImpl*>& renderSurface m_context->colorMask(true, true, true, true); GLC(m_context.get(), m_context->enable(GraphicsContext3D::BLEND)); + GLC(m_context.get(), m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST)); // Update the contents of the render surfaces. We traverse the array from // back to front to guarantee that nested render surfaces get rendered in the // correct order. for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) { - CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex]; + CCLayerImpl* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex].get(); ASSERT(renderSurfaceLayer->renderSurface()); // Render surfaces whose drawable area has zero width or height @@ -369,10 +386,10 @@ void LayerRendererChromium::drawLayers(const Vector<CCLayerImpl*>& renderSurface GLC(m_context.get(), m_context->enable(GraphicsContext3D::SCISSOR_TEST)); } - Vector<CCLayerImpl*>& layerList = renderSurfaceLayer->renderSurface()->m_layerList; + LayerList& layerList = renderSurfaceLayer->renderSurface()->m_layerList; ASSERT(layerList.size()); for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex) - drawLayer(layerList[layerIndex], renderSurfaceLayer->renderSurface()); + drawLayer(layerList[layerIndex].get(), renderSurfaceLayer->renderSurface()); } } @@ -412,10 +429,6 @@ void LayerRendererChromium::setRootLayer(PassRefPtr<LayerChromium> layer) if (m_rootLayer) m_rootLayer->setLayerRenderer(this); m_rootLayerContentTiler->invalidateEntireLayer(); - if (m_horizontalScrollbarTiler) - m_horizontalScrollbarTiler->invalidateEntireLayer(); - if (m_verticalScrollbarTiler) - m_verticalScrollbarTiler->invalidateEntireLayer(); } void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& rect) @@ -473,7 +486,7 @@ bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const Transform // Recursively walks the layer tree starting at the given node and computes all the // necessary transformations, scissor rectangles, render surfaces, etc. -void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* layer, const TransformationMatrix& parentMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList) +void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* layer, const TransformationMatrix& parentMatrix, LayerList& renderSurfaceLayerList, LayerList& layerList) { // Make sure we have CCLayerImpls for this subtree. layer->createCCLayerImplIfNeeded(); @@ -659,7 +672,18 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay // M[s] = M * Tr[-center] sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0); - Vector<CCLayerImpl*>& descendants = (drawLayer->renderSurface() ? drawLayer->renderSurface()->m_layerList : layerList); + // Compute the depth value of the center of the layer which will be used when + // sorting the layers for the preserves-3d property. + const TransformationMatrix& layerDrawMatrix = drawLayer->renderSurface() ? drawLayer->renderSurface()->m_drawTransform : drawLayer->drawTransform(); + if (drawLayer->superlayer()) { + if (!drawLayer->superlayer()->preserves3D()) + drawLayer->setDrawDepth(drawLayer->superlayer()->drawDepth()); + else + drawLayer->setDrawDepth(layerDrawMatrix.m43()); + } else + drawLayer->setDrawDepth(0); + + LayerList& descendants = (drawLayer->renderSurface() ? drawLayer->renderSurface()->m_layerList : layerList); descendants.append(drawLayer); unsigned thisLayerIndex = descendants.size() - 1; @@ -730,17 +754,6 @@ void LayerRendererChromium::updatePropertiesAndRenderSurfaces(LayerChromium* lay } } - // Compute the depth value of the center of the layer which will be used when - // sorting the layers for the preserves-3d property. - const TransformationMatrix& layerDrawMatrix = drawLayer->renderSurface() ? drawLayer->renderSurface()->m_drawTransform : drawLayer->drawTransform(); - if (drawLayer->superlayer()) { - if (!drawLayer->superlayer()->preserves3D()) - drawLayer->setDrawDepth(drawLayer->superlayer()->drawDepth()); - else - drawLayer->setDrawDepth(layerDrawMatrix.m43()); - } else - drawLayer->setDrawDepth(0); - // If preserves-3d then sort all the descendants by the Z coordinate of their // center. If the preserves-3d property is also set on the superlayer then // skip the sorting as the superlayer will sort all the descendants anyway. @@ -757,14 +770,16 @@ void LayerRendererChromium::paintContentsRecursive(LayerChromium* layer) if (layer->bounds().isEmpty()) return; + const IntRect targetSurfaceRect = layer->ccLayerImpl()->scissorRect(); + if (layer->drawsContent()) - layer->paintContentsIfDirty(); + layer->paintContentsIfDirty(targetSurfaceRect); if (layer->maskLayer() && layer->maskLayer()->drawsContent()) - layer->maskLayer()->paintContentsIfDirty(); + layer->maskLayer()->paintContentsIfDirty(targetSurfaceRect); if (layer->replicaLayer() && layer->replicaLayer()->drawsContent()) - layer->replicaLayer()->paintContentsIfDirty(); + layer->replicaLayer()->paintContentsIfDirty(targetSurfaceRect); if (layer->replicaLayer() && layer->replicaLayer()->maskLayer() && layer->replicaLayer()->maskLayer()->drawsContent()) - layer->replicaLayer()->maskLayer()->paintContentsIfDirty(); + layer->replicaLayer()->maskLayer()->paintContentsIfDirty(targetSurfaceRect); } void LayerRendererChromium::updateCompositorResourcesRecursive(LayerChromium* layer) @@ -816,7 +831,7 @@ void LayerRendererChromium::copyOffscreenTextureToDisplay() m_defaultRenderSurface->m_drawTransform.translate3d(0.5 * m_defaultRenderSurface->m_contentRect.width(), 0.5 * m_defaultRenderSurface->m_contentRect.height(), 0); m_defaultRenderSurface->m_drawOpacity = 1; - m_defaultRenderSurface->draw(); + m_defaultRenderSurface->draw(m_defaultRenderSurface->m_contentRect); } } @@ -857,10 +872,13 @@ bool LayerRendererChromium::useRenderSurface(RenderSurfaceChromium* renderSurfac void LayerRendererChromium::drawLayer(CCLayerImpl* layer, RenderSurfaceChromium* targetSurface) { if (layer->renderSurface() && layer->renderSurface() != targetSurface) { - layer->renderSurface()->draw(); + layer->renderSurface()->draw(layer->getDrawRect()); return; } + if (!layer->drawsContent()) + return; + if (layer->bounds().isEmpty()) { layer->unreserveContentsTexture(); return; @@ -894,8 +912,7 @@ void LayerRendererChromium::drawLayer(CCLayerImpl* layer, RenderSurfaceChromium* } } - if (layer->drawsContent()) - layer->draw(); + layer->draw(layer->scissorRect()); // Draw the debug border if there is one. layer->drawDebugBorder(); @@ -968,7 +985,6 @@ bool LayerRendererChromium::initializeSharedObjects() m_sharedGeometry = adoptPtr(new GeometryBinding(m_context.get())); m_borderProgram = adoptPtr(new LayerChromium::BorderProgram(m_context.get())); - m_contentLayerProgram = adoptPtr(new ContentLayerChromium::Program(m_context.get())); m_canvasLayerProgram = adoptPtr(new CCCanvasLayerImpl::Program(m_context.get())); m_videoLayerRGBAProgram = adoptPtr(new CCVideoLayerImpl::RGBAProgram(m_context.get())); m_videoLayerYUVProgram = adoptPtr(new CCVideoLayerImpl::YUVProgram(m_context.get())); @@ -978,7 +994,7 @@ bool LayerRendererChromium::initializeSharedObjects() m_tilerProgram = adoptPtr(new LayerTilerChromium::Program(m_context.get())); if (!m_sharedGeometry->initialized() || !m_borderProgram->initialized() - || !m_contentLayerProgram->initialized() || !m_canvasLayerProgram->initialized() + || !m_canvasLayerProgram->initialized() || !m_videoLayerRGBAProgram->initialized() || !m_videoLayerYUVProgram->initialized() || !m_pluginLayerProgram->initialized() || !m_renderSurfaceProgram->initialized() || !m_renderSurfaceMaskProgram->initialized() || !m_tilerProgram->initialized()) { @@ -997,7 +1013,6 @@ void LayerRendererChromium::cleanupSharedObjects() m_sharedGeometry.clear(); m_borderProgram.clear(); - m_contentLayerProgram.clear(); m_canvasLayerProgram.clear(); m_videoLayerRGBAProgram.clear(); m_videoLayerYUVProgram.clear(); @@ -1010,8 +1025,6 @@ void LayerRendererChromium::cleanupSharedObjects() // Clear tilers before the texture manager, as they have references to textures. m_rootLayerContentTiler.clear(); - m_horizontalScrollbarTiler.clear(); - m_verticalScrollbarTiler.clear(); m_textureManager.clear(); } @@ -1027,6 +1040,48 @@ String LayerRendererChromium::layerTreeAsText() const return ts.release(); } +void LayerRendererChromium::addChildContext(GraphicsContext3D* ctx) +{ + if (!ctx->getExtensions()->supports("GL_CHROMIUM_latch")) + return; + + // This is a ref-counting map, because some contexts are shared by multiple + // layers (specifically, Canvas2DLayerChromium). + + // Insert the ctx with a count of 1, or return the existing iterator. + std::pair<ChildContextMap::iterator, bool> insert_result = m_childContexts.add(ctx, 1); + if (!insert_result.second) { + // Already present in map, so increment. + ++insert_result.first->second; + } else { +// FIXME(jbates): when compositor is multithreaded and copyTexImage2D bug is fixed, +// uncomment this block: +// // This is a new child context - set the parentToChild latch so that it +// // can continue past its first wait latch. +// Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(ctx->getExtensions()); +// GC3Duint latchId; +// ext->getParentToChildLatchCHROMIUM(&latchId); +// ext->setLatchCHROMIUM(0, latchId); + } +} + +void LayerRendererChromium::removeChildContext(GraphicsContext3D* ctx) +{ + if (!ctx->getExtensions()->supports("GL_CHROMIUM_latch")) + return; + + ChildContextMap::iterator i = m_childContexts.find(ctx); + if (i != m_childContexts.end()) { + if (--i->second <= 0) { + // Count reached zero, so remove from map. + m_childContexts.remove(i); + } + } else { + // error + ASSERT(0 && "m_childContexts map has mismatched add/remove calls"); + } +} + void LayerRendererChromium::dumpRenderSurfaces(TextStream& ts, int indent, LayerChromium* layer) const { if (layer->ccLayerImpl()->renderSurface()) diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h index 667ede2..813eb46 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -52,22 +52,22 @@ #include <wtf/RefCounted.h> #include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGContext.h> #include <wtf/RetainPtr.h> #endif namespace WebCore { +class CCHeadsUpDisplay; class CCLayerImpl; class GeometryBinding; class GraphicsContext3D; -class CCHeadsUpDisplay; // Class that handles drawing of composited render layers using GL. class LayerRendererChromium : public RefCounted<LayerRendererChromium> { public: - static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint); + static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint); ~LayerRendererChromium(); @@ -88,7 +88,7 @@ public: IntSize viewportSize() const { return m_viewportVisibleRect.size(); } - void setRootLayer(PassRefPtr<LayerChromium> layer); + void setRootLayer(PassRefPtr<LayerChromium>); LayerChromium* rootLayer() { return m_rootLayer.get(); } void transferRootLayer(LayerRendererChromium* other) { other->m_rootLayer = m_rootLayer.release(); } @@ -110,7 +110,6 @@ public: const GeometryBinding* sharedGeometry() const { return m_sharedGeometry.get(); } const LayerChromium::BorderProgram* borderProgram() const { return m_borderProgram.get(); } - const ContentLayerChromium::Program* contentLayerProgram() const { return m_contentLayerProgram.get(); } const RenderSurfaceChromium::Program* renderSurfaceProgram() const { return m_renderSurfaceProgram.get(); } const RenderSurfaceChromium::MaskProgram* renderSurfaceMaskProgram() const { return m_renderSurfaceMaskProgram.get(); } const LayerTilerChromium::Program* tilerProgram() const { return m_tilerProgram.get(); } @@ -131,17 +130,23 @@ public: String layerTreeAsText() const; + void addChildContext(GraphicsContext3D*); + void removeChildContext(GraphicsContext3D*); + private: - explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint, PassOwnPtr<TilePaintInterface> scrollbarPaint); + typedef Vector<RefPtr<CCLayerImpl> > LayerList; + typedef HashMap<GraphicsContext3D*, int> ChildContextMap; + + explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D>, PassOwnPtr<TilePaintInterface> contentPaint); - void updateLayers(Vector<CCLayerImpl*>& renderSurfaceLayerList); + void updateLayers(LayerList& renderSurfaceLayerList); void updateRootLayerContents(); - void updateRootLayerScrollbars(); - void updatePropertiesAndRenderSurfaces(LayerChromium*, const TransformationMatrix& parentMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList); + void updatePropertiesAndRenderSurfaces(LayerChromium*, const TransformationMatrix& parentMatrix, LayerList& renderSurfaceLayerList, LayerList& layers); + void paintContentsRecursive(LayerChromium*); void updateCompositorResourcesRecursive(LayerChromium*); - void drawLayers(const Vector<CCLayerImpl*>& renderSurfaceLayerList); + void drawLayers(const LayerList& renderSurfaceLayerList); void drawLayer(CCLayerImpl*, RenderSurfaceChromium*); void drawRootLayer(); @@ -156,16 +161,13 @@ private: bool makeContextCurrent(); - static bool compareLayerZ(const CCLayerImpl*, const CCLayerImpl*); + static bool compareLayerZ(const RefPtr<CCLayerImpl>&, const RefPtr<CCLayerImpl>&); void dumpRenderSurfaces(TextStream&, int indent, LayerChromium*) const; bool initializeSharedObjects(); void cleanupSharedObjects(); - IntRect verticalScrollbarRect() const; - IntRect horizontalScrollbarRect() const; - IntRect m_viewportVisibleRect; IntRect m_viewportContentRect; IntPoint m_viewportScrollPosition; @@ -174,10 +176,7 @@ private: RefPtr<LayerChromium> m_rootLayer; OwnPtr<TilePaintInterface> m_rootLayerContentPaint; - OwnPtr<TilePaintInterface> m_rootLayerScrollbarPaint; OwnPtr<LayerTilerChromium> m_rootLayerContentTiler; - OwnPtr<LayerTilerChromium> m_horizontalScrollbarTiler; - OwnPtr<LayerTilerChromium> m_verticalScrollbarTiler; bool m_hardwareCompositing; @@ -188,10 +187,10 @@ private: bool m_compositeOffscreen; #if USE(SKIA) - OwnPtr<skia::PlatformCanvas> m_rootLayerCanvas; + OwnPtr<SkCanvas> m_rootLayerCanvas; OwnPtr<PlatformContextSkia> m_rootLayerSkiaContext; OwnPtr<GraphicsContext> m_rootLayerGraphicsContext; -#elif PLATFORM(CG) +#elif USE(CG) Vector<uint8_t> m_rootLayerBackingStore; RetainPtr<CGContextRef> m_rootLayerCGContext; OwnPtr<GraphicsContext> m_rootLayerGraphicsContext; @@ -206,7 +205,6 @@ private: // we cannot store these values in static variables. OwnPtr<GeometryBinding> m_sharedGeometry; OwnPtr<LayerChromium::BorderProgram> m_borderProgram; - OwnPtr<ContentLayerChromium::Program> m_contentLayerProgram; OwnPtr<RenderSurfaceChromium::Program> m_renderSurfaceProgram; OwnPtr<RenderSurfaceChromium::MaskProgram> m_renderSurfaceMaskProgram; OwnPtr<LayerTilerChromium::Program> m_tilerProgram; @@ -220,6 +218,15 @@ private: OwnPtr<CCHeadsUpDisplay> m_headsUpDisplay; RefPtr<GraphicsContext3D> m_context; + ChildContextMap m_childContexts; + + // If true, the child contexts were copied to the compositor texture targets + // and the compositor will need to wait on the proper latches before using + // the target textures. If false, the compositor is reusing the textures + // from last frame. + bool m_childContextsWereCopied; + + bool m_contextSupportsLatch; RenderSurfaceChromium* m_defaultRenderSurface; }; diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp index bc37201..54c6ac2 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.cpp @@ -40,6 +40,8 @@ using namespace std; +static int minTextureSize = 16; + namespace WebCore { PassOwnPtr<LayerTilerChromium> LayerTilerChromium::create(LayerRendererChromium* layerRenderer, const IntSize& tileSize, BorderTexelOption border) @@ -69,8 +71,10 @@ GraphicsContext3D* LayerTilerChromium::layerRendererContext() const return layerRenderer()->context(); } -void LayerTilerChromium::setTileSize(const IntSize& size) +void LayerTilerChromium::setTileSize(const IntSize& requestedSize) { + IntSize size(max(minTextureSize, requestedSize.width()), max(minTextureSize, requestedSize.height())); + if (m_tileSize == size) return; @@ -81,6 +85,12 @@ void LayerTilerChromium::setTileSize(const IntSize& size) m_tilingData.setMaxTextureSize(max(size.width(), size.height())); } +LayerTexture* LayerTilerChromium::getSingleTexture() +{ + Tile* tile = tileAt(0, 0); + return tile ? tile->texture() : 0; +} + void LayerTilerChromium::reset() { m_tiles.clear(); @@ -180,7 +190,7 @@ IntRect LayerTilerChromium::tileLayerRect(const Tile* tile) const void LayerTilerChromium::invalidateRect(const IntRect& contentRect) { - if (contentRect.isEmpty()) + if (contentRect.isEmpty() || m_skipsDraw) return; growLayerToContain(contentRect); @@ -236,6 +246,8 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont tile = createTile(i, j); if (!tile->texture()->isValid(m_tileSize, GraphicsContext3D::RGBA)) tile->m_dirtyLayerRect = tileLayerRect(tile); + else + tile->texture()->reserve(m_tileSize, GraphicsContext3D::RGBA); dirtyLayerRect.unite(tile->m_dirtyLayerRect); } } @@ -243,27 +255,35 @@ void LayerTilerChromium::update(TilePaintInterface& painter, const IntRect& cont if (dirtyLayerRect.isEmpty()) return; - const IntRect paintRect = layerRectToContentRect(dirtyLayerRect); + m_paintRect = layerRectToContentRect(dirtyLayerRect); + + m_canvas.resize(m_paintRect.size()); - m_canvas.resize(paintRect.size()); - PlatformCanvas::Painter canvasPainter(&m_canvas); - canvasPainter.context()->translate(-paintRect.x(), -paintRect.y()); + // Assumption: if a tiler is using border texels, then it is because the + // layer is likely to be filtered or transformed. Because of it might be + // transformed, draw the text in grayscale instead of subpixel antialiasing. + PlatformCanvas::Painter::TextOption textOption = m_tilingData.borderTexels() ? PlatformCanvas::Painter::GrayscaleText : PlatformCanvas::Painter::SubpixelText; + PlatformCanvas::Painter canvasPainter(&m_canvas, textOption); + canvasPainter.context()->translate(-m_paintRect.x(), -m_paintRect.y()); { TRACE_EVENT("LayerTilerChromium::update::paint", this, 0); - painter.paint(*canvasPainter.context(), paintRect); + painter.paint(*canvasPainter.context(), m_paintRect); } +} +void LayerTilerChromium::uploadCanvas() +{ PlatformCanvas::AutoLocker locker(&m_canvas); { TRACE_EVENT("LayerTilerChromium::updateFromPixels", this, 0); - updateFromPixels(paintRect, locker.pixels()); + updateFromPixels(m_paintRect, locker.pixels()); } } void LayerTilerChromium::updateFromPixels(const IntRect& paintRect, const uint8_t* paintPixels) { // Painting could cause compositing to get turned off, which may cause the tiler to become invalidated mid-update. - if (!m_tiles.size()) + if (!m_tilingData.totalSizeX() || !m_tilingData.totalSizeY()) return; GraphicsContext3D* context = layerRendererContext(); @@ -274,21 +294,26 @@ void LayerTilerChromium::updateFromPixels(const IntRect& paintRect, const uint8_ for (int i = left; i <= right; ++i) { Tile* tile = tileAt(i, j); if (!tile) - CRASH(); - if (!tile->dirty()) + tile = createTile(i, j); + else if (!tile->dirty()) continue; // Calculate page-space rectangle to copy from. IntRect sourceRect = tileContentRect(tile); const IntPoint anchor = sourceRect.location(); sourceRect.intersect(layerRectToContentRect(tile->m_dirtyLayerRect)); + // Paint rect not guaranteed to line up on tile boundaries, so + // make sure that sourceRect doesn't extend outside of it. + sourceRect.intersect(paintRect); if (sourceRect.isEmpty()) continue; - if (!tile->texture()->reserve(m_tileSize, GraphicsContext3D::RGBA)) { - m_skipsDraw = true; - reset(); - return; + if (!tile->texture()->isReserved()) { + if (!tile->texture()->reserve(m_tileSize, GraphicsContext3D::RGBA)) { + m_skipsDraw = true; + reset(); + return; + } } // Calculate tile-space rectangle to upload into. @@ -324,8 +349,10 @@ void LayerTilerChromium::updateFromPixels(const IntRect& paintRect, const uint8_ } tile->texture()->bindTexture(); - GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST)); - GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST)); + + const GC3Dint filter = m_tilingData.borderTexels() ? GraphicsContext3D::LINEAR : GraphicsContext3D::NEAREST; + GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, filter)); + GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, filter)); GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, destRect.x(), destRect.y(), destRect.width(), destRect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixelSource)); @@ -339,7 +366,7 @@ void LayerTilerChromium::setLayerPosition(const IntPoint& layerPosition) m_layerPosition = layerPosition; } -void LayerTilerChromium::draw(const IntRect& contentRect) +void LayerTilerChromium::draw(const IntRect& contentRect, const TransformationMatrix& globalTransform, float opacity) { if (m_skipsDraw || !m_tiles.size()) return; @@ -354,17 +381,18 @@ void LayerTilerChromium::draw(const IntRect& contentRect) for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { Tile* tile = tileAt(i, j); - ASSERT(tile); + if (!tile) + continue; tile->texture()->bindTexture(); - TransformationMatrix tileMatrix; + TransformationMatrix tileMatrix(globalTransform); // Don't use tileContentRect here, as that contains the full // rect with border texels which shouldn't be drawn. IntRect tileRect = m_tilingData.tileBounds(m_tilingData.tileIndex(tile->i(), tile->j())); tileRect.move(m_layerPosition.x(), m_layerPosition.y()); - tileMatrix.translate3d(tileRect.x() - contentRect.x() + tileRect.width() / 2.0, tileRect.y() - contentRect.y() + tileRect.height() / 2.0, 0); + tileMatrix.translate3d(tileRect.x() + tileRect.width() / 2.0, tileRect.y() + tileRect.height() / 2.0, 0); IntPoint texOffset = m_tilingData.textureOffset(tile->i(), tile->j()); float tileWidth = static_cast<float>(m_tileSize.width()); @@ -374,13 +402,21 @@ void LayerTilerChromium::draw(const IntRect& contentRect) float texScaleX = tileRect.width() / tileWidth; float texScaleY = tileRect.height() / tileHeight; - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), tileMatrix, tileRect.width(), tileRect.height(), 1, texTranslateX, texTranslateY, texScaleX, texScaleY, program); - - tile->texture()->unreserve(); + drawTexturedQuad(context, layerRenderer()->projectionMatrix(), tileMatrix, tileRect.width(), tileRect.height(), opacity, texTranslateX, texTranslateY, texScaleX, texScaleY, program); } } } +void LayerTilerChromium::unreserveTextures() +{ + for (TileMap::iterator iter = m_tiles.begin(); iter != m_tiles.end(); ++iter) { + Tile* tile = iter->second.get(); + if (!tile) + continue; + tile->texture()->unreserve(); + } +} + void LayerTilerChromium::growLayerToContain(const IntRect& contentRect) { // Grow the tile array to contain this content rect. diff --git a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h index 2f356e4..111dd7e 100644 --- a/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/LayerTilerChromium.h @@ -56,19 +56,40 @@ public: ~LayerTilerChromium(); + // Set invalidations to be potentially repainted during update(). void invalidateRect(const IntRect& contentRect); void invalidateEntireLayer(); + + // Paint all invalidations and missing tiles needed to draw the contentRect + // into the internal canvas. void update(TilePaintInterface& painter, const IntRect& contentRect); + + // Reserve and upload tile textures from the internal canvas. + void uploadCanvas(); + + // Reserve and upload tile textures from an externally painted buffer. void updateFromPixels(const IntRect& paintRect, const uint8_t* pixels); - void draw(const IntRect& contentRect); + + // Draw all tiles that intersect with the content rect. + void draw(const IntRect& contentRect, const TransformationMatrix&, float opacity); + + // If uploadCanvas/updateFromPixels is called, this must be called after + // draw() to unreserve any textures that were reserved prior to uploading. + void unreserveTextures(); // Set position of this tiled layer in content space. void setLayerPosition(const IntPoint& position); // Change the tile size. This may invalidate all the existing tiles. void setTileSize(const IntSize& size); + void setLayerRenderer(LayerRendererChromium* layerRenderer) { m_layerRenderer = layerRenderer; } + + bool skipsDraw() const { return m_skipsDraw; } typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderTexAlpha> Program; + // If this tiler has exactly one tile, return its texture. Otherwise, null. + LayerTexture* getSingleTexture(); + private: LayerTilerChromium(LayerRendererChromium*, const IntSize& tileSize, BorderTexelOption); @@ -140,6 +161,7 @@ private: // Tightly packed set of unused tiles. Vector<RefPtr<Tile> > m_unusedTiles; + IntRect m_paintRect; PlatformCanvas m_canvas; // Cache a tile-sized pixel buffer to draw into. diff --git a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp index 29589f4..afaa6f7 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp +++ b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.cpp @@ -34,7 +34,7 @@ #include "PlatformContextSkia.h" #include "SkColorPriv.h" #include "skia/ext/platform_canvas.h" -#elif PLATFORM(CG) +#elif USE(CG) #include <CoreGraphics/CGBitmapContext.h> #endif @@ -52,8 +52,8 @@ void PlatformCanvas::resize(const IntSize& size) { m_size = size; #if USE(SKIA) - m_skiaCanvas = new skia::PlatformCanvas(size.width(), size.height(), false); -#elif PLATFORM(CG) + m_skiaCanvas = skia::CreateBitmapCanvas(size.width(), size.height(), false); +#elif USE(CG) size_t bufferSize = size.width() * size.height() * 4; m_pixelData = adoptArrayPtr(new uint8_t[bufferSize]); memset(m_pixelData.get(), 0, bufferSize); @@ -73,8 +73,9 @@ PlatformCanvas::AutoLocker::AutoLocker(PlatformCanvas* canvas) m_pixels = static_cast<uint8_t*>(m_bitmap->getPixels()); } else m_bitmap = 0; -#elif PLATFORM(CG) - m_pixels = &canvas->m_pixelData[0]; +#elif USE(CG) + if (canvas->m_pixelData) + m_pixels = &canvas->m_pixelData[0]; #endif } @@ -86,16 +87,15 @@ PlatformCanvas::AutoLocker::~AutoLocker() #endif } -PlatformCanvas::Painter::Painter(PlatformCanvas* canvas) +PlatformCanvas::Painter::Painter(PlatformCanvas* canvas, PlatformCanvas::Painter::TextOption option) { #if USE(SKIA) m_skiaContext = adoptPtr(new PlatformContextSkia(canvas->m_skiaCanvas.get())); - // This is needed to get text to show up correctly. - m_skiaContext->setDrawingToImageBuffer(true); + m_skiaContext->setDrawingToImageBuffer(option == GrayscaleText); m_context = adoptPtr(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(m_skiaContext.get()))); -#elif PLATFORM(CG) +#elif USE(CG) m_colorSpace = CGColorSpaceCreateDeviceRGB(); size_t rowBytes = canvas->size().width() * 4; diff --git a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h index 262fdd0..b002d26 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h +++ b/Source/WebCore/platform/graphics/chromium/PlatformCanvas.h @@ -31,7 +31,7 @@ #include <wtf/Noncopyable.h> #include <wtf/OwnPtr.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGColorSpace.h> #include <CoreGraphics/CGContext.h> #include <wtf/OwnArrayPtr.h> @@ -39,8 +39,8 @@ #endif #if USE(SKIA) -namespace skia { class PlatformCanvas; } class SkBitmap; +class SkCanvas; #endif namespace WebCore { @@ -78,7 +78,9 @@ public: class Painter { WTF_MAKE_NONCOPYABLE(Painter); public: - explicit Painter(PlatformCanvas*); + enum TextOption { GrayscaleText, SubpixelText }; + + Painter(PlatformCanvas*, TextOption); ~Painter(); GraphicsContext* context() const { return m_context.get(); } @@ -86,7 +88,7 @@ public: OwnPtr<GraphicsContext> m_context; #if USE(SKIA) OwnPtr<PlatformContextSkia> m_skiaContext; -#elif PLATFORM(CG) +#elif USE(CG) RetainPtr<CGColorSpaceRef> m_colorSpace; RetainPtr<CGContextRef> m_contextCG; #endif @@ -97,8 +99,8 @@ public: private: #if USE(SKIA) - OwnPtr<skia::PlatformCanvas> m_skiaCanvas; -#elif PLATFORM(CG) + OwnPtr<SkCanvas> m_skiaCanvas; +#elif USE(CG) OwnArrayPtr<uint8_t> m_pixelData; #endif IntSize m_size; diff --git a/Source/WebCore/platform/graphics/chromium/PlatformImage.cpp b/Source/WebCore/platform/graphics/chromium/PlatformImage.cpp index 62cf4f8..c31b29c 100644 --- a/Source/WebCore/platform/graphics/chromium/PlatformImage.cpp +++ b/Source/WebCore/platform/graphics/chromium/PlatformImage.cpp @@ -30,7 +30,7 @@ #if USE(SKIA) #include "NativeImageSkia.h" #include "PlatformContextSkia.h" -#elif PLATFORM(CG) +#elif USE(CG) #include <CoreGraphics/CGBitmapContext.h> #include <CoreGraphics/CGContext.h> #include <CoreGraphics/CGImage.h> @@ -54,7 +54,7 @@ void PlatformImage::updateFromImage(NativeImagePtr nativeImage) IntSize bitmapSize(skiaBitmap->width(), skiaBitmap->height()); ASSERT(skiaBitmap); -#elif PLATFORM(CG) +#elif USE(CG) // NativeImagePtr is a CGImageRef on Mac OS X. int width = CGImageGetWidth(nativeImage); int height = CGImageGetHeight(nativeImage); @@ -73,7 +73,7 @@ void PlatformImage::updateFromImage(NativeImagePtr nativeImage) // FIXME: do we need to support more image configurations? ASSERT(skiaBitmap->config()== SkBitmap::kARGB_8888_Config); skiaBitmap->copyPixelsTo(m_pixelData.get(), bufferSize); -#elif PLATFORM(CG) +#elif USE(CG) // FIXME: we should get rid of this temporary copy where possible. int tempRowBytes = width * 4; // Note we do not zero this vector since we are going to diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp index ca42d0b..c93ef3f 100644 --- a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp @@ -143,7 +143,7 @@ void RenderSurfaceChromium::drawSurface(CCLayerImpl* maskLayer, const Transforma maskLayer->unreserveContentsTexture(); } -void RenderSurfaceChromium::draw() +void RenderSurfaceChromium::draw(const IntRect&) { if (m_skipsDraw || !m_contentsTexture) return; diff --git a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h index 6400c63..7c0e984 100644 --- a/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h +++ b/Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h @@ -52,7 +52,7 @@ public: bool prepareContentsTexture(); void cleanupResources(); - void draw(); + void draw(const IntRect& targetSurfaceRect); String name() const; void dumpSurface(TextStream&, int indent) const; @@ -84,7 +84,7 @@ private: TransformationMatrix m_replicaDrawTransform; TransformationMatrix m_originTransform; IntRect m_scissorRect; - Vector<CCLayerImpl*> m_layerList; + Vector<RefPtr<CCLayerImpl> > m_layerList; }; } diff --git a/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp index 193271d..f2c2394 100644 --- a/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp +++ b/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp @@ -49,14 +49,14 @@ namespace { // 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) +inline SkCanvas* canvasForContext(const GraphicsContext& context) { return context.platformContext()->canvas(); } inline const SkBitmap& bitmapForContext(const GraphicsContext& context) { - return canvasForContext(context)->getTopPlatformDevice().accessBitmap(false); + return canvasForContext(context)->getTopDevice()->accessBitmap(false); } void compositeToCopy(const GraphicsContext& sourceLayers, @@ -466,7 +466,7 @@ void TransparencyWin::compositeTextComposite() if (!m_validLayer) return; - const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopPlatformDevice().accessBitmap(true); + const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopDevice()->accessBitmap(true); SkColor textColor = m_textCompositeColor.rgb(); for (int y = 0; y < m_layerSize.height(); y++) { uint32_t* row = bitmap.getAddr32(0, y); @@ -502,7 +502,7 @@ void TransparencyWin::makeLayerOpaque() return; SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()-> - canvas()->getTopPlatformDevice().accessBitmap(true)); + canvas()->getTopDevice()->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++) diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp index dda84a9..524beec 100644 --- a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp +++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp @@ -31,45 +31,16 @@ #include "config.h" #include "UniscribeHelper.h" -#include <windows.h> - +#include "Font.h" #include "FontUtilsChromiumWin.h" #include "PlatformContextSkia.h" #include "SkiaFontWin.h" #include "SkPoint.h" +#include <windows.h> #include <wtf/Assertions.h> namespace WebCore { -// This function is used to see where word spacing should be applied inside -// runs. Note that this must match Font::treatAsSpace so we all agree where -// and how much space this is, so we don't want to do more general Unicode -// "is this a word break" thing. -static bool treatAsSpace(UChar c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; -} - -// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid -// and blank glyphs. Just because ScriptShape succeeds does not mean -// that a text run is rendered correctly. Some characters may be rendered -// with default/invalid/blank glyphs. Therefore, we need to check if the glyph -// array returned by ScriptShape contains any of those glyphs to make -// sure that the text run is rendered successfully. -static bool containsMissingGlyphs(WORD *glyphs, - int length, - SCRIPT_FONTPROPERTIES* properties) -{ - for (int i = 0; i < length; ++i) { - if (glyphs[i] == properties->wgDefault - || (glyphs[i] == properties->wgInvalid - && glyphs[i] != properties->wgBlank)) - return true; - } - - return false; -} - // HFONT is the 'incarnation' of 'everything' about font, but it's an opaque // handle and we can't directly query it to make a new HFONT sharing // its characteristics (height, style, etc) except for family name. @@ -102,13 +73,15 @@ UniscribeHelper::UniscribeHelper(const UChar* input, bool isRtl, HFONT hfont, SCRIPT_CACHE* scriptCache, - SCRIPT_FONTPROPERTIES* fontProperties) + SCRIPT_FONTPROPERTIES* fontProperties, + WORD spaceGlyph) : m_input(input) , m_inputLength(inputLength) , m_isRtl(isRtl) , m_hfont(hfont) , m_scriptCache(scriptCache) , m_fontProperties(fontProperties) + , m_spaceGlyph(spaceGlyph) , m_directionalOverride(false) , m_inhibitLigate(false) , m_letterSpacing(0) @@ -546,6 +519,7 @@ bool UniscribeHelper::shape(const UChar* input, SCRIPT_CACHE* scriptCache = m_scriptCache; SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties; int ascent = m_ascent; + WORD spaceGlyph = m_spaceGlyph; HDC tempDC = 0; HGDIOBJ oldFont = 0; HRESULT hr; @@ -601,7 +575,7 @@ bool UniscribeHelper::shape(const UChar* input, } else if (hr == E_OUTOFMEMORY) { numGlyphs *= 2; continue; - } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(&shaping.m_glyphs[0], generatedGlyphs, fontProperties))) + } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(shaping, run, fontProperties))) break; // The current font can't render this run. clear DC and try @@ -632,7 +606,9 @@ bool UniscribeHelper::shape(const UChar* input, const UChar *family = getFallbackFamily(input, itemLength, FontDescription::StandardFamily, 0, 0); bool fontOk = getDerivedFontData(family, m_style, &m_logfont, - &ascent, &hfont, &scriptCache); + &ascent, &hfont, &scriptCache, + &spaceGlyph); + if (!fontOk) { // If this GetDerivedFontData is called from the renderer it @@ -644,7 +620,8 @@ bool UniscribeHelper::shape(const UChar* input, // Try again. fontOk = getDerivedFontData(family, m_style, &m_logfont, - &ascent, &hfont, &scriptCache); + &ascent, &hfont, &scriptCache, + &spaceGlyph); ASSERT(fontOk); } @@ -673,6 +650,7 @@ bool UniscribeHelper::shape(const UChar* input, // because it's not used elsewhere. shaping.m_hfont = hfont; shaping.m_scriptCache = scriptCache; + shaping.m_spaceGlyph = spaceGlyph; // The ascent of a font for this run can be different from // that of the primary font so that we need to keep track of @@ -806,22 +784,39 @@ void UniscribeHelper::adjustSpaceAdvances() for (size_t run = 0; run < m_runs.size(); run++) { Shaping& shaping = m_shapes[run]; + // FIXME: This loop is not UTF-16-safe. Unicode 6.0 has a couple + // of complex script blocks in Plane 1. for (int i = 0; i < shaping.charLength(); i++) { - if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) + UChar c = m_input[m_runs[run].iCharPos + i]; + bool treatAsSpace = Font::treatAsSpace(c); + if (!treatAsSpace && !Font::treatAsZeroWidthSpaceInComplexScript(c)) continue; int glyphIndex = shaping.m_logs[i]; int currentAdvance = shaping.m_advance[glyphIndex]; - // currentAdvance does not include additional letter-spacing, but - // space_width does. Here we find out how off we are from the - // correct width for the space not including letter-spacing, then - // just subtract that diff. - int diff = currentAdvance - spaceWidthWithoutLetterSpacing; - // The shaping can consist of a run of text, so only subtract the - // difference in the width of the glyph. - shaping.m_advance[glyphIndex] -= diff; - shaping.m_abc.abcB -= diff; + if (treatAsSpace) { + // currentAdvance does not include additional letter-spacing, + // but m_spaceWidth does. Here we find out how off we are from + // the correct width (spaceWidthWithoutLetterSpacing) and + // just subtract that diff. + int diff = currentAdvance - spaceWidthWithoutLetterSpacing; + // The shaping can consist of a run of text, so only subtract + // the difference in the width of the glyph. + shaping.m_advance[glyphIndex] -= diff; + shaping.m_abc.abcB -= diff; + continue; + } + + // For characters treated as zero-width space in complex + // scripts, set the advance width to zero, adjust + // |abcB| of the current run accordingly and set + // the glyph to m_spaceGlyph (invisible). + shaping.m_advance[glyphIndex] = 0; + shaping.m_abc.abcB -= currentAdvance; + shaping.m_offsets[glyphIndex].du = 0; + shaping.m_offsets[glyphIndex].dv = 0; + shaping.m_glyphs[glyphIndex] = shaping.m_spaceGlyph; } } } @@ -872,7 +867,7 @@ void UniscribeHelper::applySpacing() // extra wordspacing amount for the glyphs they correspond to. if (m_wordSpacing != 0) { for (int i = 0; i < shaping.charLength(); i++) { - if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) + if (!Font::treatAsSpace(m_input[m_runs[run].iCharPos + i])) continue; // The char in question is a word separator... @@ -929,4 +924,31 @@ int UniscribeHelper::advanceForItem(int itemIndex) const return shaping.m_prePadding + justification; } +// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid +// and blank glyphs. Just because ScriptShape succeeds does not mean +// that a text run is rendered correctly. Some characters may be rendered +// with default/invalid/blank glyphs. Therefore, we need to check if the glyph +// array returned by ScriptShape contains any of those glyphs to make +// sure that the text run is rendered successfully. +// However, we should not subject zero-width characters to this test. + +bool UniscribeHelper::containsMissingGlyphs(const Shaping& shaping, + const SCRIPT_ITEM& run, + const SCRIPT_FONTPROPERTIES* properties) const +{ + for (int i = 0; i < shaping.charLength(); i++) { + UChar c = m_input[run.iCharPos + i]; + // Skip zero-width space characters because they're not considered to be missing in a font. + if (Font::treatAsZeroWidthSpaceInComplexScript(c)) + continue; + int glyphIndex = shaping.m_logs[i]; + WORD glyph = shaping.m_glyphs[glyphIndex]; + if (glyph == properties->wgDefault + || (glyph == properties->wgInvalid && glyph != properties->wgBlank)) + return true; + } + return false; +} + + } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h index ffd57db..4bcdbd6 100644 --- a/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h +++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelper.h @@ -76,7 +76,8 @@ public: bool isRtl, HFONT, SCRIPT_CACHE*, - SCRIPT_FONTPROPERTIES*); + SCRIPT_FONTPROPERTIES*, + WORD); virtual ~UniscribeHelper(); @@ -225,7 +226,9 @@ private: : m_prePadding(0) , m_hfont(NULL) , m_scriptCache(NULL) - , m_ascentOffset(0) { + , m_ascentOffset(0) + , m_spaceGlyph(0) + { m_abc.abcA = 0; m_abc.abcB = 0; m_abc.abcC = 0; @@ -319,6 +322,8 @@ private: // when drawing a string, to align multiple runs rendered with // different fonts. int m_ascentOffset; + + WORD m_spaceGlyph; }; // Computes the runs_ array from the text run. @@ -343,6 +348,10 @@ private: // Returns the total width of a single item. int advanceForItem(int) const; + bool containsMissingGlyphs(const Shaping&, + const SCRIPT_ITEM&, + const SCRIPT_FONTPROPERTIES*) const; + // Shapes a run (pointed to by |input|) using |hfont| first. // Tries a series of fonts specified retrieved with NextWinFontData // and finally a font covering characters in |*input|. A string pointed @@ -384,6 +393,7 @@ private: int m_ascent; LOGFONT m_logfont; int m_style; + WORD m_spaceGlyph; // Options, see the getters/setters above. bool m_directionalOverride; diff --git a/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp index c060b43..8e0bc04 100644 --- a/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp +++ b/Source/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp @@ -43,7 +43,8 @@ UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run, : UniscribeHelper(run.characters(), run.length(), run.rtl(), font.primaryFont()->platformData().hfont(), font.primaryFont()->platformData().scriptCache(), - font.primaryFont()->platformData().scriptFontProperties()) + font.primaryFont()->platformData().scriptFontProperties(), + font.primaryFont()->spaceGlyph()) , m_font(&font) , m_fontIndex(0) { @@ -69,7 +70,7 @@ UniscribeHelperTextRun::UniscribeHelperTextRun( SCRIPT_CACHE* scriptCache, SCRIPT_FONTPROPERTIES* fontProperties) : UniscribeHelper(input, inputLength, isRtl, hfont, - scriptCache, fontProperties) + scriptCache, fontProperties, 0) , m_font(0) , m_fontIndex(-1) { diff --git a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 182e730..e75df24 100644 --- a/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -96,7 +96,7 @@ void VideoLayerChromium::cleanupResources() void VideoLayerChromium::updateCompositorResources() { - if (!m_contentsDirty) + if (!m_contentsDirty || !m_owner) return; RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp index 652e752..aef14ed 100644 --- a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp +++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp @@ -51,6 +51,12 @@ WebGLLayerChromium::WebGLLayerChromium(GraphicsLayerChromium* owner) { } +WebGLLayerChromium::~WebGLLayerChromium() +{ + if (m_context && layerRenderer()) + layerRenderer()->removeChildContext(m_context); +} + void WebGLLayerChromium::updateCompositorResources() { if (!m_contentsDirty) @@ -70,6 +76,9 @@ void WebGLLayerChromium::updateCompositorResources() } // Update the contents of the texture used by the compositor. if (m_contentsDirty && m_textureUpdated) { + // prepareTexture copies the contents of the off-screen render target into the texture + // used by the compositor. + // m_context->prepareTexture(); m_context->markLayerComposited(); m_contentsDirty = false; @@ -84,6 +93,13 @@ void WebGLLayerChromium::setTextureUpdated() void WebGLLayerChromium::setContext(const GraphicsContext3D* context) { + if (m_context != context && layerRenderer()) { + if (m_context) + layerRenderer()->removeChildContext(m_context); + if (context) + layerRenderer()->addChildContext(const_cast<GraphicsContext3D*>(context)); + } + m_context = const_cast<GraphicsContext3D*>(context); unsigned int textureId = m_context->platformTexture(); @@ -95,5 +111,19 @@ void WebGLLayerChromium::setContext(const GraphicsContext3D* context) m_premultipliedAlpha = m_context->getContextAttributes().premultipliedAlpha; } +void WebGLLayerChromium::setLayerRenderer(LayerRendererChromium* newLayerRenderer) +{ + if (layerRenderer() != newLayerRenderer) { + if (m_context) { + if (layerRenderer()) + layerRenderer()->removeChildContext(m_context); + if (newLayerRenderer) + newLayerRenderer->addChildContext(m_context); + } + + LayerChromium::setLayerRenderer(newLayerRenderer); + } +} + } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h index 33db730..342275b 100644 --- a/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h +++ b/Source/WebCore/platform/graphics/chromium/WebGLLayerChromium.h @@ -44,12 +44,17 @@ class GraphicsContext3D; class WebGLLayerChromium : public CanvasLayerChromium { public: static PassRefPtr<WebGLLayerChromium> create(GraphicsLayerChromium* owner = 0); + + virtual ~WebGLLayerChromium(); + virtual bool drawsContent() const { return m_context; } virtual void updateCompositorResources(); void setTextureUpdated(); void setContext(const GraphicsContext3D* context); + virtual void setLayerRenderer(LayerRendererChromium*); + protected: virtual const char* layerTypeAsString() const { return "WebGLLayer"; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp index 649d049..d70e15c 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.cpp @@ -47,7 +47,7 @@ CCCanvasLayerImpl::~CCCanvasLayerImpl() { } -void CCCanvasLayerImpl::draw() +void CCCanvasLayerImpl::draw(const IntRect&) { ASSERT(layerRenderer()); const CCCanvasLayerImpl::Program* program = layerRenderer()->canvasLayerProgram(); @@ -77,4 +77,3 @@ void CCCanvasLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const } #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h index 8cbf8d1..3aa917c 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCanvasLayerImpl.h @@ -42,7 +42,7 @@ public: typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; - virtual void draw(); + virtual void draw(const IntRect&); virtual void dumpLayerProperties(TextStream&, int indent) const; @@ -58,4 +58,3 @@ private: } #endif // CCCanvasLayerImpl_h - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCCompletionEvent.h b/Source/WebCore/platform/graphics/chromium/cc/CCCompletionEvent.h new file mode 100644 index 0000000..a8ac151 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCCompletionEvent.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CCCompletionEvent_h +#define CCCompletionEvent_h + +#include <wtf/ThreadingPrimitives.h> + +namespace WebCore { + +class CCCompletionEvent { +public: + CCCompletionEvent() + { + m_mutex.lock(); + } + + ~CCCompletionEvent() + { + m_mutex.unlock(); + } + + void wait() + { + m_condition.wait(m_mutex); + } + + void signal() + { + MutexLocker lock(m_mutex); + m_condition.signal(); + } + +private: + Mutex m_mutex; + ThreadCondition m_condition; +}; + +} + +#endif diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp index 404944b..d22b098 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp @@ -44,13 +44,30 @@ namespace WebCore { using namespace std; CCHeadsUpDisplay::CCHeadsUpDisplay(LayerRendererChromium* owner) - : m_currentFrameNumber(0) + : m_currentFrameNumber(1) + , m_filteredFrameTime(0) , m_layerRenderer(owner) , m_showFPSCounter(false) , m_showPlatformLayerTree(false) { m_presentTimeHistoryInSec[0] = currentTime(); m_presentTimeHistoryInSec[1] = m_presentTimeHistoryInSec[0]; + for (int i = 2; i < kPresentHistorySize; i++) + m_presentTimeHistoryInSec[i] = 0; + + FontDescription mediumFontDesc; + mediumFontDesc.setGenericFamily(FontDescription::MonospaceFamily); + mediumFontDesc.setComputedSize(20); + + m_mediumFont = adoptPtr(new Font(mediumFontDesc, 0, 0)); + m_mediumFont->update(0); + + FontDescription smallFontDesc; + smallFontDesc.setGenericFamily(FontDescription::MonospaceFamily); + smallFontDesc.setComputedSize(10); + + m_smallFont = adoptPtr(new Font(smallFontDesc, 0, 0)); + m_smallFont->update(0); } CCHeadsUpDisplay::~CCHeadsUpDisplay() @@ -79,7 +96,7 @@ void CCHeadsUpDisplay::draw() PlatformCanvas canvas; canvas.resize(hudSize); { - PlatformCanvas::Painter painter(&canvas); + PlatformCanvas::Painter painter(&canvas, PlatformCanvas::Painter::GrayscaleText); drawHudContents(painter.context(), hudSize); } @@ -92,7 +109,7 @@ void CCHeadsUpDisplay::draw() } // Draw the HUD onto the default render surface. - const ContentLayerChromium::Program* program = m_layerRenderer->contentLayerProgram(); + const LayerTilerChromium::Program* program = m_layerRenderer->tilerProgram(); ASSERT(program && program->initialized()); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); m_hudTexture->bindTexture(); @@ -111,59 +128,98 @@ void CCHeadsUpDisplay::draw() void CCHeadsUpDisplay::drawHudContents(GraphicsContext* ctx, const IntSize& hudSize) { - FontDescription mediumFontDesc; - mediumFontDesc.setGenericFamily(FontDescription::MonospaceFamily); - mediumFontDesc.setComputedSize(12); - Font mediumFont(mediumFontDesc, 0, 0); - mediumFont.update(0); - - FontDescription smallFontDesc; - smallFontDesc.setGenericFamily(FontDescription::MonospaceFamily); - smallFontDesc.setComputedSize(10); - Font smallFont(smallFontDesc, 0, 0); - smallFont.update(0); - - // We haven't finished rendering yet, so we don't now the "current" present time. - // So, consider the *last two* present times and use those as our present time. - double secForLastFrame = m_presentTimeHistoryInSec[(m_currentFrameNumber - 1) % 2] - m_presentTimeHistoryInSec[m_currentFrameNumber % 2]; - - int y = 14; - if (m_showPlatformLayerTree) { ctx->setFillColor(Color(0, 0, 0, 192), ColorSpaceDeviceRGB); ctx->fillRect(FloatRect(0, 0, hudSize.width(), hudSize.height())); } - // Draw fps. - String topLine = ""; - if (secForLastFrame > 0 && m_showFPSCounter) { - double fps = 1.0 / secForLastFrame; - topLine += String::format("FPS: %3.1f", fps); - } - if (topLine.length()) { - ctx->setFillColor(Color(0, 0, 0, 255), ColorSpaceDeviceRGB); - TextRun run(topLine); - ctx->fillRect(FloatRect(2, 2, mediumFont.width(run) + 2.0f, 15)); + int fpsCounterHeight = m_mediumFont->fontMetrics().floatHeight() + 2; + int fpsCounterTop = 2; + int platformLayerTreeTop; + if (m_showFPSCounter) + platformLayerTreeTop = fpsCounterTop + fpsCounterHeight + 2; + else + platformLayerTreeTop = 0; + + if (m_showFPSCounter) + drawFPSCounter(ctx, fpsCounterTop, fpsCounterHeight); + + if (m_showPlatformLayerTree) + drawPlatformLayerTree(ctx, platformLayerTreeTop); +} + +void CCHeadsUpDisplay::drawFPSCounter(GraphicsContext* ctx, int top, int height) +{ + // Note that since we haven't finished the current frame, the FPS counter + // actually reports the last frame's time. + double secForLastFrame = m_presentTimeHistoryInSec[(m_currentFrameNumber + kPresentHistorySize - 1) % kPresentHistorySize] - + m_presentTimeHistoryInSec[(m_currentFrameNumber + kPresentHistorySize - 2) % kPresentHistorySize]; + + // Filter the frame times to avoid spikes. + const float alpha = 0.1; + if (!m_filteredFrameTime) { + if (m_currentFrameNumber == 2) + m_filteredFrameTime = secForLastFrame; + } else + m_filteredFrameTime = ((1.0 - alpha) * m_filteredFrameTime) + (alpha * secForLastFrame); + + // Create & measure FPS text. + String text(String::format("FPS: %5.1f", 1.0 / m_filteredFrameTime)); + TextRun run(text); + float textWidth = m_mediumFont->width(run) + 2.0f; + float graphWidth = kPresentHistorySize; + + // Draw background. + ctx->setFillColor(Color(0, 0, 0, 255), ColorSpaceDeviceRGB); + ctx->fillRect(FloatRect(2, top, textWidth + graphWidth, height)); + + // Draw FPS text. + if (m_filteredFrameTime) { ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB); - ctx->drawText(mediumFont, run, IntPoint(3, y)); - y = 26; + ctx->drawText(*m_mediumFont, run, IntPoint(3, top + height - 6)); } - // Draw layer tree, if enabled. - if (m_showPlatformLayerTree) { - ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB); - Vector<String> lines; - m_layerRenderer->layerTreeAsText().split('\n', lines); - for (size_t i = 0; i < lines.size(); ++i) { - ctx->drawText(smallFont, TextRun(lines[i]), IntPoint(2, y)); - y += 12; - } + // Draw FPS graph. + const double loFPS = 0.0; + const double hiFPS = 120.0; + ctx->setStrokeStyle(SolidStroke); + ctx->setStrokeColor(Color(255, 0, 0), ColorSpaceDeviceRGB); + int graphLeft = static_cast<int>(textWidth + 3); + IntPoint prev(-1, 0); + int x = 0; + double h = static_cast<double>(height - 2); + for (int i = m_currentFrameNumber % kPresentHistorySize; i != (m_currentFrameNumber - 1) % kPresentHistorySize; i = (i + 1) % kPresentHistorySize) { + int j = (i + 1) % kPresentHistorySize; + double fps = 1.0 / (m_presentTimeHistoryInSec[j] - m_presentTimeHistoryInSec[i]); + double p = 1 - ((fps - loFPS) / (hiFPS - loFPS)); + if (p < 0) + p = 0; + if (p > 1) + p = 1; + IntPoint cur(graphLeft + x, 1 + top + p*h); + if (prev.x() != -1) + ctx->drawLine(prev, cur); + prev = cur; + x += 1; + } +} + +void CCHeadsUpDisplay::drawPlatformLayerTree(GraphicsContext* ctx, int top) +{ + float smallFontHeight = m_smallFont->fontMetrics().floatHeight(); + int y = top + smallFontHeight - 4; + ctx->setFillColor(Color(255, 0, 0), ColorSpaceDeviceRGB); + Vector<String> lines; + m_layerRenderer->layerTreeAsText().split('\n', lines); + for (size_t i = 0; i < lines.size(); ++i) { + ctx->drawText(*m_smallFont, TextRun(lines[i]), IntPoint(2, y)); + y += smallFontHeight; } } void CCHeadsUpDisplay::onPresent() { - m_presentTimeHistoryInSec[m_currentFrameNumber % 2] = currentTime(); + m_presentTimeHistoryInSec[m_currentFrameNumber % kPresentHistorySize] = currentTime(); m_currentFrameNumber += 1; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h index d56f8ab..09f198a 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCHeadsUpDisplay.h @@ -27,8 +27,10 @@ #if USE(ACCELERATED_COMPOSITING) +#include "Font.h" #include "LayerRendererChromium.h" + namespace WebCore { class GeometryBinding; @@ -59,17 +61,26 @@ public: private: explicit CCHeadsUpDisplay(LayerRendererChromium* owner); void drawHudContents(GraphicsContext*, const IntSize& hudSize); + void drawFPSCounter(GraphicsContext*, int top, int height); + void drawPlatformLayerTree(GraphicsContext*, int top); + int m_currentFrameNumber; + double m_filteredFrameTime; + OwnPtr<LayerTexture> m_hudTexture; LayerRendererChromium* m_layerRenderer; - double m_presentTimeHistoryInSec[2]; + static const int kPresentHistorySize = 64; + double m_presentTimeHistoryInSec[kPresentHistorySize]; bool m_showFPSCounter; bool m_showPlatformLayerTree; + + OwnPtr<Font> m_smallFont; + OwnPtr<Font> m_mediumFont; }; } diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp index 9411e5a..e2d651d 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp @@ -126,12 +126,12 @@ bool CCLayerImpl::descendantsDrawsContent() // These belong on CCLayerImpl, but should be overridden by each type and not defer to the LayerChromium subtypes. bool CCLayerImpl::drawsContent() const { - return m_owner->drawsContent(); + return m_owner && m_owner->drawsContent(); } -void CCLayerImpl::draw() +void CCLayerImpl::draw(const IntRect& targetSurfaceRect) { - return m_owner->draw(); + return m_owner->draw(targetSurfaceRect); } void CCLayerImpl::updateCompositorResources() @@ -215,4 +215,3 @@ void CCLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const } #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h index 96c4f1b..649f4dd 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h @@ -50,6 +50,7 @@ public: } // When this class gets subclasses, remember to add 'virtual' here. virtual ~CCLayerImpl(); + void resetOwner() { m_owner = 0; } #ifndef NDEBUG int debugID() const { return m_debugID; } @@ -59,7 +60,7 @@ public: CCLayerImpl* maskLayer() const; CCLayerImpl* replicaLayer() const; - virtual void draw(); + virtual void draw(const IntRect& contentRect); virtual void updateCompositorResources(); void unreserveContentsTexture(); void bindContentsTexture(); @@ -205,4 +206,3 @@ private: } #endif // CCLayerImpl_h - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.cpp new file mode 100644 index 0000000..cd36817 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include "CCMainThread.h" + +#include <wtf/MainThread.h> + +using namespace WTF; + +namespace WebCore { + +void CCMainThread::performTask(void* userdata) +{ + Task* task = static_cast<Task*>(userdata); + task->performTask(); + delete task; +} + +void CCMainThread::postTask(PassOwnPtr<Task> task) +{ + callOnMainThread(performTask, task.leakPtr()); +} + +} diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.h b/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.h new file mode 100644 index 0000000..ca8e8c1 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCMainThread.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef CCMainThread_h +#define CCMainThread_h + +#include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +// Task wrapper around WTF::callOnMainThreadThread +class CCMainThread { +public: + class Task { + WTF_MAKE_NONCOPYABLE(Task); + public: + virtual ~Task() { } + virtual void performTask() = 0; + void* instance() const { return m_instance; } + protected: + Task(void* instance) : m_instance(instance) { } + void* m_instance; + }; + + static void postTask(PassOwnPtr<Task>); // Executes the task on main thread asynchronously. +private: + static void performTask(void*); +}; + +} // namespace WebCore + +#endif // CCMainThread_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCMainThreadTask.h b/Source/WebCore/platform/graphics/chromium/cc/CCMainThreadTask.h new file mode 100644 index 0000000..7de8d71 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCMainThreadTask.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2011 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef CCMainThreadTask_h +#define CCMainThreadTask_h + +#include "CCMainThread.h" +#include "CrossThreadCopier.h" +#include "CrossThreadTask.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +template<typename T> +class MainThreadTask0 : public CCMainThread::Task { +public: + typedef void (T::*Method)(); + typedef MainThreadTask0<T> MainThreadTaskImpl; + + static PassOwnPtr<MainThreadTaskImpl> create(T* instance, Method method) + { + return adoptPtr(new MainThreadTaskImpl(instance, method)); + } + +private: + MainThreadTask0(T* instance, Method method) + : CCMainThread::Task(instance) + , m_method(method) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(); + } + +private: + Method m_method; +}; + +template<typename T, typename P1, typename MP1> +class MainThreadTask1 : public CCMainThread::Task { +public: + typedef void (T::*Method)(MP1); + typedef MainThreadTask1<T, P1, MP1> MainThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + + static PassOwnPtr<MainThreadTaskImpl> create(T* instance, Method method, Param1 parameter1) + { + return adoptPtr(new MainThreadTaskImpl(instance, method, parameter1)); + } + +private: + MainThreadTask1(T* instance, Method method, Param1 parameter1) + : CCMainThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1); + } + +private: + Method m_method; + P1 m_parameter1; +}; + +template<typename T, typename P1, typename MP1, typename P2, typename MP2> +class MainThreadTask2 : public CCMainThread::Task { +public: + typedef void (T::*Method)(MP1, MP2); + typedef MainThreadTask2<T, P1, MP1, P2, MP2> MainThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + + static PassOwnPtr<MainThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2) + { + return adoptPtr(new MainThreadTaskImpl(instance, method, parameter1, parameter2)); + } + +private: + MainThreadTask2(T* instance, Method method, Param1 parameter1, Param2 parameter2) + : CCMainThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; +}; + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +class MainThreadTask3 : public CCMainThread::Task { +public: + typedef void (T::*Method)(MP1, MP2, MP3); + typedef MainThreadTask3<T, P1, MP1, P2, MP2, P3, MP3> MainThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + typedef typename CrossThreadTaskTraits<P3>::ParamType Param3; + + static PassOwnPtr<MainThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + { + return adoptPtr(new MainThreadTaskImpl(instance, method, parameter1, parameter2, parameter3)); + } + +private: + MainThreadTask3(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + : CCMainThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2, m_parameter3); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; +}; + +template<typename T> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)()); + +template<typename T> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)()) +{ + return MainThreadTask0<T>::create( + callee, + method); +} + +template<typename T, typename P1, typename MP1> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)(MP1), + const P1& parameter1) +{ + return MainThreadTask1<T, typename CrossThreadCopier<P1>::Type, MP1>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)(MP1, MP2), + const P1& parameter1, + const P2& parameter2) +{ + return MainThreadTask2<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +PassOwnPtr<CCMainThread::Task> createMainThreadTask( + T* const callee, + void (T::*method)(MP1, MP2, MP3), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3) +{ + return MainThreadTask3<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3)); +} + +} // namespace WebCore + +#endif // CCMainThreadTask_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp index 4aef639..a428829 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.cpp @@ -46,7 +46,7 @@ CCPluginLayerImpl::~CCPluginLayerImpl() { } -void CCPluginLayerImpl::draw() +void CCPluginLayerImpl::draw(const IntRect&) { ASSERT(layerRenderer()); const CCPluginLayerImpl::Program* program = layerRenderer()->pluginLayerProgram(); @@ -81,4 +81,3 @@ void CCPluginLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const } #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h index 65eb5b7..4fd7457 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCPluginLayerImpl.h @@ -42,7 +42,7 @@ public: typedef ProgramBinding<VertexShaderPosTex, FragmentShaderRGBATexFlipAlpha> Program; - virtual void draw(); + virtual void draw(const IntRect&); virtual void dumpLayerProperties(TextStream&, int indent) const; @@ -57,4 +57,3 @@ private: } #endif // CCPluginLayerImpl_h - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThread.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCThread.cpp new file mode 100644 index 0000000..9566584 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThread.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "CCThread.h" + +#include "LayerRendererChromium.h" +#include <wtf/CurrentTime.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/ThreadingPrimitives.h> + +namespace WebCore { + +using namespace WTF; + +CCThread::CCThread() +{ + MutexLocker lock(m_threadCreationMutex); + m_threadID = createThread(CCThread::compositorThreadStart, this, "Chromium Compositor"); +} + +CCThread::~CCThread() +{ + m_queue.kill(); + + // Stop thread. + void* exitCode; + waitForThreadCompletion(m_threadID, &exitCode); + m_threadID = 0; +} + +void CCThread::postTask(PassOwnPtr<Task> task) +{ + m_queue.append(task); +} + +void* CCThread::compositorThreadStart(void* userdata) +{ + CCThread* ccThread = static_cast<CCThread*>(userdata); + return ccThread->runLoop(); +} + +void* CCThread::runLoop() +{ + { + // Wait for CCThread::start() to complete to have m_threadID + // established before starting the main loop. + MutexLocker lock(m_threadCreationMutex); + } + + while (OwnPtr<Task> task = m_queue.waitForMessage()) + task->performTask(); + + return 0; +} + +} diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThread.h b/Source/WebCore/platform/graphics/chromium/cc/CCThread.h new file mode 100644 index 0000000..177d3f3 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThread.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CCThread_h +#define CCThread_h + +#include <wtf/MessageQueue.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Threading.h> + +namespace WebCore { + +// The CCThread singleton owns the compositor thread and provides +// basic infrastructure for messaging between the two threads. +class CCThread { +public: + static PassOwnPtr<CCThread> create() + { + return adoptPtr(new CCThread()); + } + + virtual ~CCThread(); + + class Task { + WTF_MAKE_NONCOPYABLE(Task); + public: + virtual ~Task() { } + virtual void performTask() = 0; + void* instance() const { return m_instance; } + protected: + Task(void* instance) : m_instance(instance) { } + void* m_instance; + }; + + void postTask(PassOwnPtr<Task>); // Executes the task on context's thread asynchronously. + + WTF::ThreadIdentifier threadID() const { return m_threadID; } + +protected: + explicit CCThread(); + + static void* compositorThreadStart(void*); + void* runLoop(); + + WTF::ThreadIdentifier m_threadID; + MessageQueue<Task> m_queue; + + Mutex m_threadCreationMutex; +}; + +} + +#endif diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCThreadTask.h b/Source/WebCore/platform/graphics/chromium/cc/CCThreadTask.h new file mode 100644 index 0000000..71245d3 --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/cc/CCThreadTask.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2011 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef CCThreadTask_h +#define CCThreadTask_h + +#include "CCThread.h" +#include "CrossThreadCopier.h" +#include "CrossThreadTask.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +template<typename T> +class CCThreadTask0 : public CCThread::Task { +public: + typedef void (T::*Method)(); + typedef CCThreadTask0<T> CCThreadTaskImpl; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method) + { + return adoptPtr(new CCThreadTaskImpl(instance, method)); + } + +private: + CCThreadTask0(T* instance, Method method) + : CCThread::Task(instance) + , m_method(method) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(); + } + +private: + Method m_method; +}; + +template<typename T, typename P1, typename MP1> +class CCThreadTask1 : public CCThread::Task { +public: + typedef void (T::*Method)(MP1); + typedef CCThreadTask1<T, P1, MP1> CCThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method, Param1 parameter1) + { + return adoptPtr(new CCThreadTaskImpl(instance, method, parameter1)); + } + +private: + CCThreadTask1(T* instance, Method method, Param1 parameter1) + : CCThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1); + } + +private: + Method m_method; + P1 m_parameter1; +}; + +template<typename T, typename P1, typename MP1, typename P2, typename MP2> +class CCThreadTask2 : public CCThread::Task { +public: + typedef void (T::*Method)(MP1, MP2); + typedef CCThreadTask2<T, P1, MP1, P2, MP2> CCThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2) + { + return adoptPtr(new CCThreadTaskImpl(instance, method, parameter1, parameter2)); + } + +private: + CCThreadTask2(T* instance, Method method, Param1 parameter1, Param2 parameter2) + : CCThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; +}; + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +class CCThreadTask3 : public CCThread::Task { +public: + typedef void (T::*Method)(MP1, MP2, MP3); + typedef CCThreadTask3<T, P1, MP1, P2, MP2, P3, MP3> CCThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + typedef typename CrossThreadTaskTraits<P3>::ParamType Param3; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + { + return adoptPtr(new CCThreadTaskImpl(instance, method, parameter1, parameter2, parameter3)); + } + +private: + CCThreadTask3(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + : CCThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2, m_parameter3); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; +}; + + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4> +class CCThreadTask4 : public CCThread::Task { +public: + typedef void (T::*Method)(MP1, MP2, MP3, MP4); + typedef CCThreadTask4<T, P1, MP1, P2, MP2, P3, MP3, P4, MP4> CCThreadTaskImpl; + typedef typename CrossThreadTaskTraits<P1>::ParamType Param1; + typedef typename CrossThreadTaskTraits<P2>::ParamType Param2; + typedef typename CrossThreadTaskTraits<P3>::ParamType Param3; + typedef typename CrossThreadTaskTraits<P4>::ParamType Param4; + + static PassOwnPtr<CCThreadTaskImpl> create(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4) + { + return adoptPtr(new CCThreadTaskImpl(instance, method, parameter1, parameter2, parameter3, parameter4)); + } + +private: + CCThreadTask4(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4) + : CCThread::Task(instance) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + , m_parameter4(parameter4) + { + } + + virtual void performTask() + { + (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2, m_parameter3, m_parameter4); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; + P4 m_parameter4; +}; + +template<typename T> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)()); + +template<typename T> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)()) +{ + return CCThreadTask0<T>::create( + callee, + method); +} + +template<typename T, typename P1, typename MP1> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)(MP1), + const P1& parameter1) +{ + return CCThreadTask1<T, typename CrossThreadCopier<P1>::Type, MP1>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)(MP1, MP2), + const P1& parameter1, + const P2& parameter2) +{ + return CCThreadTask2<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)(MP1, MP2, MP3), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3) +{ + return CCThreadTask3<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3)); +} + +template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4> +PassOwnPtr<CCThread::Task> createCCThreadTask( + T* const callee, + void (T::*method)(MP1, MP2, MP3, MP4), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3, + const P4& parameter4) +{ + return CCThreadTask4<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3, typename CrossThreadCopier<P4>::Type, MP4>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3), + CrossThreadCopier<P4>::copy(parameter4)); + +} + +} // namespace WebCore + +#endif // CCThreadTask_h diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp index eb3612b..99a148d 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.cpp @@ -75,7 +75,7 @@ void CCVideoLayerImpl::setTexture(size_t i, VideoLayerChromium::Texture texture) m_textures[i] = texture; } -void CCVideoLayerImpl::draw() +void CCVideoLayerImpl::draw(const IntRect&) { if (m_skipsDraw) return; @@ -170,4 +170,3 @@ void CCVideoLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const } #endif // USE(ACCELERATED_COMPOSITING) - diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h index 62f8778..0e1d1f6 100644 --- a/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h +++ b/Source/WebCore/platform/graphics/chromium/cc/CCVideoLayerImpl.h @@ -47,7 +47,7 @@ public: typedef ProgramBinding<VertexShaderPosTexTransform, FragmentShaderRGBATexFlipAlpha> RGBAProgram; typedef ProgramBinding<VertexShaderPosTexYUVStretch, FragmentShaderYUVVideo> YUVProgram; - virtual void draw(); + virtual void draw(const IntRect&); virtual void dumpLayerProperties(TextStream&, int indent) const; @@ -72,4 +72,3 @@ private: } #endif // CCVideoLayerImpl_h - diff --git a/Source/WebCore/platform/graphics/filters/FEFlood.cpp b/Source/WebCore/platform/graphics/filters/FEFlood.cpp index 3c48cf9..d832d2b 100644 --- a/Source/WebCore/platform/graphics/filters/FEFlood.cpp +++ b/Source/WebCore/platform/graphics/filters/FEFlood.cpp @@ -49,9 +49,12 @@ Color FEFlood::floodColor() const return m_floodColor; } -void FEFlood::setFloodColor(const Color& color) +bool FEFlood::setFloodColor(const Color& color) { + if (m_floodColor == color) + return false; m_floodColor = color; + return true; } float FEFlood::floodOpacity() const @@ -59,9 +62,12 @@ float FEFlood::floodOpacity() const return m_floodOpacity; } -void FEFlood::setFloodOpacity(float floodOpacity) +bool FEFlood::setFloodOpacity(float floodOpacity) { + if (m_floodOpacity == floodOpacity) + return false; m_floodOpacity = floodOpacity; + return true; } void FEFlood::apply() diff --git a/Source/WebCore/platform/graphics/filters/FEFlood.h b/Source/WebCore/platform/graphics/filters/FEFlood.h index 2e8824f..cac4153 100644 --- a/Source/WebCore/platform/graphics/filters/FEFlood.h +++ b/Source/WebCore/platform/graphics/filters/FEFlood.h @@ -34,10 +34,10 @@ public: static PassRefPtr<FEFlood> create(Filter* filter, const Color&, float); Color floodColor() const; - void setFloodColor(const Color &); + bool setFloodColor(const Color &); float floodOpacity() const; - void setFloodOpacity(float); + bool setFloodOpacity(float); virtual void apply(); virtual void dump(); diff --git a/Source/WebCore/platform/graphics/filters/FELighting.cpp b/Source/WebCore/platform/graphics/filters/FELighting.cpp index ec1ca88..13a69fd 100644 --- a/Source/WebCore/platform/graphics/filters/FELighting.cpp +++ b/Source/WebCore/platform/graphics/filters/FELighting.cpp @@ -30,6 +30,13 @@ #include "FELighting.h" #include "LightSource.h" +#include "PointLightSource.h" +#include "SpotLightSource.h" + +#if CPU(ARM_NEON) && COMPILER(GCC) +#include "FELightingNEON.h" +#include <wtf/Vector.h> +#endif namespace WebCore { @@ -301,6 +308,9 @@ bool FELighting::drawLighting(ByteArray* pixels, int width, int height) if (width >= 3 && height >= 3) { // Interior pixels +#if CPU(ARM_NEON) && COMPILER(GCC) + drawInteriorPixels(data, paintingData); +#else for (int y = 1; y < data.heightDecreasedByOne; ++y) { offset = y * data.widthMultipliedByPixelSize + cPixelSize; for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) { @@ -308,6 +318,7 @@ bool FELighting::drawLighting(ByteArray* pixels, int width, int height) inlineSetPixel(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, normalVector); } } +#endif } int lastPixel = data.widthMultipliedByPixelSize * height; @@ -354,6 +365,118 @@ void FELighting::apply() drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height()); } +#if CPU(ARM_NEON) && COMPILER(GCC) + +static int getPowerCoefficients(float exponent) +{ + // Calling a powf function from the assembly code would require to save + // and reload a lot of NEON registers. Since the base is in range [0..1] + // and only 8 bit precision is required, we use our own powf function. + // This is probably not the best, but it uses only a few registers and + // gives us enough precision (modifying the exponent field directly would + // also be possible). + + // First, we limit the exponent to maximum of 64, which gives us enough + // precision. We split the exponent to an integer and fraction part, + // since a^x = (a^y)*(a^z) where x = y+z. The integer exponent of the + // power is estimated by square, and the fraction exponent of the power + // is estimated by square root assembly instructions. + int i, result; + + if (exponent < 0) + exponent = 1 / (-exponent); + + if (exponent > 63.99) + exponent = 63.99; + + exponent /= 64; + result = 0; + for (i = 11; i >= 0; --i) { + exponent *= 2; + if (exponent >= 1) { + result |= 1 << i; + exponent -= 1; + } + } + return result; +} + +void FELighting::drawInteriorPixels(LightingData& data, LightSource::PaintingData& paintingData) +{ + WTF_ALIGNED(FELightingFloatArgumentsForNeon, floatArguments, 16); + + FELightingPaintingDataForNeon neonData = { + data.pixels->data(), + data.widthDecreasedByOne - 1, + data.heightDecreasedByOne - 1, + 0, + 0, + 0, + &floatArguments, + feLightingConstantsForNeon() + }; + + // Set light source arguments. + floatArguments.constOne = 1; + + floatArguments.colorRed = m_lightingColor.red(); + floatArguments.colorGreen = m_lightingColor.green(); + floatArguments.colorBlue = m_lightingColor.blue(); + floatArguments.padding4 = 0; + + if (m_lightSource->type() == LS_POINT) { + neonData.flags |= FLAG_POINT_LIGHT; + PointLightSource* pointLightSource = static_cast<PointLightSource*>(m_lightSource.get()); + floatArguments.lightX = pointLightSource->position().x(); + floatArguments.lightY = pointLightSource->position().y(); + floatArguments.lightZ = pointLightSource->position().z(); + floatArguments.padding2 = 0; + } else if (m_lightSource->type() == LS_SPOT) { + neonData.flags |= FLAG_SPOT_LIGHT; + SpotLightSource* spotLightSource = static_cast<SpotLightSource*>(m_lightSource.get()); + floatArguments.lightX = spotLightSource->position().x(); + floatArguments.lightY = spotLightSource->position().y(); + floatArguments.lightZ = spotLightSource->position().z(); + floatArguments.padding2 = 0; + + floatArguments.directionX = paintingData.directionVector.x(); + floatArguments.directionY = paintingData.directionVector.y(); + floatArguments.directionZ = paintingData.directionVector.z(); + floatArguments.padding3 = 0; + + floatArguments.coneCutOffLimit = paintingData.coneCutOffLimit; + floatArguments.coneFullLight = paintingData.coneFullLight; + floatArguments.coneCutOffRange = paintingData.coneCutOffLimit - paintingData.coneFullLight; + neonData.coneExponent = getPowerCoefficients(spotLightSource->specularExponent()); + if (spotLightSource->specularExponent() == 1) + neonData.flags |= FLAG_CONE_EXPONENT_IS_1; + } else { + ASSERT(m_lightSource.type == LS_DISTANT); + floatArguments.lightX = paintingData.lightVector.x(); + floatArguments.lightY = paintingData.lightVector.y(); + floatArguments.lightZ = paintingData.lightVector.z(); + floatArguments.padding2 = 1; + } + + // Set lighting arguments. + floatArguments.surfaceScale = data.surfaceScale; + floatArguments.minusSurfaceScaleDividedByFour = -data.surfaceScale / 4; + if (m_lightingType == FELighting::DiffuseLighting) + floatArguments.diffuseConstant = m_diffuseConstant; + else { + neonData.flags |= FLAG_SPECULAR_LIGHT; + floatArguments.diffuseConstant = m_specularConstant; + neonData.specularExponent = getPowerCoefficients(m_specularExponent); + if (m_specularExponent == 1) + neonData.flags |= FLAG_SPECULAR_EXPONENT_IS_1; + } + if (floatArguments.diffuseConstant == 1) + neonData.flags |= FLAG_DIFFUSE_CONST_IS_1; + + neonDrawLighting(&neonData); +} +#endif // CPU(ARM_NEON) && COMPILER(GCC) + } // namespace WebCore #endif // ENABLE(FILTERS) diff --git a/Source/WebCore/platform/graphics/filters/FELighting.h b/Source/WebCore/platform/graphics/filters/FELighting.h index fa1c0aa..3dc46e9 100644 --- a/Source/WebCore/platform/graphics/filters/FELighting.h +++ b/Source/WebCore/platform/graphics/filters/FELighting.h @@ -33,6 +33,7 @@ #include "FilterEffect.h" #include "LightSource.h" #include <wtf/ByteArray.h> +#include <wtf/Platform.h> // Common base class for FEDiffuseLighting and FESpecularLighting @@ -79,6 +80,10 @@ protected: void setPixel(int offset, LightingData&, LightSource::PaintingData&, int lightX, int lightY, float factorX, float factorY, IntPoint& normalVector); +#if CPU(ARM_NEON) && COMPILER(GCC) + void drawInteriorPixels(LightingData&, LightSource::PaintingData&); +#endif + LightingType m_lightingType; RefPtr<LightSource> m_lightSource; diff --git a/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp b/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp index a20eb8c..2c7b1eb 100644 --- a/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp +++ b/Source/WebCore/platform/graphics/filters/FESpecularLighting.cpp @@ -54,9 +54,12 @@ Color FESpecularLighting::lightingColor() const return m_lightingColor; } -void FESpecularLighting::setLightingColor(const Color& lightingColor) +bool FESpecularLighting::setLightingColor(const Color& lightingColor) { + if (m_lightingColor == lightingColor) + return false; m_lightingColor = lightingColor; + return true; } float FESpecularLighting::surfaceScale() const diff --git a/Source/WebCore/platform/graphics/filters/FESpecularLighting.h b/Source/WebCore/platform/graphics/filters/FESpecularLighting.h index 9d3ea2d..9fa3add 100644 --- a/Source/WebCore/platform/graphics/filters/FESpecularLighting.h +++ b/Source/WebCore/platform/graphics/filters/FESpecularLighting.h @@ -34,7 +34,7 @@ public: virtual ~FESpecularLighting(); Color lightingColor() const; - void setLightingColor(const Color&); + bool setLightingColor(const Color&); float surfaceScale() const; bool setSurfaceScale(float); diff --git a/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp new file mode 100644 index 0000000..3807f1f --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.cpp @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Zoltan Herczeg + * + * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 "FELightingNEON.h" + +#if CPU(ARM_NEON) && COMPILER(GCC) + +#include <wtf/Vector.h> + +namespace WebCore { + +// These constants are copied to the following SIMD registers: +// ALPHAX_Q ALPHAY_Q REMAPX_D REMAPY_D + +WTF_ALIGNED(short, s_FELightingConstantsForNeon[], 16) = { + // Alpha coefficients. + -2, 1, 0, -1, 2, 1, 0, -1, + 0, -1, -2, -1, 0, 1, 2, 1, + // Remapping indicies. + 0x0f0e, 0x0302, 0x0504, 0x0706, + 0x0b0a, 0x1312, 0x1514, 0x1716, +}; + +short* feLightingConstantsForNeon() +{ + return s_FELightingConstantsForNeon; +} + +#define ASSTRING(str) #str +#define TOSTRING(value) ASSTRING(value) + +#define PIXELS_OFFSET TOSTRING(0) +#define WIDTH_OFFSET TOSTRING(4) +#define HEIGHT_OFFSET TOSTRING(8) +#define FLAGS_OFFSET TOSTRING(12) +#define SPECULAR_EXPONENT_OFFSET TOSTRING(16) +#define CONE_EXPONENT_OFFSET TOSTRING(20) +#define FLOAT_ARGUMENTS_OFFSET TOSTRING(24) +#define DRAWING_CONSTANTS_OFFSET TOSTRING(28) +#define NL "\n" + +// Register allocation +#define PAINTING_DATA_R "r11" +#define RESET_WIDTH_R PAINTING_DATA_R +#define PIXELS_R "r4" +#define WIDTH_R "r5" +#define HEIGHT_R "r6" +#define FLAGS_R "r7" +#define SPECULAR_EXPONENT_R "r8" +#define CONE_EXPONENT_R "r10" +#define SCANLINE_R "r12" + +#define TMP1_Q "q0" +#define TMP1_D0 "d0" +#define TMP1_S0 "s0" +#define TMP1_S1 "s1" +#define TMP1_D1 "d1" +#define TMP1_S2 "s2" +#define TMP1_S3 "s3" +#define TMP2_Q "q1" +#define TMP2_D0 "d2" +#define TMP2_S0 "s4" +#define TMP2_S1 "s5" +#define TMP2_D1 "d3" +#define TMP2_S2 "s6" +#define TMP2_S3 "s7" +#define TMP3_Q "q2" +#define TMP3_D0 "d4" +#define TMP3_S0 "s8" +#define TMP3_S1 "s9" +#define TMP3_D1 "d5" +#define TMP3_S2 "s10" +#define TMP3_S3 "s11" + +#define COSINE_OF_ANGLE "s12" +#define POWF_INT_S "s13" +#define POWF_FRAC_S "s14" +#define SPOT_COLOR_Q "q4" + +// Because of VMIN and VMAX CONST_ZERO_S and CONST_ONE_S +// must be placed on the same side of the double vector + +// Current pixel position +#define POSITION_Q "q5" +#define POSITION_X_S "s20" +#define POSITION_Y_S "s21" +#define POSITION_Z_S "s22" +#define CONST_ZERO_HI_D "d11" +#define CONST_ZERO_S "s23" + +// ------------------------------- +// Variable arguments +// Misc arguments +#define READ1_RANGE "d12-d15" +#define READ2_RANGE "d16-d19" +#define READ3_RANGE "d20-d21" + +#define SCALE_S "s24" +#define SCALE_DIV4_S "s25" +#define DIFFUSE_CONST_S "s26" + +// Light source position +#define CONE_CUT_OFF_S "s28" +#define CONE_FULL_LIGHT_S "s29" +#define CONE_CUT_OFF_RANGE_S "s30" +#define CONST_ONE_HI_D "d15" +#define CONST_ONE_S "s31" + +#define LIGHT_Q "q8" +#define DIRECTION_Q "q9" +#define COLOR_Q "q10" +// ------------------------------- +// Constant coefficients +#define READ4_RANGE "d22-d25" +#define READ5_RANGE "d26-d27" + +#define ALPHAX_Q "q11" +#define ALPHAY_Q "q12" +#define REMAPX_D "d26" +#define REMAPY_D "d27" +// ------------------------------- + +#define ALL_ROWS_D "{d28,d29,d30}" +#define TOP_ROW_D "d28" +#define MIDDLE_ROW_D "d29" +#define BOTTOM_ROW_D "d30" + +#define GET_LENGTH(source, temp) \ + "vmul.f32 " temp##_Q ", " source##_Q ", " source##_Q NL \ + "vadd.f32 " source##_S3 ", " temp##_S0 ", " temp##_S1 NL \ + "vadd.f32 " source##_S3 ", " source##_S3 ", " temp##_S2 NL \ + "vsqrt.f32 " source##_S3 ", " source##_S3 NL + +// destination##_S3 can contain the multiply of length. +#define DOT_PRODUCT(destination, source1, source2) \ + "vmul.f32 " destination##_Q ", " source1##_Q ", " source2##_Q NL \ + "vadd.f32 " destination##_S0 ", " destination##_S0 ", " destination##_S1 NL \ + "vadd.f32 " destination##_S0 ", " destination##_S0 ", " destination##_S2 NL + +#define MULTIPLY_BY_DIFFUSE_CONST(normalVectorLength, dotProductLength) \ + "tst " FLAGS_R ", #" TOSTRING(FLAG_DIFFUSE_CONST_IS_1) NL \ + "vmuleq.f32 " TMP2_S1 ", " DIFFUSE_CONST_S ", " normalVectorLength NL \ + "vdiveq.f32 " TMP2_S1 ", " TMP2_S1 ", " dotProductLength NL \ + "vdivne.f32 " TMP2_S1 ", " normalVectorLength ", " dotProductLength NL + +#define POWF_SQR(value, exponent, current, remaining) \ + "tst " exponent ", #" ASSTRING(current) NL \ + "vmulne.f32 " value ", " value ", " POWF_INT_S NL \ + "tst " exponent ", #" ASSTRING(remaining) NL \ + "vmulne.f32 " POWF_INT_S ", " POWF_INT_S ", " POWF_INT_S NL + +#define POWF_SQRT(value, exponent, current, remaining) \ + "tst " exponent ", #" ASSTRING(remaining) NL \ + "vsqrtne.f32 " POWF_FRAC_S ", " POWF_FRAC_S NL \ + "tst " exponent ", #" ASSTRING(current) NL \ + "vmulne.f32 " value ", " value ", " POWF_FRAC_S NL + +// This simplified powf function is sufficiently accurate. +#define POWF(value, exponent) \ + "tst " exponent ", #0xfc0" NL \ + "vmovne.f32 " POWF_INT_S ", " value NL \ + "tst " exponent ", #0x03f" NL \ + "vmovne.f32 " POWF_FRAC_S ", " value NL \ + "vmov.f32 " value ", " CONST_ONE_S NL \ + \ + POWF_SQR(value, exponent, 0x040, 0xf80) \ + POWF_SQR(value, exponent, 0x080, 0xf00) \ + POWF_SQR(value, exponent, 0x100, 0xe00) \ + POWF_SQR(value, exponent, 0x200, 0xc00) \ + POWF_SQR(value, exponent, 0x400, 0x800) \ + "tst " exponent ", #0x800" NL \ + "vmulne.f32 " value ", " value ", " POWF_INT_S NL \ + \ + POWF_SQRT(value, exponent, 0x20, 0x3f) \ + POWF_SQRT(value, exponent, 0x10, 0x1f) \ + POWF_SQRT(value, exponent, 0x08, 0x0f) \ + POWF_SQRT(value, exponent, 0x04, 0x07) \ + POWF_SQRT(value, exponent, 0x02, 0x03) \ + POWF_SQRT(value, exponent, 0x01, 0x01) + +// The following algorithm is an ARM-NEON optimized version of +// the main loop found in FELighting.cpp. Since the whole code +// is redesigned to be as effective as possible (ARM specific +// thinking), it is four times faster than its C++ counterpart. + +asm ( // NOLINT +".globl " TOSTRING(neonDrawLighting) NL +TOSTRING(neonDrawLighting) ":" NL + // Because of the clever register allocation, nothing is stored on the stack + // except the saved registers. + // Stack must be aligned to 8 bytes. + "stmdb sp!, {r4-r8, r10, r11, lr}" NL + "vstmdb sp!, {d8-d15}" NL + "mov " PAINTING_DATA_R ", r0" NL + + // The following two arguments are loaded to SIMD registers. + "ldr r0, [" PAINTING_DATA_R ", #" FLOAT_ARGUMENTS_OFFSET "]" NL + "ldr r1, [" PAINTING_DATA_R ", #" DRAWING_CONSTANTS_OFFSET "]" NL + "ldr " PIXELS_R ", [" PAINTING_DATA_R ", #" PIXELS_OFFSET "]" NL + "ldr " WIDTH_R ", [" PAINTING_DATA_R ", #" WIDTH_OFFSET "]" NL + "ldr " HEIGHT_R ", [" PAINTING_DATA_R ", #" HEIGHT_OFFSET "]" NL + "ldr " FLAGS_R ", [" PAINTING_DATA_R ", #" FLAGS_OFFSET "]" NL + "ldr " SPECULAR_EXPONENT_R ", [" PAINTING_DATA_R ", #" SPECULAR_EXPONENT_OFFSET "]" NL + "ldr " CONE_EXPONENT_R ", [" PAINTING_DATA_R ", #" CONE_EXPONENT_OFFSET "]" NL + + // Load all data to the SIMD registers with the least number of instructions. + "vld1.f32 { " READ1_RANGE " }, [r0]!" NL + "vld1.f32 { " READ2_RANGE " }, [r0]!" NL + "vld1.f32 { " READ3_RANGE " }, [r0]!" NL + "vld1.s16 {" READ4_RANGE "}, [r1]!" NL + "vld1.s16 {" READ5_RANGE "}, [r1]!" NL + + // Initializing local variables. + "mov " SCANLINE_R ", " WIDTH_R ", lsl #2" NL + "add " SCANLINE_R ", " SCANLINE_R ", #8" NL + "add " PIXELS_R ", " PIXELS_R ", " SCANLINE_R NL + "add " PIXELS_R ", " PIXELS_R ", #3" NL + "mov r0, #0" NL + "vmov.f32 " CONST_ZERO_S ", r0" NL + "vmov.f32 " POSITION_Y_S ", " CONST_ONE_S NL + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "vmov.f32 " SPOT_COLOR_Q ", " COLOR_Q NL + "mov " RESET_WIDTH_R ", " WIDTH_R NL + +".mainloop:" NL + "mov r3, #3" NL + "vmov.f32 " POSITION_X_S ", " CONST_ONE_S NL + +".scanline:" NL + // The ROW registers are storing the alpha channel of the last three pixels. + // The alpha channel is stored as signed short (sint16) values. The fourth value + // is garbage. The following instructions are shifting out the unnecessary alpha + // values and load the next ones. + "ldrb r0, [" PIXELS_R ", -" SCANLINE_R "]" NL + "ldrb r1, [" PIXELS_R ", +" SCANLINE_R "]" NL + "ldrb r2, [" PIXELS_R "], #4" NL + "vext.s16 " TOP_ROW_D ", " TOP_ROW_D ", " TOP_ROW_D ", #3" NL + "vext.s16 " MIDDLE_ROW_D ", " MIDDLE_ROW_D ", " MIDDLE_ROW_D ", #3" NL + "vext.s16 " BOTTOM_ROW_D ", " BOTTOM_ROW_D ", " BOTTOM_ROW_D ", #3" NL + "vmov.s16 " TOP_ROW_D "[1], r0" NL + "vmov.s16 " MIDDLE_ROW_D "[1], r2" NL + "vmov.s16 " BOTTOM_ROW_D "[1], r1" NL + + // The two border pixels (rightmost and leftmost) are skipped when + // the next scanline is reached. It also jumps, when the algorithm + // is started, and the first free alpha values are loaded to each row. + "subs r3, r3, #1" NL + "bne .scanline" NL + + // The light vector goes to TMP1_Q. It is constant in case of distant light. + // The fourth value contains the length of the light vector. + "tst " FLAGS_R ", #" TOSTRING(FLAG_POINT_LIGHT | FLAG_SPOT_LIGHT) NL + "beq .distantLight" NL + + "vmov.s16 r3, " MIDDLE_ROW_D "[2]" NL + "vmov.f32 " POSITION_Z_S ", r3" NL + "vcvt.f32.s32 " POSITION_Z_S ", " POSITION_Z_S NL + "vmul.f32 " POSITION_Z_S ", " POSITION_Z_S ", " SCALE_S NL + + "vsub.f32 " TMP1_Q ", " LIGHT_Q ", " POSITION_Q NL + GET_LENGTH(TMP1, TMP2) + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "bne .cosineOfAngle" NL +".visiblePixel:" NL + + // | -1 0 1 | | -1 -2 -1 | + // X = | -2 0 2 | Y = | 0 0 0 | + // | -1 0 1 | | 1 2 1 | + + // Multiply the alpha values by the X and Y matrices. + + // Moving the 8 alpha value to TMP3. + "vtbl.8 " TMP3_D0 ", " ALL_ROWS_D ", " REMAPX_D NL + "vtbl.8 " TMP3_D1 ", " ALL_ROWS_D ", " REMAPY_D NL + + "vmul.s16 " TMP2_Q ", " TMP3_Q ", " ALPHAX_Q NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D1 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vmov.s16 r0, " TMP2_D0 "[0]" NL + + "vmul.s16 " TMP2_Q ", " TMP3_Q ", " ALPHAY_Q NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D1 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL + "vmov.s16 r1, " TMP2_D0 "[0]" NL + + // r0 and r1 contains the X and Y coordinates of the + // normal vector, respectively. + + // Calculating the spot light strength. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL + "beq .endLight" NL + + "vneg.f32 " TMP3_S1 ", " COSINE_OF_ANGLE NL + "tst " FLAGS_R ", #" TOSTRING(FLAG_CONE_EXPONENT_IS_1) NL + "beq .coneExpPowf" NL +".coneExpPowfFinished:" NL + + // Smoothing the cone edge if necessary. + "vcmp.f32 " COSINE_OF_ANGLE ", " CONE_FULL_LIGHT_S NL + "fmstat" NL + "bhi .cutOff" NL +".cutOffFinished:" NL + + "vmin.f32 " TMP3_D0 ", " TMP3_D0 ", " CONST_ONE_HI_D NL + "vmul.f32 " COLOR_Q ", " SPOT_COLOR_Q ", " TMP3_D0 "[1]" NL + +".endLight:" NL + // Summarize: + // r0 and r1 contains the normalVector. + // TMP1_Q contains the light vector and its length. + // COLOR_Q contains the color of the light vector. + + // Test whether both r0 and r1 are zero (Normal vector is (0, 0, 1)). + "orrs r2, r0, r1" NL + "bne .normalVectorIsNonZero" NL + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_LIGHT) NL + "bne .specularLight1" NL + + // Calculate diffuse light strength. + MULTIPLY_BY_DIFFUSE_CONST(TMP1_S2, TMP1_S3) + "b .lightStrengthCalculated" NL + +".specularLight1:" NL + // Calculating specular light strength. + "vadd.f32 " TMP1_S2 ", " TMP1_S2 ", " TMP1_S3 NL + GET_LENGTH(TMP1, TMP2) + + // When the exponent is 1, we don't need to call an expensive powf function. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_EXPONENT_IS_1) NL + "vdiveq.f32 " TMP2_S1 ", " TMP1_S2 ", " TMP1_S3 NL + "beq .specularExpPowf" NL + + MULTIPLY_BY_DIFFUSE_CONST(TMP1_S2, TMP1_S3) + "b .lightStrengthCalculated" NL + +".normalVectorIsNonZero:" NL + // Normal vector goes to TMP2, and its length is calculated as well. + "vmov.s32 " TMP2_S0 ", r0" NL + "vcvt.f32.s32 " TMP2_S0 ", " TMP2_S0 NL + "vmul.f32 " TMP2_S0 ", " TMP2_S0 ", " SCALE_DIV4_S NL + "vmov.s32 " TMP2_S1 ", r1" NL + "vcvt.f32.s32 " TMP2_S1 ", " TMP2_S1 NL + "vmul.f32 " TMP2_S1 ", " TMP2_S1 ", " SCALE_DIV4_S NL + "vmov.f32 " TMP2_S2 ", " CONST_ONE_S NL + GET_LENGTH(TMP2, TMP3) + + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_LIGHT) NL + "bne .specularLight2" NL + + // Calculating diffuse light strength. + DOT_PRODUCT(TMP3, TMP2, TMP1) + MULTIPLY_BY_DIFFUSE_CONST(TMP3_S0, TMP3_S3) + "b .lightStrengthCalculated" NL + +".specularLight2:" NL + // Calculating specular light strength. + "vadd.f32 " TMP1_S2 ", " TMP1_S2 ", " TMP1_S3 NL + GET_LENGTH(TMP1, TMP3) + DOT_PRODUCT(TMP3, TMP2, TMP1) + + // When the exponent is 1, we don't need to call an expensive powf function. + "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_EXPONENT_IS_1) NL + "vdiveq.f32 " TMP2_S1 ", " TMP3_S0 ", " TMP3_S3 NL + "beq .specularExpPowf" NL + MULTIPLY_BY_DIFFUSE_CONST(TMP3_S0, TMP3_S3) + +".lightStrengthCalculated:" NL + // TMP2_S1 contains the light strength. Clamp it to [0, 1] + "vmax.f32 " TMP2_D0 ", " TMP2_D0 ", " CONST_ZERO_HI_D NL + "vmin.f32 " TMP2_D0 ", " TMP2_D0 ", " CONST_ONE_HI_D NL + "vmul.f32 " TMP3_Q ", " COLOR_Q ", " TMP2_D0 "[1]" NL + "vcvt.u32.f32 " TMP3_Q ", " TMP3_Q NL + "vmov.u32 r2, r3, " TMP3_S0 ", " TMP3_S1 NL + // The color values are stored in-place. + "strb r2, [" PIXELS_R ", #-11]" NL + "strb r3, [" PIXELS_R ", #-10]" NL + "vmov.u32 r2, " TMP3_S2 NL + "strb r2, [" PIXELS_R ", #-9]" NL + + // Continue to the next pixel. +".blackPixel:" NL + "vadd.f32 " POSITION_X_S ", " CONST_ONE_S NL + "mov r3, #1" NL + "subs " WIDTH_R ", " WIDTH_R ", #1" NL + "bne .scanline" NL + + // If the end of the scanline is reached, we continue + // to the next scanline. + "vadd.f32 " POSITION_Y_S ", " CONST_ONE_S NL + "mov " WIDTH_R ", " RESET_WIDTH_R NL + "subs " HEIGHT_R ", " HEIGHT_R ", #1" NL + "bne .mainloop" NL + + // Return. + "vldmia sp!, {d8-d15}" NL + "ldmia sp!, {r4-r8, r10, r11, pc}" NL + +".distantLight:" NL + // In case of distant light, the light vector is constant, + // we simply copy it. + "vmov.f32 " TMP1_Q ", " LIGHT_Q NL + "b .visiblePixel" NL + +".cosineOfAngle:" NL + // If the pixel is outside of the cone angle, it is simply a black pixel. + DOT_PRODUCT(TMP3, TMP1, DIRECTION) + "vdiv.f32 " COSINE_OF_ANGLE ", " TMP3_S0 ", " TMP1_S3 NL + "vcmp.f32 " COSINE_OF_ANGLE ", " CONE_CUT_OFF_S NL + "fmstat" NL + "bls .visiblePixel" NL + "mov r0, #0" NL + "strh r0, [" PIXELS_R ", #-11]" NL + "strb r0, [" PIXELS_R ", #-9]" NL + "b .blackPixel" NL + +".cutOff:" NL + // Smoothing the light strength on the cone edge. + "vsub.f32 " TMP3_S0 ", " CONE_CUT_OFF_S ", " COSINE_OF_ANGLE NL + "vdiv.f32 " TMP3_S0 ", " TMP3_S0 ", " CONE_CUT_OFF_RANGE_S NL + "vmul.f32 " TMP3_S1 ", " TMP3_S1 ", " TMP3_S0 NL + "b .cutOffFinished" NL + +".coneExpPowf:" NL + POWF(TMP3_S1, CONE_EXPONENT_R) + "b .coneExpPowfFinished" NL + +".specularExpPowf:" NL + POWF(TMP2_S1, SPECULAR_EXPONENT_R) + "tst " FLAGS_R ", #" TOSTRING(FLAG_DIFFUSE_CONST_IS_1) NL + "vmuleq.f32 " TMP2_S1 ", " TMP2_S1 ", " DIFFUSE_CONST_S NL + "b .lightStrengthCalculated" NL +); // NOLINT + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) diff --git a/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h new file mode 100644 index 0000000..d83b7fe --- /dev/null +++ b/Source/WebCore/platform/graphics/filters/arm/FELightingNEON.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2011 University of Szeged + * Copyright (C) 2011 Zoltan Herczeg + * + * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 FELightingNeon_h +#define FELightingNeon_h + +#include <wtf/Platform.h> + +#if CPU(ARM_NEON) && COMPILER(GCC) + +namespace WebCore { + +// Otherwise: Distant Light. +#define FLAG_POINT_LIGHT 0x01 +#define FLAG_SPOT_LIGHT 0x02 +#define FLAG_CONE_EXPONENT_IS_1 0x04 + +// Otherwise: Diffuse light. +#define FLAG_SPECULAR_LIGHT 0x10 +#define FLAG_DIFFUSE_CONST_IS_1 0x20 +#define FLAG_SPECULAR_EXPONENT_IS_1 0x40 + +// Must be aligned to 16 bytes. +struct FELightingFloatArgumentsForNeon { + float surfaceScale; + float minusSurfaceScaleDividedByFour; + float diffuseConstant; + float padding1; + + float coneCutOffLimit; + float coneFullLight; + float coneCutOffRange; + float constOne; + + float lightX; + float lightY; + float lightZ; + float padding2; + + float directionX; + float directionY; + float directionZ; + float padding3; + + float colorRed; + float colorGreen; + float colorBlue; + float padding4; +}; + +struct FELightingPaintingDataForNeon { + unsigned char* pixels; + int widthDecreasedByTwo; + int heightDecreasedByTwo; + // Combination of FLAG constants above. + int flags; + int specularExponent; + int coneExponent; + FELightingFloatArgumentsForNeon* floatArguments; + short* paintingConstants; +}; + +short* feLightingConstantsForNeon(); + +extern "C" { +void neonDrawLighting(FELightingPaintingDataForNeon*); +} + +} // namespace WebCore + +#endif // CPU(ARM_NEON) && COMPILER(GCC) + +#endif // FELightingNeon_h diff --git a/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp b/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp index 40c9843..f6f428d 100644 --- a/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/BicubicShader.cpp @@ -55,11 +55,12 @@ PassOwnPtr<BicubicShader> BicubicShader::create(GraphicsContext3D* context) static const char* vertexShaderSource = "uniform mat3 matrix;\n" "uniform mat3 texMatrix;\n" - "attribute vec3 position;\n" + "attribute vec2 position;\n" "varying vec2 texCoord;\n" "void main() {\n" - " texCoord = (texMatrix * position).xy;\n" - " gl_Position = vec4(matrix * position, 1.0);\n" + " vec3 pos = vec3(position, 1.0);\n" + " texCoord = (texMatrix * pos).xy;\n" + " gl_Position = vec4(matrix * pos, 1.0);\n" "}\n"; static const char* fragmentShaderSource = "#ifdef GL_ES\n" @@ -127,7 +128,7 @@ void BicubicShader::use(const AffineTransform& transform, const AffineTransform& m_context->uniform1i(m_imageLocation, 0); m_context->uniform1f(m_alphaLocation, alpha); - m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0); + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context->enableVertexAttribArray(m_positionLocation); } diff --git a/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp b/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp index f0b6bd9..b11d966 100644 --- a/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/ConvolutionShader.cpp @@ -58,13 +58,14 @@ PassOwnPtr<ConvolutionShader> ConvolutionShader::create(GraphicsContext3D* conte "uniform mat3 matrix;\n" "uniform mat3 texMatrix;\n" "uniform vec2 imageIncrement;\n" - "attribute vec3 position;\n" + "attribute vec2 position;\n" "varying vec2 imageCoord;\n" "void main() {\n" + " vec3 pos = vec3(position, 1.0);\n" " // Offset image coords by half of kernel width, in image texels\n" - " gl_Position = vec4(matrix * position, 1.0);\n" + " gl_Position = vec4(matrix * pos, 1.0);\n" " float scale = (float(KERNEL_WIDTH) - 1.0) / 2.0;\n" - " imageCoord = (texMatrix * position).xy - vec2(scale, scale) * imageIncrement;\n" + " imageCoord = (texMatrix * pos).xy - vec2(scale, scale) * imageIncrement;\n" "}\n"; char vertexShaderSource[1024]; snprintf(vertexShaderSource, sizeof(vertexShaderSource), vertexShaderRaw, kernelWidth); @@ -115,7 +116,7 @@ void ConvolutionShader::use(const AffineTransform& transform, const AffineTransf kernelWidth = m_kernelWidth; m_context->uniform1fv(m_kernelLocation, const_cast<float*>(kernel), kernelWidth); - m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0); + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context->enableVertexAttribArray(m_positionLocation); } diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp index 2a83fcf..8e293f7 100644 --- a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp +++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.cpp @@ -144,112 +144,128 @@ void DrawingBuffer::resizeDepthStencil(int sampleCount) m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); } -void DrawingBuffer::reset(const IntSize& newSize) +void DrawingBuffer::clearFramebuffer() { - m_size = newSize; + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); + const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes(); + float clearDepth = 0; + int clearStencil = 0; + unsigned char depthMask = false; + unsigned int stencilMask = 0xffffffff; + unsigned char isScissorEnabled = false; + unsigned long clearMask = GraphicsContext3D::COLOR_BUFFER_BIT; + if (attributes.depth) { + m_context->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &clearDepth); + m_context->clearDepth(1); + m_context->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask); + m_context->depthMask(true); + clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; + } + if (attributes.stencil) { + m_context->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &clearStencil); + m_context->clearStencil(0); + m_context->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask)); + m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xffffffff); + clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; + } + isScissorEnabled = m_context->isEnabled(GraphicsContext3D::SCISSOR_TEST); + m_context->disable(GraphicsContext3D::SCISSOR_TEST); + + float clearColor[4]; + m_context->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, clearColor); + m_context->clearColor(0, 0, 0, 0); + m_context->clear(clearMask); + m_context->clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + + if (attributes.depth) { + m_context->clearDepth(clearDepth); + m_context->depthMask(depthMask); + } + if (attributes.stencil) { + m_context->clearStencil(clearStencil); + m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, stencilMask); + } + if (isScissorEnabled) + m_context->enable(GraphicsContext3D::SCISSOR_TEST); + else + m_context->disable(GraphicsContext3D::SCISSOR_TEST); +} +bool DrawingBuffer::reset(const IntSize& newSize) +{ if (!m_context) - return; - + return false; + m_context->makeContextCurrent(); - - const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes(); - unsigned long internalColorFormat, colorFormat, internalRenderbufferFormat; - if (attributes.alpha) { - internalColorFormat = GraphicsContext3D::RGBA; - colorFormat = GraphicsContext3D::RGBA; - internalRenderbufferFormat = Extensions3D::RGBA8_OES; - } else { - internalColorFormat = GraphicsContext3D::RGB; - colorFormat = GraphicsContext3D::RGB; - internalRenderbufferFormat = Extensions3D::RGB8_OES; - } + int maxTextureSize = 0; + m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize); + if (newSize.height() > maxTextureSize || newSize.width() > maxTextureSize) { + clear(); + return false; + } - // resize multisample FBO - if (multisample()) { - int maxSampleCount = 0; - - m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); - int sampleCount = std::min(8, maxSampleCount); + const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes(); - m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); + if (newSize != m_size) { + m_size = newSize; - m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); - m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalRenderbufferFormat, m_size.width(), m_size.height()); - m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); - resizeDepthStencil(sampleCount); - if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { - // Cleanup - clear(); - return; + unsigned long internalColorFormat, colorFormat, internalRenderbufferFormat; + if (attributes.alpha) { + internalColorFormat = GraphicsContext3D::RGBA; + colorFormat = GraphicsContext3D::RGBA; + internalRenderbufferFormat = Extensions3D::RGBA8_OES; + } else { + internalColorFormat = GraphicsContext3D::RGB; + colorFormat = GraphicsContext3D::RGB; + internalRenderbufferFormat = Extensions3D::RGB8_OES; } - } - // resize regular FBO - m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); - m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); - m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE); - m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); - m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); - if (!multisample()) - resizeDepthStencil(0); - if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { - // Cleanup - clear(); - return; - } + // resize multisample FBO + if (multisample()) { + int maxSampleCount = 0; + + m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); + int sampleCount = std::min(8, maxSampleCount); - if (multisample()) - m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); - if (!m_context->getExtensions()->supports("GL_CHROMIUM_resource_safe")) { - // Initialize renderbuffers (depth/stencil). - float clearDepth = 0; - int clearStencil = 0; - unsigned char depthMask = true; - unsigned int stencilMask = 0xffffffff; - unsigned char isScissorEnabled = false; - unsigned long clearMask = 0; - if (attributes.depth) { - m_context->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &clearDepth); - m_context->clearDepth(1); - m_context->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask); - m_context->depthMask(true); - clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; - } - if (attributes.stencil) { - m_context->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &clearStencil); - m_context->clearStencil(0); - m_context->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask)); - m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xffffffff); - clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; + m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); + m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalRenderbufferFormat, m_size.width(), m_size.height()); + m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer); + resizeDepthStencil(sampleCount); + if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { + // Cleanup + clear(); + return false; + } } - if (clearMask) { - isScissorEnabled = m_context->isEnabled(GraphicsContext3D::SCISSOR_TEST); - m_context->disable(GraphicsContext3D::SCISSOR_TEST); - m_context->clear(clearMask); + // resize regular FBO + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); - if (attributes.depth) { - m_context->clearDepth(clearDepth); - m_context->depthMask(depthMask); - } - if (attributes.stencil) { - m_context->clearStencil(clearStencil); - m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, stencilMask); - } - if (isScissorEnabled) - m_context->enable(GraphicsContext3D::SCISSOR_TEST); - else - m_context->disable(GraphicsContext3D::SCISSOR_TEST); + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); + + m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE); + + m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); + + if (!multisample()) + resizeDepthStencil(0); + if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { + // Cleanup + clear(); + return false; } } - m_context->flush(); - + clearFramebuffer(); + didReset(); + + return true; } void DrawingBuffer::commit(long x, long y, long width, long height) diff --git a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h index 606484e..caf3aa5 100644 --- a/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h +++ b/Source/WebCore/platform/graphics/gpu/DrawingBuffer.h @@ -44,6 +44,7 @@ #if ENABLE(SKIA_GPU) class GrContext; +struct GrPlatformSurfaceDesc; #endif namespace WebCore { @@ -60,7 +61,10 @@ public: ~DrawingBuffer(); - void reset(const IntSize&); + void clearFramebuffer(); + + // Returns true if the buffer was successfully resized. + bool reset(const IntSize&); void bind(); IntSize size() const { return m_size; } Platform3DObject colorBuffer() const { return m_colorBuffer; } @@ -101,6 +105,7 @@ public: #if ENABLE(SKIA_GPU) void setGrContext(GrContext* ctx); + void getGrPlatformSurfaceDesc(GrPlatformSurfaceDesc*); #endif PassRefPtr<GraphicsContext3D> graphicsContext3D() const { return m_context; } diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp index 5b155a5..b228cbf 100644 --- a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp @@ -562,6 +562,108 @@ int numXRayCrossingsForCubic(const XRay& xRay, const FloatPoint cubic[4], bool& return numCrossings; } +/* + * Based on C code from the article + * "Testing the Convexity of a Polygon" + * by Peter Schorn and Frederick Fisher, + * (schorn@inf.ethz.ch, fred@kpc.com) + * in "Graphics Gems IV", Academic Press, 1994 + */ + +static inline int convexCompare(const FloatSize& delta) +{ + return (delta.width() > 0) ? -1 : /* x coord diff, second pt > first pt */ + (delta.width() < 0) ? 1 : /* x coord diff, second pt < first pt */ + (delta.height() > 0) ? -1 : /* x coord same, second pt > first pt */ + (delta.height() < 0) ? 1 : /* x coord same, second pt > first pt */ + 0; /* second pt equals first point */ +} + +static inline float convexCross(const FloatSize& p, const FloatSize& q) +{ + return p.width() * q.height() - p.height() * q.width(); +} + +static inline bool convexCheckTriple(const FloatSize& dcur, const FloatSize& dprev, int* curDir, int* dirChanges, int* angleSign) +{ + int thisDir = convexCompare(dcur); + if (thisDir == -*curDir) + ++*dirChanges; + *curDir = thisDir; + float cross = convexCross(dprev, dcur); + if (cross > 0) { + if (*angleSign == -1) + return false; + *angleSign = 1; + } else if (cross < 0) { + if (*angleSign == 1) + return false; + *angleSign = -1; + } + return true; +} + +bool isConvex(const FloatPoint* vertices, int nVertices) +{ + int dirChanges = 0, angleSign = 0; + FloatPoint second, third; + FloatSize dprev, dcur; + + /* Get different point, return if less than 3 diff points. */ + if (nVertices < 3) + return false; + int i = 1; + while (true) { + second = vertices[i++]; + dprev = second - vertices[0]; + if (dprev.width() || dprev.height()) + break; + /* Check if out of points. Check here to avoid slowing down cases + * without repeated points. + */ + if (i >= nVertices) + return false; + } + FloatPoint saveSecond = second; + int curDir = convexCompare(dprev); /* Find initial direction */ + while (i < nVertices) { + /* Get different point, break if no more points */ + third = vertices[i++]; + dcur = third - second; + if (!dcur.width() && !dcur.height()) + continue; + + /* Check current three points */ + if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) + return false; + second = third; /* Remember ptr to current point. */ + dprev = dcur; /* Remember current delta. */ + } + + /* Must check for direction changes from last vertex back to first */ + third = vertices[0]; /* Prepare for 'ConvexCheckTriple' */ + dcur = third - second; + if (convexCompare(dcur)) { + if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) + return false; + second = third; /* Remember ptr to current point. */ + dprev = dcur; /* Remember current delta. */ + } + + /* and check for direction changes back to second vertex */ + dcur = saveSecond - second; + if (!convexCheckTriple(dcur, dprev, &curDir, &dirChanges, &angleSign)) + return false; + + /* Decide on polygon type given accumulated status */ + if (dirChanges > 2) + return false; + + if (angleSign > 0 || angleSign < 0) + return true; + return false; +} + } // namespace LoopBlinnMathUtils } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h index b9d19c5..361d901 100644 --- a/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h +++ b/Source/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h @@ -101,6 +101,9 @@ bool xRayCrossesLine(const XRay& xRay, const FloatPoint lineEndpoints[2], bool& ambiguous); + +bool isConvex(const FloatPoint* vertices, int nVertices); + } // namespace LoopBlinnMathUtils } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/gpu/Shader.cpp b/Source/WebCore/platform/graphics/gpu/Shader.cpp index 1b9bfd5..13c5ebf 100644 --- a/Source/WebCore/platform/graphics/gpu/Shader.cpp +++ b/Source/WebCore/platform/graphics/gpu/Shader.cpp @@ -140,7 +140,7 @@ String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fi case TwoDimensional: builder.append( "uniform mat3 matrix;\n" - "attribute vec3 position;\n"); + "attribute vec2 position;\n"); break; case LoopBlinnInterior: builder.append( @@ -167,7 +167,7 @@ String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fi if (vertexType == TwoDimensional) { builder.append( - "gl_Position = vec4(matrix * position, 1.0);\n"); + "gl_Position = vec4(matrix * vec3(position, 1.0), 1.0);\n"); } else { builder.append( "gl_Position = worldViewProjection * vec4(position, 0.0, 1.0);\n"); @@ -179,7 +179,7 @@ String Shader::generateVertex(Shader::VertexType vertexType, Shader::FillType fi if (fillType == TextureFill) { builder.append( - "texCoord = texMatrix * position;\n"); + "texCoord = texMatrix * vec3(position, 1.0);\n"); } builder.append( diff --git a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp index 662d6a8..b7b94c4 100644 --- a/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp +++ b/Source/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp @@ -346,10 +346,10 @@ void SharedGraphicsContext3D::enableStencil(bool enable) void SharedGraphicsContext3D::useQuadVertices() { if (!m_quadVertices) { - float vertices[] = { 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 1.0f, - 0.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f }; + float vertices[] = { 0.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f }; m_quadVertices = m_context->createBuffer(); m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices); m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(vertices), vertices, GraphicsContext3D::STATIC_DRAW); diff --git a/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp b/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp index 78381f0..0a6e084 100644 --- a/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/SolidFillShader.cpp @@ -69,7 +69,7 @@ void SolidFillShader::use(const AffineTransform& transform, const Color& color) affineTo3x3(transform, matrix); m_context->uniformMatrix3fv(m_matrixLocation, false /*transpose*/, matrix, 1 /*count*/); - m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0); + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context->enableVertexAttribArray(m_positionLocation); } diff --git a/Source/WebCore/platform/graphics/gpu/TexShader.cpp b/Source/WebCore/platform/graphics/gpu/TexShader.cpp index 9eb5c16..ac141a5 100644 --- a/Source/WebCore/platform/graphics/gpu/TexShader.cpp +++ b/Source/WebCore/platform/graphics/gpu/TexShader.cpp @@ -72,7 +72,7 @@ void TexShader::use(const AffineTransform& transform, const AffineTransform& tex m_context->uniform1i(m_samplerLocation, sampler); m_context->uniform1f(m_alphaLocation, alpha); - m_context->vertexAttribPointer(m_positionLocation, 3, GraphicsContext3D::FLOAT, false, 0, 0); + m_context->vertexAttribPointer(m_positionLocation, 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context->enableVertexAttribArray(m_positionLocation); diff --git a/Source/WebCore/platform/graphics/gpu/TilingData.cpp b/Source/WebCore/platform/graphics/gpu/TilingData.cpp index 1370543..2415ee4 100644 --- a/Source/WebCore/platform/graphics/gpu/TilingData.cpp +++ b/Source/WebCore/platform/graphics/gpu/TilingData.cpp @@ -44,6 +44,9 @@ namespace WebCore { static int computeNumTiles(int maxTextureSize, int totalSize, int borderTexels) { + if (maxTextureSize - 2 * borderTexels <= 0) + return totalSize > 0 && maxTextureSize >= totalSize ? 1 : 0; + int numTiles = max(1, 1 + (totalSize - 1 - 2 * borderTexels) / (maxTextureSize - 2 * borderTexels)); return totalSize > 0 ? numTiles : 0; } diff --git a/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h index 6e53cfc..332908d 100644 --- a/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h +++ b/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h @@ -27,7 +27,7 @@ #include <gst/video/video.h> #include <wtf/PassRefPtr.h> -#if PLATFORM(CAIRO) +#if USE(CAIRO) #include <cairo.h> #endif @@ -48,7 +48,7 @@ class ImageGStreamer : public RefCounted<ImageGStreamer> { private: RefPtr<BitmapImage> m_image; -#if PLATFORM(CAIRO) +#if USE(CAIRO) ImageGStreamer(GstBuffer*&, IntSize, cairo_format_t&); #endif diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 2fb4cef..56c2f30 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -81,194 +81,74 @@ static int greatestCommonDivisor(int a, int b) return ABS(a); } -gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data) +static gboolean mediaPlayerPrivateMessageCallback(GstBus*, GstMessage* message, MediaPlayerPrivateGStreamer* player) { - GOwnPtr<GError> err; - GOwnPtr<gchar> debug; - MediaPlayer::NetworkState error; - MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); - bool issueError = true; - bool attemptNextLocation = false; - GstElement* pipeline = mp->pipeline(); - - if (message->structure) { - const gchar* messageTypeName = gst_structure_get_name(message->structure); - - // Redirect messages are sent from elements, like qtdemux, to - // notify of the new location(s) of the media. - if (!g_strcmp0(messageTypeName, "redirect")) { - mp->mediaLocationChanged(message); - return true; - } - } - - switch (GST_MESSAGE_TYPE(message)) { - case GST_MESSAGE_ERROR: - if (mp && mp->pipelineReset()) - break; - gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); - LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); - - error = MediaPlayer::Empty; - if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND - || err->code == GST_STREAM_ERROR_WRONG_TYPE - || err->code == GST_STREAM_ERROR_FAILED - || err->code == GST_CORE_ERROR_MISSING_PLUGIN - || err->code == GST_RESOURCE_ERROR_NOT_FOUND) - error = MediaPlayer::FormatError; - else if (err->domain == GST_STREAM_ERROR) { - // Let the mediaPlayerClient handle the stream error, in - // this case the HTMLMediaElement will emit a stalled - // event. - if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) { - LOG_VERBOSE(Media, "Decode error, let the Media element emit a stalled event."); - break; - } - error = MediaPlayer::DecodeError; - attemptNextLocation = true; - } else if (err->domain == GST_RESOURCE_ERROR) - error = MediaPlayer::NetworkError; - - if (mp) { - if (attemptNextLocation) - issueError = !mp->loadNextLocation(); - if (issueError) - mp->loadingFailed(error); - } - break; - case GST_MESSAGE_EOS: - LOG_VERBOSE(Media, "End of Stream"); - mp->didEnd(); - break; - case GST_MESSAGE_STATE_CHANGED: - // Ignore state changes if load is delayed (preload=none). The - // player state will be updated once commitLoad() is called. - if (mp->loadDelayed()) { - LOG_VERBOSE(Media, "Media load has been delayed. Ignoring state changes for now"); - break; - } - - // Ignore state changes from internal elements. They are - // forwarded to playbin2 anyway. - if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(pipeline)) - mp->updateStates(); - break; - case GST_MESSAGE_BUFFERING: - mp->processBufferingStats(message); - break; - case GST_MESSAGE_DURATION: - LOG_VERBOSE(Media, "Duration changed"); - mp->durationChanged(); - break; - default: - LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s", - GST_MESSAGE_TYPE_NAME(message)); - break; - } - return true; + return player->handleMessage(message); } -void mediaPlayerPrivateSourceChangedCallback(GObject *object, GParamSpec *pspec, gpointer data) +static void mediaPlayerPrivateSourceChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player) { - MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); - GOwnPtr<GstElement> element; - - g_object_get(mp->m_playBin, "source", &element.outPtr(), NULL); - gst_object_replace((GstObject**) &mp->m_source, (GstObject*) element.get()); - - if (WEBKIT_IS_WEB_SRC(element.get())) { - Frame* frame = mp->m_player->frameView() ? mp->m_player->frameView()->frame() : 0; - - if (frame) - webKitWebSrcSetFrame(WEBKIT_WEB_SRC(element.get()), frame); - } + player->sourceChanged(); } -void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec, gpointer data) +static void mediaPlayerPrivateVolumeChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player) { // This is called when playbin receives the notify::volume signal. - MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); - mp->volumeChanged(); + player->volumeChanged(); } -gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +static gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) { // This is the callback of the timeout source created in ::volumeChanged. player->notifyPlayerOfVolumeChange(); return FALSE; } -void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, gpointer data) +static void mediaPlayerPrivateMuteChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player) { // This is called when playbin receives the notify::mute signal. - MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); - mp->muteChanged(); + player->muteChanged(); } -gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +static gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) { // This is the callback of the timeout source created in ::muteChanged. player->notifyPlayerOfMute(); return FALSE; } -void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player) +static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player) { - player->videoTagsChanged(streamId); + player->videoChanged(); } -void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player) +static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player) { - player->audioTagsChanged(streamId); + player->videoChanged(); } -gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player) { - // This is the callback of the timeout source created in ::audioTagsChanged. - player->notifyPlayerOfAudioTags(); - return FALSE; + player->audioChanged(); } -gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) +static gboolean mediaPlayerPrivateAudioChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) { - // This is the callback of the timeout source created in ::videoTagsChanged. - player->notifyPlayerOfVideoTags(); + // This is the callback of the timeout source created in ::audioChanged. + player->notifyPlayerOfAudio(); return FALSE; } -static float playbackPosition(GstElement* playbin) +static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player) { - - float ret = 0.0f; - - GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); - if (!gst_element_query(playbin, query)) { - LOG_VERBOSE(Media, "Position query failed..."); - gst_query_unref(query); - return ret; - } - - gint64 position; - gst_query_parse_position(query, 0, &position); - - // Position is available only if the pipeline is not in GST_STATE_NULL or - // GST_STATE_READY state. - if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE)) - ret = static_cast<float>(position) / static_cast<float>(GST_SECOND); - - LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); - - gst_query_unref(query); - - return ret; + // This is the callback of the timeout source created in ::videoChanged. + player->notifyPlayerOfVideo(); + return FALSE; } - -void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate) +static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate) { - g_return_if_fail(GST_IS_BUFFER(buffer)); - gst_buffer_replace(&playerPrivate->m_buffer, buffer); - playerPrivate->repaint(); + playerPrivate->triggerRepaint(buffer); } MediaPlayerPrivateInterface* MediaPlayerPrivateGStreamer::create(MediaPlayer* player) @@ -347,8 +227,9 @@ MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player) , m_muteTimerHandler(0) , m_hasVideo(false) , m_hasAudio(false) - , m_audioTagsTimerHandler(0) - , m_videoTagsTimerHandler(0) + , m_audioTimerHandler(0) + , m_videoTimerHandler(0) + , m_webkitAudioSink(0) { if (doGstInit()) createGSTPlayBin(); @@ -392,11 +273,11 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer() if (m_volumeTimerHandler) g_source_remove(m_volumeTimerHandler); - if (m_videoTagsTimerHandler) - g_source_remove(m_videoTagsTimerHandler); + if (m_videoTimerHandler) + g_source_remove(m_videoTimerHandler); - if (m_audioTagsTimerHandler) - g_source_remove(m_audioTagsTimerHandler); + if (m_audioTimerHandler) + g_source_remove(m_audioTimerHandler); } void MediaPlayerPrivateGStreamer::load(const String& url) @@ -425,6 +306,32 @@ void MediaPlayerPrivateGStreamer::commitLoad() updateStates(); } +float MediaPlayerPrivateGStreamer::playbackPosition() const +{ + float ret = 0.0f; + + GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); + if (!gst_element_query(m_playBin, query)) { + LOG_VERBOSE(Media, "Position query failed..."); + gst_query_unref(query); + return ret; + } + + gint64 position; + gst_query_parse_position(query, 0, &position); + + // Position is available only if the pipeline is not in GST_STATE_NULL or + // GST_STATE_READY state. + if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE)) + ret = static_cast<float>(position) / static_cast<float>(GST_SECOND); + + LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); + + gst_query_unref(query); + + return ret; +} + bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState) { ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED); @@ -504,14 +411,14 @@ float MediaPlayerPrivateGStreamer::currentTime() const if (m_seeking) return m_seekTime; - return playbackPosition(m_playBin); + return playbackPosition(); } void MediaPlayerPrivateGStreamer::seek(float time) { // Avoid useless seeking. - if (time == playbackPosition(m_playBin)) + if (time == playbackPosition()) return; if (!m_playBin) @@ -582,6 +489,7 @@ IntSize MediaPlayerPrivateGStreamer::naturalSize() const || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, &pixelAspectRatioDenominator)) { gst_object_unref(GST_OBJECT(pad)); + // The video-sink has likely not yet negotiated its caps. return IntSize(); } @@ -618,39 +526,40 @@ IntSize MediaPlayerPrivateGStreamer::naturalSize() const return IntSize(static_cast<int>(width), static_cast<int>(height)); } -void MediaPlayerPrivateGStreamer::videoTagsChanged(gint streamId) +void MediaPlayerPrivateGStreamer::videoChanged() { - if (m_videoTagsTimerHandler) - g_source_remove(m_videoTagsTimerHandler); - m_videoTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoTagsChangeTimeoutCallback), this); + if (m_videoTimerHandler) + g_source_remove(m_videoTimerHandler); + m_videoTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoChangeTimeoutCallback), this); } -void MediaPlayerPrivateGStreamer::notifyPlayerOfVideoTags() +void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo() { - m_videoTagsTimerHandler = 0; + m_videoTimerHandler = 0; - gint currentVideo = -1; + gint videoTracks = 0; if (m_playBin) - g_object_get(m_playBin, "current-video", ¤tVideo, NULL); - m_hasVideo = currentVideo > -1; + g_object_get(m_playBin, "n-video", &videoTracks, NULL); + + m_hasVideo = videoTracks > 0; m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player); } -void MediaPlayerPrivateGStreamer::audioTagsChanged(gint streamId) +void MediaPlayerPrivateGStreamer::audioChanged() { - if (m_audioTagsTimerHandler) - g_source_remove(m_audioTagsTimerHandler); - m_audioTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioTagsChangeTimeoutCallback), this); + if (m_audioTimerHandler) + g_source_remove(m_audioTimerHandler); + m_audioTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioChangeTimeoutCallback), this); } -void MediaPlayerPrivateGStreamer::notifyPlayerOfAudioTags() +void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio() { - m_audioTagsTimerHandler = 0; + m_audioTimerHandler = 0; - gint currentAudio = -1; + gint audioTracks = 0; if (m_playBin) - g_object_get(m_playBin, "current-audio", ¤tAudio, NULL); - m_hasAudio = currentAudio > -1; + g_object_get(m_playBin, "n-audio", &audioTracks, NULL); + m_hasAudio = audioTracks > 0; m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player); } @@ -704,13 +613,19 @@ void MediaPlayerPrivateGStreamer::setRate(float rate) m_playbackRate = rate; m_changingRate = true; - float currentPosition = static_cast<float>(playbackPosition(m_playBin) * GST_SECOND); + + if (!rate) { + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + return; + } + + float currentPosition = static_cast<float>(playbackPosition() * GST_SECOND); GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH); gint64 start, end; bool mute = false; LOG_VERBOSE(Media, "Set Rate to %f", rate); - if (rate >= 0) { + if (rate > 0) { // Mute the sound if the playback rate is too extreme. // TODO: in other cases we should perform pitch adjustments. mute = (bool) (rate < 0.8 || rate > 2); @@ -788,6 +703,89 @@ PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const return timeRanges.release(); } +gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message) +{ + GOwnPtr<GError> err; + GOwnPtr<gchar> debug; + MediaPlayer::NetworkState error; + bool issueError = true; + bool attemptNextLocation = false; + + if (message->structure) { + const gchar* messageTypeName = gst_structure_get_name(message->structure); + + // Redirect messages are sent from elements, like qtdemux, to + // notify of the new location(s) of the media. + if (!g_strcmp0(messageTypeName, "redirect")) { + mediaLocationChanged(message); + return TRUE; + } + } + + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: + if (m_resetPipeline) + break; + gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); + LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); + + error = MediaPlayer::Empty; + if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND + || err->code == GST_STREAM_ERROR_WRONG_TYPE + || err->code == GST_STREAM_ERROR_FAILED + || err->code == GST_CORE_ERROR_MISSING_PLUGIN + || err->code == GST_RESOURCE_ERROR_NOT_FOUND) + error = MediaPlayer::FormatError; + else if (err->domain == GST_STREAM_ERROR) { + // Let the mediaPlayerClient handle the stream error, in + // this case the HTMLMediaElement will emit a stalled + // event. + if (err->code == GST_STREAM_ERROR_TYPE_NOT_FOUND) { + LOG_VERBOSE(Media, "Decode error, let the Media element emit a stalled event."); + break; + } + error = MediaPlayer::DecodeError; + attemptNextLocation = true; + } else if (err->domain == GST_RESOURCE_ERROR) + error = MediaPlayer::NetworkError; + + if (attemptNextLocation) + issueError = !loadNextLocation(); + if (issueError) + loadingFailed(error); + break; + case GST_MESSAGE_EOS: + LOG_VERBOSE(Media, "End of Stream"); + didEnd(); + break; + case GST_MESSAGE_STATE_CHANGED: + // Ignore state changes if load is delayed (preload=none). The + // player state will be updated once commitLoad() is called. + if (m_delayingLoad) { + LOG_VERBOSE(Media, "Media load has been delayed. Ignoring state changes for now"); + break; + } + + // Ignore state changes from internal elements. They are + // forwarded to playbin2 anyway. + if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin)) + updateStates(); + break; + case GST_MESSAGE_BUFFERING: + processBufferingStats(message); + break; + case GST_MESSAGE_DURATION: + LOG_VERBOSE(Media, "Duration changed"); + durationChanged(); + break; + default: + LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s", + GST_MESSAGE_TYPE_NAME(message)); + break; + } + return TRUE; +} + void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message) { // This is the immediate buffering that needs to happen so we have @@ -952,6 +950,75 @@ unsigned MediaPlayerPrivateGStreamer::totalBytes() const return static_cast<unsigned>(length); } +unsigned MediaPlayerPrivateGStreamer::decodedFrameCount() const +{ + guint64 decodedFrames = 0; + if (m_fpsSink) + g_object_get(m_fpsSink, "frames-rendered", &decodedFrames, NULL); + return static_cast<unsigned>(decodedFrames); +} + +unsigned MediaPlayerPrivateGStreamer::droppedFrameCount() const +{ + guint64 framesDropped = 0; + if (m_fpsSink) + g_object_get(m_fpsSink, "frames-dropped", &framesDropped, NULL); + return static_cast<unsigned>(framesDropped); +} + +unsigned MediaPlayerPrivateGStreamer::audioDecodedByteCount() const +{ + GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES); + gint64 position = 0; + + if (m_webkitAudioSink && gst_element_query(m_webkitAudioSink, query)) + gst_query_parse_position(query, 0, &position); + + gst_query_unref(query); + return static_cast<unsigned>(position); +} + +unsigned MediaPlayerPrivateGStreamer::videoDecodedByteCount() const +{ + GstQuery* query = gst_query_new_position(GST_FORMAT_BYTES); + gint64 position = 0; + + if (gst_element_query(m_webkitVideoSink, query)) + gst_query_parse_position(query, 0, &position); + + gst_query_unref(query); + return static_cast<unsigned>(position); +} + +void MediaPlayerPrivateGStreamer::updateAudioSink() +{ + if (!m_playBin) + return; + + GOwnPtr<GstElement> element; + + g_object_get(m_playBin, "audio-sink", &element.outPtr(), NULL); + gst_object_replace(reinterpret_cast<GstObject**>(&m_webkitAudioSink), + reinterpret_cast<GstObject*>(element.get())); +} + + +void MediaPlayerPrivateGStreamer::sourceChanged() +{ + GOwnPtr<GstElement> element; + + g_object_get(m_playBin, "source", &element.outPtr(), NULL); + gst_object_replace(reinterpret_cast<GstObject**>(&m_source), + reinterpret_cast<GstObject*>(element.get())); + + if (WEBKIT_IS_WEB_SRC(element.get())) { + Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; + + if (frame) + webKitWebSrcSetFrame(WEBKIT_WEB_SRC(element.get()), frame); + } +} + void MediaPlayerPrivateGStreamer::cancelLoad() { if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) @@ -1011,6 +1078,8 @@ void MediaPlayerPrivateGStreamer::updateStates() // information from GStreamer, while we sync states where // needed. if (state == GST_STATE_PAUSED) { + if (!m_webkitAudioSink) + updateAudioSink(); if (m_buffering && m_bufferingPercentage == 100) { m_buffering = false; m_bufferingPercentage = 0; @@ -1347,8 +1416,11 @@ void MediaPlayerPrivateGStreamer::setVisible(bool visible) { } -void MediaPlayerPrivateGStreamer::repaint() + +void MediaPlayerPrivateGStreamer::triggerRepaint(GstBuffer* buffer) { + g_return_if_fail(GST_IS_BUFFER(buffer)); + gst_buffer_replace(&m_buffer, buffer); m_player->repaint(); } @@ -1359,6 +1431,7 @@ void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect& if (!m_player->visible()) return; + if (!m_buffer) return; @@ -1477,6 +1550,9 @@ static HashSet<String> mimeTypeCache() || (g_str_equal(mimetype[0], "application") && handledApplicationSubtypes.contains(String(mimetype[1])))) cache.add(String(name)); + else if (g_str_equal(name, "application/x-hls")) + cache.add(String("application/vnd.apple.mpegurl")); + g_strfreev(mimetype); } @@ -1584,8 +1660,8 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this); g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this); g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this); - g_signal_connect(m_playBin, "video-tags-changed", G_CALLBACK(mediaPlayerPrivateVideoTagsChangedCallback), this); - g_signal_connect(m_playBin, "audio-tags-changed", G_CALLBACK(mediaPlayerPrivateAudioTagsChangedCallback), this); + g_signal_connect(m_playBin, "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this); + g_signal_connect(m_playBin, "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this); m_webkitVideoSink = webkit_video_sink_new(); @@ -1613,39 +1689,44 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() gst_object_unref(GST_OBJECT(srcPad)); gst_object_unref(GST_OBJECT(sinkPad)); - WTFLogChannel* channel = getChannelFromName("Media"); - if (channel->state == WTFLogChannelOn) { - m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink"); - if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) { - g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL); - gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink); -#if GST_CHECK_VERSION(0, 10, 30) - // Faster elements linking, if possible. - gst_element_link_pads_full(queue, "src", m_fpsSink, "sink", GST_PAD_LINK_CHECK_NOTHING); -#else - gst_element_link(queue, m_fpsSink); -#endif - } else { + GstElement* actualVideoSink = 0; + m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink"); + if (m_fpsSink) { + // The verbose property has been added in -bad 0.10.22. Making + // this whole code depend on it because we don't want + // fpsdiplaysink to spit data on stdout. + GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(m_fpsSink)->elementfactory); + if (gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 22)) { + g_object_set(m_fpsSink, "silent", TRUE , NULL); + + // Turn off text overlay unless logging is enabled. + WTFLogChannel* channel = getChannelFromName("Media"); + if (channel->state != WTFLogChannelOn) + g_object_set(m_fpsSink, "text-overlay", FALSE , NULL); + + if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_fpsSink), "video-sink")) { + g_object_set(m_fpsSink, "video-sink", m_webkitVideoSink, NULL); + gst_bin_add(GST_BIN(m_videoSinkBin), m_fpsSink); + actualVideoSink = m_fpsSink; + } else + m_fpsSink = 0; + } else m_fpsSink = 0; - gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink); -#if GST_CHECK_VERSION(0, 10, 30) - // Faster elements linking, if possible. - gst_element_link_pads_full(queue, "src", m_webkitVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); -#else - gst_element_link(queue, m_webkitVideoSink); -#endif - LOG_VERBOSE(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18"); - } - } else { + } + + if (!m_fpsSink) { gst_bin_add(GST_BIN(m_videoSinkBin), m_webkitVideoSink); + actualVideoSink = m_webkitVideoSink; + } + + ASSERT(actualVideoSink); #if GST_CHECK_VERSION(0, 10, 30) // Faster elements linking, if possible. gst_element_link_pads_full(queue, "src", identity, "sink", GST_PAD_LINK_CHECK_NOTHING); - gst_element_link_pads_full(identity, "src", m_webkitVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); + gst_element_link_pads_full(identity, "src", actualVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING); #else - gst_element_link_many(queue, identity, m_webkitVideoSink, NULL); + gst_element_link_many(queue, identity, actualVideoSink, NULL); #endif - } // Add a ghostpad to the bin so it can proxy to tee. GstPad* pad = gst_element_get_static_pad(videoTee, "sink"); @@ -1654,6 +1735,14 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() // Set the bin as video sink of playbin. g_object_set(m_playBin, "video-sink", m_videoSinkBin, NULL); + + + pad = gst_element_get_static_pad(m_webkitVideoSink, "sink"); + if (pad) { + g_signal_connect(pad, "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this); + gst_object_unref(GST_OBJECT(pad)); + } + } } diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h index 8003887..024fad0 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h @@ -35,7 +35,6 @@ typedef struct _WebKitVideoSink WebKitVideoSink; typedef struct _GstBuffer GstBuffer; typedef struct _GstMessage GstMessage; typedef struct _GstElement GstElement; -typedef struct _GstBus GstBus; namespace WebCore { @@ -45,25 +44,11 @@ class IntRect; class GStreamerGWorld; class MediaPlayerPrivateGStreamer; -gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); -void mediaPlayerPrivateVolumeChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); -void mediaPlayerPrivateMuteChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); -void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); -void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*); -void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*); -gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player); -gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player); - -gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer*); -gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer*); - class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { - friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); - friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer* buffer, MediaPlayerPrivateGStreamer* playerPrivate); - friend void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); public: static void registerMediaEngine(MediaEngineRegistrar); + gboolean handleMessage(GstMessage*); IntSize naturalSize() const; bool hasVideo() const { return m_hasVideo; } @@ -72,7 +57,6 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void load(const String &url); void commitLoad(); void cancelLoad(); - bool loadNextLocation(); void prepareToPlay(); void play(); @@ -96,7 +80,6 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void muteChanged(); void notifyPlayerOfMute(); - bool loadDelayed() const { return m_delayingLoad; } void setPreload(MediaPlayer::Preload); void fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*); @@ -111,7 +94,6 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void setVisible(bool); void setSize(const IntSize&); - void mediaLocationChanged(GstMessage*); void loadStateChanged(); void sizeChanged(); void timeChanged(); @@ -119,6 +101,7 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void durationChanged(); void loadingFailed(MediaPlayer::NetworkState); + void triggerRepaint(GstBuffer*); void repaint(); void paint(GraphicsContext*, const IntRect&); @@ -127,13 +110,17 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { bool supportsFullscreen() const; PlatformMedia platformMedia() const; - GstElement* pipeline() const { return m_playBin; } - bool pipelineReset() const { return m_resetPipeline; } + void videoChanged(); + void audioChanged(); + void notifyPlayerOfVideo(); + void notifyPlayerOfAudio(); + + void sourceChanged(); - void videoTagsChanged(gint); - void audioTagsChanged(gint); - void notifyPlayerOfVideoTags(); - void notifyPlayerOfAudioTags(); + unsigned decodedFrameCount() const; + unsigned droppedFrameCount() const; + unsigned audioDecodedByteCount() const; + unsigned videoDecodedByteCount() const; private: MediaPlayerPrivateGStreamer(MediaPlayer*); @@ -145,6 +132,10 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); static bool isAvailable(); + void updateAudioSink(); + + float playbackPosition() const; + void cacheDuration(); void updateStates(); float maxTimeLoaded() const; @@ -152,7 +143,10 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { void createGSTPlayBin(); bool changePipelineState(GstState state); - void processBufferingStats(GstMessage* message); + bool loadNextLocation(); + void mediaLocationChanged(GstMessage*); + + void processBufferingStats(GstMessage*); private: MediaPlayer* m_player; @@ -191,8 +185,9 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { guint m_muteTimerHandler; bool m_hasVideo; bool m_hasAudio; - guint m_audioTagsTimerHandler; - guint m_videoTagsTimerHandler; + guint m_audioTimerHandler; + guint m_videoTimerHandler; + GstElement* m_webkitAudioSink; }; } diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h index 0ae4587..7b441f4 100644 --- a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h +++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowPrivate.h @@ -20,21 +20,37 @@ #ifndef PlatformVideoWindowPrivate_h #define PlatformVideoWindowPrivate_h +#include <QTimer> #include <QWidget> class QKeyEvent; namespace WebCore { +class HTMLVideoElement; + class FullScreenVideoWindow: public QWidget { Q_OBJECT public: FullScreenVideoWindow(); + void setVideoElement(HTMLVideoElement*); signals: void closed(); protected: - void keyPressEvent(QKeyEvent* ev); - bool event(QEvent* ev); + void closeEvent(QCloseEvent*); + void keyPressEvent(QKeyEvent*); + bool event(QEvent*); + +public slots: + void showFullScreen(); + +private slots: + void hideCursor(); + +private: + void showCursor(); + QTimer m_cursorTimer; + HTMLVideoElement* m_mediaElement; }; diff --git a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp index 872d055..7270785 100644 --- a/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/PlatformVideoWindowQt.cpp @@ -20,6 +20,7 @@ #include "config.h" #include "PlatformVideoWindow.h" +#include "HTMLVideoElement.h" #include "PlatformVideoWindowPrivate.h" #include <QApplication> @@ -28,29 +29,55 @@ #include <QPalette> using namespace WebCore; +static const int gHideMouseCursorDelay = 3000; + FullScreenVideoWindow::FullScreenVideoWindow() : QWidget(0, Qt::Window) + , m_mediaElement(0) { setAttribute(Qt::WA_NativeWindow); - // Setting these values ensures smooth resizing since it - // will prevent the system from clearing the background. + setWindowModality(Qt::ApplicationModal); setAttribute(Qt::WA_NoSystemBackground, true); setAttribute(Qt::WA_PaintOnScreen, true); + + m_cursorTimer.setSingleShot(true); + connect(&m_cursorTimer, SIGNAL(timeout()), this, SLOT(hideCursor())); +} + +void FullScreenVideoWindow::setVideoElement(HTMLVideoElement* element) +{ + m_mediaElement = element; +} + +void FullScreenVideoWindow::closeEvent(QCloseEvent*) +{ + m_cursorTimer.stop(); + setMouseTracking(false); + releaseMouse(); + QApplication::restoreOverrideCursor(); } void FullScreenVideoWindow::keyPressEvent(QKeyEvent* ev) { - if (ev->key() == Qt::Key_Escape) { - close(); + if (m_mediaElement && ev->key() == Qt::Key_Space) { + if (!m_mediaElement->paused()) + m_mediaElement->pause(true); + else + m_mediaElement->play(true); + } else if (ev->key() == Qt::Key_Escape) emit closed(); - } + QWidget::keyPressEvent(ev); } bool FullScreenVideoWindow::event(QEvent* ev) { switch (ev->type()) { + case QEvent::MouseMove: + showCursor(); + ev->accept(); + return true; case QEvent::MouseButtonDblClick: - close(); + emit closed(); ev->accept(); return true; default: @@ -58,6 +85,26 @@ bool FullScreenVideoWindow::event(QEvent* ev) } } +void FullScreenVideoWindow::showFullScreen() +{ + QWidget::showFullScreen(); + setMouseTracking(true); + raise(); + setFocus(); + hideCursor(); +} + +void FullScreenVideoWindow::hideCursor() +{ + QApplication::setOverrideCursor(QCursor(Qt::BlankCursor)); +} + +void FullScreenVideoWindow::showCursor() +{ + QApplication::restoreOverrideCursor(); + m_cursorTimer.start(gHideMouseCursorDelay); +} + PlatformVideoWindow::PlatformVideoWindow() { diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index 66ea9ba..e48998f 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -791,7 +791,7 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse gst_element_found_tags_for_pad(GST_ELEMENT(m_src), m_src->priv->srcpad, tags); } -void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, int length, int lengthReceived) +void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, int length, int encodedDataLength) { WebKitWebSrcPrivate* priv = m_src->priv; diff --git a/Source/WebCore/platform/graphics/gtk/DrawingBufferGtk.cpp b/Source/WebCore/platform/graphics/gtk/DrawingBufferGtk.cpp new file mode 100644 index 0000000..17fc334 --- /dev/null +++ b/Source/WebCore/platform/graphics/gtk/DrawingBufferGtk.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(WEBGL) + +#include "DrawingBuffer.h" + +#include "Extensions3D.h" + +namespace WebCore { + +DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, + const IntSize& size, + bool multisampleExtensionSupported, + bool packedDepthStencilExtensionSupported) + : m_context(context) + , m_size(-1, -1) + , m_multisampleExtensionSupported(multisampleExtensionSupported) + , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) + , m_fbo(context->createFramebuffer()) + , m_colorBuffer(0) + , m_depthStencilBuffer(0) + , m_multisampleFBO(0) + , m_multisampleColorBuffer(0) +{ + ASSERT(m_fbo); + if (!m_fbo) { + clear(); + return; + } + + // create a texture to render into + m_colorBuffer = context->createTexture(); + context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer); + context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); + context->texParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); + context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); + context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); + context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); + + // Create the FBO + m_fbo = context->createFramebuffer(); + ASSERT(m_fbo); + if (!m_fbo) { + clear(); + return; + } + + createSecondaryBuffers(); + reset(size); +} + +DrawingBuffer::~DrawingBuffer() +{ + clear(); +} + +void DrawingBuffer::didReset() +{ +} + +Platform3DObject DrawingBuffer::platformColorBuffer() const +{ + return m_colorBuffer; +} + +} + +#endif diff --git a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp index d14b052..977aa62 100644 --- a/Source/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/Source/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -35,9 +35,10 @@ #include "CairoUtilities.h" #include "ContextShadow.h" -#include "PlatformContextCairo.h" +#include "GOwnPtr.h" #include "GraphicsContext.h" #include "NotImplemented.h" +#include "PlatformContextCairo.h" #include "SimpleFontData.h" #include "TextRun.h" #include <cairo.h> @@ -84,75 +85,71 @@ IntRect getPangoRegionExtents(PangoRegionType region) #define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff) #define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff) -static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length) +static gchar* utf16ToUtf8(const UChar* aText, gint aLength, gint &length) { - gboolean need_copy = FALSE; - int i; + gboolean needCopy = FALSE; - for (i = 0; i < aLength; i++) { - if (!aText[i] || IS_LOW_SURROGATE(aText[i])) { - need_copy = TRUE; - break; - } - else if (IS_HIGH_SURROGATE(aText[i])) { - if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) - i++; - else { - need_copy = TRUE; - break; - } + for (int i = 0; i < aLength; i++) { + if (!aText[i] || IS_LOW_SURROGATE(aText[i])) { + needCopy = TRUE; + break; + } + + if (IS_HIGH_SURROGATE(aText[i])) { + if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) + i++; + else { + needCopy = TRUE; + break; + } + } } - } - - if (need_copy) { - /* Pango doesn't correctly handle nuls. We convert them to 0xff. */ - /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */ - - UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0])); - - /* don't need to reset i */ - for (i = 0; i < aLength; i++) { - if (!p[i] || IS_LOW_SURROGATE(p[i])) - p[i] = 0xFFFD; - else if (IS_HIGH_SURROGATE(p[i])) { - if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) - i++; - else - p[i] = 0xFFFD; - } + GOwnPtr<UChar> copiedString; + if (needCopy) { + /* Pango doesn't correctly handle nuls. We convert them to 0xff. */ + /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */ + + copiedString.set(static_cast<UChar*>(g_memdup(aText, aLength * sizeof(aText[0])))); + UChar* p = copiedString.get(); + + /* don't need to reset i */ + for (int i = 0; i < aLength; i++) { + if (!p[i] || IS_LOW_SURROGATE(p[i])) + p[i] = 0xFFFD; + else if (IS_HIGH_SURROGATE(p[i])) { + if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) + i++; + else + p[i] = 0xFFFD; + } + } + + aText = p; } - aText = p; - } - - glong items_written; - text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, NULL, &items_written, NULL); - length = items_written; - - if (need_copy) - g_free((gpointer)aText); + gchar* utf8Text; + glong itemsWritten; + utf8Text = g_utf16_to_utf8(static_cast<const gunichar2*>(aText), aLength, 0, &itemsWritten, 0); + length = itemsWritten; + return utf8Text; } static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to) { - gchar* utf8 = 0; - gint new_length = 0; - utf16_to_utf8(characters, length, utf8, new_length); - if (!utf8) - return NULL; + gint newLength = 0; + GOwnPtr<gchar> utf8Text(utf16ToUtf8(characters, length, newLength)); + if (!utf8Text) + return 0; + gchar* pos = utf8Text.get(); if (from > 0) { // discard the first 'from' characters // FIXME: we should do this before the conversion probably - gchar* str_left = g_utf8_offset_to_pointer(utf8, from); - gchar* tmp = g_strdup(str_left); - g_free(utf8); - utf8 = tmp; + pos = g_utf8_offset_to_pointer(utf8Text.get(), from); } - gchar* pos = utf8; gint len = strlen(pos); GString* ret = g_string_new_len(NULL, len); diff --git a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DGtk.cpp b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DGtk.cpp new file mode 100644 index 0000000..8e03ad7 --- /dev/null +++ b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DGtk.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2011 Igalia S.L. + * + * 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 "GraphicsContext3D.h" + +#if ENABLE(WEBGL) + +#include "Extensions3DOpenGL.h" +#include "GraphicsContext3DInternal.h" +#include "OpenGLShims.h" +#include "ShaderLang.h" +#include <wtf/NotFound.h> + +namespace WebCore { + +PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attributes, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) +{ + // This implementation doesn't currently support rendering directly to the HostWindow. + if (renderStyle == RenderDirectlyToHostWindow) + return 0; + + GraphicsContext3DInternal* internal = GraphicsContext3DInternal::create(); + if (!internal) + return 0; + + RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attributes, hostWindow, false)); + context->m_internal.set(internal); + return context.release(); +} + +GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attributes, HostWindow*, bool) + : m_currentWidth(0) + , m_currentHeight(0) + , m_attrs(attributes) + , m_texture(0) + , m_fbo(0) + , m_depthStencilBuffer(0) + , m_boundFBO(0) + , m_multisampleFBO(0) + , m_multisampleDepthStencilBuffer(0) + , m_multisampleColorBuffer(0) +{ + GraphicsContext3DInternal::addActiveGraphicsContext(this); + + validateAttributes(); + + // Create a texture to render into. + ::glGenTextures(1, &m_texture); + ::glBindTexture(GL_TEXTURE_2D, m_texture); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + ::glBindTexture(GL_TEXTURE_2D, 0); + + // Create an FBO. + ::glGenFramebuffersEXT(1, &m_fbo); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + + m_boundFBO = m_fbo; + if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) + ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer); + + // Create a multisample FBO. + if (m_attrs.antialias) { + ::glGenFramebuffersEXT(1, &m_multisampleFBO); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); + m_boundFBO = m_multisampleFBO; + ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer); + if (m_attrs.stencil || m_attrs.depth) + ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); + } + + // ANGLE initialization. + ShBuiltInResources ANGLEResources; + ShInitBuiltInResources(&ANGLEResources); + + getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs); + getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors); + getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors); + getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits); + getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits); + getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits); + getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors); + + // Always set to 1 for OpenGL ES. + ANGLEResources.MaxDrawBuffers = 1; + m_compiler.setResources(ANGLEResources); + + ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + ::glEnable(GL_POINT_SPRITE); + ::glClearColor(0, 0, 0, 0); +} + +GraphicsContext3D::~GraphicsContext3D() +{ + GraphicsContext3DInternal::removeActiveGraphicsContext(this); + if (!m_internal->m_context) + return; + + makeContextCurrent(); + ::glDeleteTextures(1, &m_texture); + if (m_attrs.antialias) { + ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer); + if (m_attrs.stencil || m_attrs.depth) + ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); + ::glDeleteFramebuffersEXT(1, &m_multisampleFBO); + } else { + if (m_attrs.stencil || m_attrs.depth) + ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer); + } + ::glDeleteFramebuffersEXT(1, &m_fbo); +} + +void GraphicsContext3D::makeContextCurrent() +{ + if (!m_internal) + return; + m_internal->makeContextCurrent(); +} + +PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() +{ + return m_internal->m_context; +} + +bool GraphicsContext3D::isGLES2Compliant() const +{ + return false; +} + +} + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.cpp b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.cpp new file mode 100644 index 0000000..de24554 --- /dev/null +++ b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "GraphicsContext3DInternal.h" + +#if ENABLE(WEBGL) + +#include "GraphicsContext3D.h" +#include "OpenGLShims.h" +#include <GL/glx.h> +#include <dlfcn.h> + +// We do not want to call glXMakeContextCurrent using different Display pointers, +// because it might lead to crashes in some drivers (fglrx). We use a shared display +// pointer here. +static Display* gSharedDisplay = 0; +static Display* sharedDisplay() +{ + if (!gSharedDisplay) + gSharedDisplay = XOpenDisplay(0); + return gSharedDisplay; +} + +namespace WebCore { + +// Because of driver bugs, exiting the program when there are active pbuffers +// can crash the X server (this has been observed with the official Nvidia drivers). +// We need to ensure that we clean everything up on exit. There are several reasons +// that GraphicsContext3Ds will still be alive at exit, including user error (memory +// leaks) and the page cache. In any case, we don't want the X server to crash. +static bool cleaningUpAtExit = false; +static Vector<GraphicsContext3D*>& activeGraphicsContexts() +{ + DEFINE_STATIC_LOCAL(Vector<GraphicsContext3D*>, contexts, ()); + return contexts; +} + +void GraphicsContext3DInternal::addActiveGraphicsContext(GraphicsContext3D* context) +{ + static bool addedAtExitHandler = false; + if (!addedAtExitHandler) { + atexit(&GraphicsContext3DInternal::cleanupActiveContextsAtExit); + addedAtExitHandler = true; + } + activeGraphicsContexts().append(context); +} + +void GraphicsContext3DInternal::removeActiveGraphicsContext(GraphicsContext3D* context) +{ + if (cleaningUpAtExit) + return; + + Vector<GraphicsContext3D*>& contexts = activeGraphicsContexts(); + size_t location = contexts.find(context); + if (location != WTF::notFound) + contexts.remove(location); +} + +void GraphicsContext3DInternal::cleanupActiveContextsAtExit() +{ + cleaningUpAtExit = true; + + Vector<GraphicsContext3D*>& contexts = activeGraphicsContexts(); + for (size_t i = 0; i < contexts.size(); i++) + contexts[i]->~GraphicsContext3D(); + + if (!gSharedDisplay) + return; + XCloseDisplay(gSharedDisplay); + gSharedDisplay = 0; +} + +GraphicsContext3DInternal* GraphicsContext3DInternal::create() +{ + if (!sharedDisplay()) + return 0; + + static bool initialized = false; + static bool success = true; + if (!initialized) { + success = initializeOpenGLShims(); + initialized = true; + } + if (!success) + return 0; + + GraphicsContext3DInternal* internal = createPbufferContext(); + if (!internal) + internal = createPixmapContext(); + if (!internal) + return 0; + + // The GraphicsContext3D constructor requires that this context is the current OpenGL context. + internal->makeContextCurrent(); + return internal; +} + +GraphicsContext3DInternal* GraphicsContext3DInternal::createPbufferContext() +{ + int fbConfigAttributes[] = { + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 1, + GLX_DEPTH_SIZE, 1, + GLX_STENCIL_SIZE, 1, + GLX_SAMPLE_BUFFERS, 1, + GLX_DOUBLEBUFFER, GL_FALSE, + GLX_SAMPLES, 4, + 0 + }; + int returnedElements; + GLXFBConfig* configs = glXChooseFBConfig(sharedDisplay(), 0, fbConfigAttributes, &returnedElements); + if (!configs) { + fbConfigAttributes[20] = 0; // Attempt without anti-aliasing. + configs = glXChooseFBConfig(sharedDisplay(), 0, fbConfigAttributes, &returnedElements); + } + if (!returnedElements) { + XFree(configs); + return 0; + } + + // We will be rendering to a texture, so our pbuffer does not need to be large. + static const int pbufferAttributes[] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, 0 }; + GLXPbuffer pbuffer = glXCreatePbuffer(sharedDisplay(), configs[0], pbufferAttributes); + if (!pbuffer) { + XFree(configs); + return 0; + } + + GLXContext context = glXCreateNewContext(sharedDisplay(), configs[0], GLX_RGBA_TYPE, 0, GL_TRUE); + XFree(configs); + if (!context) + return 0; + return new GraphicsContext3DInternal(context, pbuffer); +} + +GraphicsContext3DInternal* GraphicsContext3DInternal::createPixmapContext() +{ + static int visualAttributes[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 1, + GLX_DOUBLEBUFFER, + 0 + }; + + XVisualInfo* visualInfo = glXChooseVisual(sharedDisplay(), DefaultScreen(sharedDisplay()), visualAttributes); + if (!visualInfo) + return 0; + + GLXContext context = glXCreateContext(sharedDisplay(), visualInfo, 0, GL_TRUE); + if (!context) { + XFree(visualInfo); + return 0; + } + + Pixmap pixmap = XCreatePixmap(sharedDisplay(), DefaultRootWindow(sharedDisplay()), 1, 1, visualInfo->depth); + if (!pixmap) { + XFree(visualInfo); + return 0; + } + + GLXPixmap glxPixmap = glXCreateGLXPixmap(sharedDisplay(), visualInfo, pixmap); + if (!glxPixmap) { + XFreePixmap(sharedDisplay(), pixmap); + XFree(visualInfo); + return 0; + } + + return new GraphicsContext3DInternal(context, pixmap, glxPixmap); +} + +GraphicsContext3DInternal::GraphicsContext3DInternal(GLXContext context, GLXPbuffer pbuffer) + : m_context(context) + , m_pbuffer(pbuffer) + , m_pixmap(0) + , m_glxPixmap(0) +{ +} + +GraphicsContext3DInternal::GraphicsContext3DInternal(GLXContext context, Pixmap pixmap, GLXPixmap glxPixmap) + : m_context(context) + , m_pbuffer(0) + , m_pixmap(pixmap) + , m_glxPixmap(glxPixmap) +{ +} + +GraphicsContext3DInternal::~GraphicsContext3DInternal() +{ + if (m_context) { + // This may be necessary to prevent crashes with NVidia's closed source drivers. Originally + // from Mozilla's 3D canvas implementation at: http://bitbucket.org/ilmari/canvas3d/ + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + ::glXMakeContextCurrent(sharedDisplay(), 0, 0, 0); + ::glXDestroyContext(sharedDisplay(), m_context); + m_context = 0; + } + + if (m_pbuffer) { + ::glXDestroyPbuffer(sharedDisplay(), m_pbuffer); + m_pbuffer = 0; + } + if (m_glxPixmap) { + glXDestroyGLXPixmap(sharedDisplay(), m_glxPixmap); + m_glxPixmap = 0; + } + if (m_pixmap) { + XFreePixmap(sharedDisplay(), m_pixmap); + m_pixmap = 0; + } +} + +void GraphicsContext3DInternal::makeContextCurrent() +{ + if (::glXGetCurrentContext() == m_context) + return; + if (!m_context) + return; + if (m_pbuffer) { + ::glXMakeCurrent(sharedDisplay(), m_pbuffer, m_context); + return; + } + + ASSERT(m_glxPixmap); + ::glXMakeCurrent(sharedDisplay(), m_glxPixmap, m_context); +} + +} // namespace WebCore + +#endif // ENABLE_WEBGL diff --git a/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.h b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.h new file mode 100644 index 0000000..f4a60d9 --- /dev/null +++ b/Source/WebCore/platform/graphics/gtk/GraphicsContext3DInternal.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GraphicsContext3DInternal_h +#define GraphicsContext3DInternal_h + +typedef struct __GLXcontextRec *GLXContext; +typedef unsigned long GLXPbuffer; +typedef unsigned long GLXPixmap; +typedef unsigned char GLubyte; +typedef unsigned long Pixmap; + +namespace WebCore { + +class GraphicsContext3D; + +class GraphicsContext3DInternal { + public: + static GraphicsContext3DInternal* create(); + ~GraphicsContext3DInternal(); + void makeContextCurrent(); + + private: + friend class GraphicsContext3D; + static GraphicsContext3DInternal* createPbufferContext(); + static GraphicsContext3DInternal* createPixmapContext(); + GraphicsContext3DInternal(GLXContext, GLXPbuffer); + GraphicsContext3DInternal(GLXContext, Pixmap, GLXPixmap); + + static void addActiveGraphicsContext(GraphicsContext3D*); + static void removeActiveGraphicsContext(GraphicsContext3D*); + static void cleanupActiveContextsAtExit(); + + GLXContext m_context; + GLXPbuffer m_pbuffer; + Pixmap m_pixmap; + GLXPixmap m_glxPixmap; +}; + +} + +#endif // GraphicsContext3DIternal_h diff --git a/Source/WebCore/platform/graphics/haiku/ImageBufferData.h b/Source/WebCore/platform/graphics/haiku/ImageBufferDataHaiku.h index 7c676cd..10285fc 100644 --- a/Source/WebCore/platform/graphics/haiku/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/haiku/ImageBufferDataHaiku.h @@ -25,9 +25,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include <Bitmap.h> #include <View.h> @@ -45,6 +42,3 @@ public: }; } // namespace WebCore - -#endif // ImageBufferData_h - diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextController.h b/Source/WebCore/platform/graphics/mac/ComplexTextController.h index 44a7994..281e49f 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextController.h +++ b/Source/WebCore/platform/graphics/mac/ComplexTextController.h @@ -116,9 +116,6 @@ private: static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef, URefCon, void*, ATSULayoutOperationCallbackStatus*); #endif -#if USE(CORE_TEXT) - RetainPtr<CTRunRef> m_coreTextRun; -#endif unsigned m_glyphCount; const SimpleFontData* m_fontData; const UChar* m_characters; @@ -159,6 +156,10 @@ private: Vector<UChar, 256> m_smallCapsBuffer; +#if USE(CORE_TEXT) + // Retain lines rather than their runs for better performance. + Vector<RetainPtr<CTLineRef> > m_coreTextLines; +#endif Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns; Vector<CGSize, 256> m_adjustedAdvances; Vector<CGGlyph, 256> m_adjustedGlyphs; diff --git a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp index d2fbaf5..1473b1e 100644 --- a/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp +++ b/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp @@ -43,33 +43,32 @@ extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel; namespace WebCore { ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, CFRange runRange) - : m_coreTextRun(ctRun) - , m_fontData(fontData) + : m_fontData(fontData) , m_characters(characters) , m_stringLocation(stringLocation) , m_stringLength(stringLength) , m_indexEnd(runRange.location + runRange.length) , m_isMonotonic(true) { - m_glyphCount = CTRunGetGlyphCount(m_coreTextRun.get()); - m_coreTextIndices = CTRunGetStringIndicesPtr(m_coreTextRun.get()); + m_glyphCount = CTRunGetGlyphCount(ctRun); + m_coreTextIndices = CTRunGetStringIndicesPtr(ctRun); if (!m_coreTextIndices) { m_coreTextIndicesVector.grow(m_glyphCount); - CTRunGetStringIndices(m_coreTextRun.get(), CFRangeMake(0, 0), m_coreTextIndicesVector.data()); + CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), m_coreTextIndicesVector.data()); m_coreTextIndices = m_coreTextIndicesVector.data(); } - m_glyphs = CTRunGetGlyphsPtr(m_coreTextRun.get()); + m_glyphs = CTRunGetGlyphsPtr(ctRun); if (!m_glyphs) { m_glyphsVector.grow(m_glyphCount); - CTRunGetGlyphs(m_coreTextRun.get(), CFRangeMake(0, 0), m_glyphsVector.data()); + CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), m_glyphsVector.data()); m_glyphs = m_glyphsVector.data(); } - m_advances = CTRunGetAdvancesPtr(m_coreTextRun.get()); + m_advances = CTRunGetAdvancesPtr(ctRun); if (!m_advances) { m_advancesVector.grow(m_glyphCount); - CTRunGetAdvances(m_coreTextRun.get(), CFRangeMake(0, 0), m_advancesVector.data()); + CTRunGetAdvances(ctRun, CFRangeMake(0, 0), m_advancesVector.data()); m_advances = m_advancesVector.data(); } } @@ -159,6 +158,8 @@ void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UC line.adoptCF(wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info)); } + m_coreTextLines.append(line.get()); + CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); CFIndex runCount = CFArrayGetCount(runArray); diff --git a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm index 997c976..2a469a7 100644 --- a/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm +++ b/Source/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm @@ -90,8 +90,8 @@ PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attri GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, bool) : m_currentWidth(0) , m_currentHeight(0) - , m_attrs(attrs) , m_contextObj(0) + , m_attrs(attrs) , m_texture(0) , m_compositorTexture(0) , m_fbo(0) diff --git a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index cd34000..f34d53b 100644 --- a/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/Source/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -241,6 +241,7 @@ void SimpleFontData::platformInit() NSString *familyName = [m_platformData.font() familyName]; if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"]) ascent += floorf(((ascent + descent) * 0.15f) + 0.5f); +#if defined(BUILDING_ON_LEOPARD) else if ([familyName isEqualToString:@"Geeza Pro"]) { // Geeza Pro has glyphs that draw slightly above the ascent or far below the descent. Adjust // those vertical metrics to better match reality, so that diacritics at the bottom of one line @@ -248,6 +249,7 @@ void SimpleFontData::platformInit() ascent *= 1.08f; descent *= 2.f; } +#endif // Compute and store line spacing, before the line metrics hacks are applied. m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp index e09534e..4c7164e 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.cpp @@ -35,6 +35,8 @@ #if PLATFORM(MAC) #include "ANGLE/ShaderLang.h" #include <OpenGL/gl.h> +#elif PLATFORM(GTK) +#include "OpenGLShims.h" #endif namespace WebCore { @@ -116,6 +118,17 @@ void Extensions3DOpenGL::ensureEnabled(const String& name) #endif } +bool Extensions3DOpenGL::isEnabled(const String& name) +{ +#if PLATFORM(MAC) + if (name == "GL_OES_standard_derivatives") { + ANGLEWebKitBridge& compiler = m_context->m_compiler; + return compiler.getResources().OES_standard_derivatives; + } +#endif + return supports(name); +} + int Extensions3DOpenGL::getGraphicsResetStatusARB() { return GraphicsContext3D::NO_ERROR; @@ -134,7 +147,7 @@ void Extensions3DOpenGL::renderbufferStorageMultisample(unsigned long target, un Platform3DObject Extensions3DOpenGL::createVertexArrayOES() { m_context->makeContextCurrent(); -#if defined GL_APPLE_vertex_array_object && GL_APPLE_vertex_array_object +#if !PLATFORM(GTK) && defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object GLuint array = 0; glGenVertexArraysAPPLE(1, &array); return array; @@ -149,7 +162,7 @@ void Extensions3DOpenGL::deleteVertexArrayOES(Platform3DObject array) return; m_context->makeContextCurrent(); -#if defined GL_APPLE_vertex_array_object && GL_APPLE_vertex_array_object +#if !PLATFORM(GTK) && defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object glDeleteVertexArraysAPPLE(1, &array); #endif } @@ -160,7 +173,7 @@ GC3Dboolean Extensions3DOpenGL::isVertexArrayOES(Platform3DObject array) return GL_FALSE; m_context->makeContextCurrent(); -#if defined GL_APPLE_vertex_array_object && GL_APPLE_vertex_array_object +#if !PLATFORM(GTK) && defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object return glIsVertexArrayAPPLE(array); #else return GL_FALSE; @@ -173,7 +186,7 @@ void Extensions3DOpenGL::bindVertexArrayOES(Platform3DObject array) return; m_context->makeContextCurrent(); -#if defined GL_APPLE_vertex_array_object && GL_APPLE_vertex_array_object +#if !PLATFORM(GTK) && defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object glBindVertexArrayAPPLE(array); #endif } diff --git a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h index 9188507..e545fbc 100644 --- a/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h +++ b/Source/WebCore/platform/graphics/opengl/Extensions3DOpenGL.h @@ -41,6 +41,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); virtual void ensureEnabled(const String&); + virtual bool isEnabled(const String&); virtual int getGraphicsResetStatusARB(); virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp index f831550..af46293 100644 --- a/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp @@ -42,14 +42,16 @@ #include "Int32Array.h" #include "NotImplemented.h" #include "Uint8Array.h" +#include <cstring> +#include <wtf/UnusedParam.h> +#include <wtf/text/CString.h> #if PLATFORM(MAC) #include <OpenGL/gl.h> +#elif PLATFORM(GTK) +#include "OpenGLShims.h" #endif -#include <wtf/UnusedParam.h> -#include <wtf/text/CString.h> - namespace WebCore { void GraphicsContext3D::validateAttributes() @@ -163,7 +165,7 @@ PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData() void GraphicsContext3D::reshape(int width, int height) { - if (!m_contextObj) + if (!platformGraphicsContext3D()) return; if (width == m_currentWidth && height == m_currentHeight) diff --git a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp index 9765937..1493966 100644 --- a/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/opengl/TextureMapperGL.cpp @@ -388,7 +388,7 @@ void TextureMapperGL::drawTexture(const BitmapTexture& texture, const IntRect& t GL_CMD(glBindTexture(GL_TEXTURE_2D, textureGL.m_id)) GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0)) const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1}; - GL_CMD(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) + GL_CMD(glVertexAttribPointer(gInVertexAttributeIndex, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) TransformationMatrix matrix = TransformationMatrix(data().projectionMatrix).multiply(modelViewMatrix).multiply(TransformationMatrix( targetRect.width(), 0, 0, 0, @@ -641,7 +641,7 @@ void TextureMapperGL::paintToTarget(const BitmapTexture& aSurface, const IntSize GL_CMD(glUniformMatrix4fv(programInfo.vars[TextureMapperGLData::ShaderInfo::InSourceMatrixVariable], 1, GL_FALSE, m4src)) GL_CMD(glBindBuffer(GL_ARRAY_BUFFER, 0)) const GLfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1}; - GL_CMD(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) + GL_CMD(glVertexAttribPointer(gInVertexAttributeIndex, 2, GL_FLOAT, GL_FALSE, 0, unitRect)) GL_CMD(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)) GL_CMD(glEnable(GL_BLEND)) setClip(visibleRect); diff --git a/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index 7f4547d..6afe3d9 100644 --- a/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp +++ b/Source/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp @@ -70,7 +70,7 @@ struct TableDirectoryEntry { BigEndianULong length; }; -#if !PLATFORM(CG) || !defined(COREGRAPHICS_INCLUDES_CORESERVICES_HEADER) +#if !USE(CG) || !defined(COREGRAPHICS_INCLUDES_CORESERVICES_HEADER) // Fixed type is not defined on non-CG and Windows 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 diff --git a/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp b/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp index 75dbadb..1595692 100644 --- a/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp +++ b/Source/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp @@ -257,7 +257,7 @@ void GraphicsContext::drawLineForTextChecking(const IntPoint& origin, int width, UNUSED_PARAM(style); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode) { if (paintingDisabled()) return FloatRect(); diff --git a/Source/WebCore/platform/graphics/pango/FontPlatformData.h b/Source/WebCore/platform/graphics/pango/FontPlatformData.h index 180d23b..bd9251b 100644 --- a/Source/WebCore/platform/graphics/pango/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/pango/FontPlatformData.h @@ -68,6 +68,7 @@ public: bool syntheticOblique() const { return m_syntheticOblique; } FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + void setOrientation(FontOrientation) { } // FIXME: Implement. cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp index 3adc93f..45d5e9c 100644 --- a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp @@ -52,6 +52,11 @@ void Extensions3DQt::ensureEnabled(const String& name) ASSERT(supports(name)); } +bool Extensions3DQt::isEnabled(const String& name) +{ + return supports(name); +} + int Extensions3DQt::getGraphicsResetStatusARB() { return GraphicsContext3D::NO_ERROR; diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.h b/Source/WebCore/platform/graphics/qt/Extensions3DQt.h index c67fbed..1bc47b8 100644 --- a/Source/WebCore/platform/graphics/qt/Extensions3DQt.h +++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.h @@ -37,6 +37,7 @@ public: // Extensions3D methods. virtual bool supports(const String&); virtual void ensureEnabled(const String&); + virtual bool isEnabled(const String&); virtual int getGraphicsResetStatusARB(); virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter); virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height); diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 4daa4dc..e92f927 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -447,6 +447,12 @@ GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attribut GraphicsContext3DInternal::~GraphicsContext3DInternal() { + m_glWidget->makeCurrent(); + if (m_glWidget->isValid()) { + ::glDeleteTextures(1, &m_texture); + deleteRenderbuffers(1, &m_depthBuffer); + deleteFramebuffers(1, &m_canvasFbo); + } delete m_glWidget; m_glWidget = 0; } @@ -588,7 +594,7 @@ void* GraphicsContext3DInternal::getProcAddress(const String& proc) for (int i = 0; i < 3; i++) { String nameWithExt = proc + ext[i]; - void* addr = m_glWidget->context()->getProcAddress(nameWithExt.utf8().data()); + void* addr = m_glWidget->context()->getProcAddress(QString(nameWithExt)); if (addr) return addr; } @@ -656,7 +662,7 @@ PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData() void GraphicsContext3D::reshape(int width, int height) { - if (width == m_currentWidth && height == m_currentHeight || (!m_internal)) + if ((width == m_currentWidth && height == m_currentHeight) || (!m_internal)) return; m_currentWidth = width; diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index e3e0fa6..a3a08eb 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -900,7 +900,7 @@ void GraphicsContext::drawLineForTextChecking(const FloatPoint&, float, TextChec notImplemented(); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { // It is not enough just to round to pixels in device space. The rotation part of the // affine transform matrix to device space can mess with this conversion if we have a diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferData.h b/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.h index 602197e..8b49829 100644 --- a/Source/WebCore/platform/graphics/qt/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/qt/ImageBufferDataQt.h @@ -23,16 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "Image.h" -#include <wtf/RefPtr.h> +#include "OwnPtr.h" #include <QPainter> #include <QPixmap> - -#include "OwnPtr.h" +#include <wtf/RefPtr.h> namespace WebCore { @@ -49,6 +45,4 @@ public: RefPtr<Image> m_image; }; -} // namespace WebCore - -#endif // ImageBufferData_h +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index bc43acf..e7efdf9 100644 --- a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -84,7 +84,17 @@ MediaPlayer::SupportsType MediaPlayerPrivateQt::supportsType(const String& mime, if (!mime.startsWith("audio/") && !mime.startsWith("video/")) return MediaPlayer::IsNotSupported; - if (QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMultimediaKit::ProbablySupported) + // Parse and trim codecs. + QString codecStr = codec; + QStringList codecList = codecStr.split(QLatin1Char(','), QString::SkipEmptyParts); + QStringList codecListTrimmed; + foreach (const QString& codecStrNotTrimmed, codecList) { + QString codecStrTrimmed = codecStrNotTrimmed.trimmed(); + if (!codecStrTrimmed.isEmpty()) + codecListTrimmed.append(codecStrTrimmed); + } + + if (QMediaPlayer::hasSupport(mime, codecListTrimmed) >= QtMultimediaKit::ProbablySupported) return MediaPlayer::IsSupported; return MediaPlayer::MayBeSupported; diff --git a/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index 5d0b302..9bf1030 100644 --- a/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2008, 2009, 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) Copyright (C) 2008 Holger Hans Peter Freyther This library is free software; you can redistribute it and/or @@ -48,11 +48,29 @@ void SimpleFontData::platformInit() } QFontMetricsF fm(m_platformData.font()); - m_fontMetrics.setAscent(fm.ascent()); - m_fontMetrics.setDescent(fm.descent()); + + // Qt subtracts 1 from the descent to account for the baseline, + // we add it back here to get correct metrics for WebKit. + float descent = fm.descent() + 1; + float ascent = fm.ascent(); + + float lineSpacing = fm.lineSpacing(); + + // The line spacing should always be >= (ascent + descent), but this + // may be false in some cases due to misbehaving platform libraries. + // Workaround from SimpleFontPango.cpp and SimpleFontFreeType.cpp + if (lineSpacing < ascent + descent) + lineSpacing = ascent + descent; + + // QFontMetricsF::leading() may return negative values on platforms + // such as FreeType. Calculate the line gap manually instead. + float lineGap = lineSpacing - ascent - descent; + + m_fontMetrics.setAscent(ascent); + m_fontMetrics.setDescent(descent); + m_fontMetrics.setLineSpacing(lineSpacing); m_fontMetrics.setXHeight(fm.xHeight()); - m_fontMetrics.setLineGap(fm.leading()); - m_fontMetrics.setLineSpacing(fm.lineSpacing()); + m_fontMetrics.setLineGap(lineGap); m_spaceWidth = fm.width(QLatin1Char(' ')); } diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp index 5950c35..0fb44e7 100644 --- a/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp @@ -30,6 +30,7 @@ #include "GraphicsContext3D.h" +#include "BitmapImage.h" #include "Image.h" #include "ImageSource.h" #include "NativeImageSkia.h" @@ -50,15 +51,17 @@ bool GraphicsContext3D::getImageData(Image* image, if (!image) return false; OwnPtr<NativeImageSkia> pixels; - NativeImageSkia* skiaImage = 0; + NativeImageSkia* skiaImage = image->nativeImageForCurrentFrame(); AlphaOp neededAlphaOp = AlphaDoNothing; - if (image->data()) { + bool hasAlpha = skiaImage ? !skiaImage->isOpaque() : true; + if ((!skiaImage || ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && image->data()) { ImageSource decoder(ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); + // Attempt to get raw unpremultiplied image data decoder.setData(image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; - bool hasAlpha = decoder.frameHasAlphaAtIndex(0); + hasAlpha = decoder.frameHasAlphaAtIndex(0); pixels = adoptPtr(decoder.createFrameAtIndex(0)); if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height()) return false; @@ -68,12 +71,8 @@ bool GraphicsContext3D::getImageData(Image* image, skiaImage = pixels.get(); if (hasAlpha && premultiplyAlpha) neededAlphaOp = AlphaDoPremultiply; - } else { - // This is a special case for texImage2D with HTMLCanvasElement input. - skiaImage = image->nativeImageForCurrentFrame(); - if (!premultiplyAlpha) - neededAlphaOp = AlphaDoUnmultiply; - } + } else if (!premultiplyAlpha && hasAlpha) + neededAlphaOp = AlphaDoUnmultiply; if (!skiaImage) return false; SkBitmap& skiaImageRef = *skiaImage; diff --git a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index df680eb..f285c9b 100644 --- a/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -44,8 +44,10 @@ #include "PlatformContextSkia.h" #include "SkBitmap.h" -#include "SkBlurDrawLooper.h" +#include "SkBlurMaskFilter.h" +#include "SkColorFilter.h" #include "SkCornerPathEffect.h" +#include "SkLayerDrawLooper.h" #include "SkShader.h" #include "SkiaUtils.h" #include "skia/ext/platform_canvas.h" @@ -853,6 +855,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, SkPaint paint; platformContext()->setupPaintForFilling(&paint); + paint.setColor(color.rgb()); platformContext()->canvas()->drawPath(path, paint); } @@ -867,7 +870,7 @@ AffineTransform GraphicsContext::getCTM() const SkScalarToDouble(m.getTranslateY())); } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect, RoundingMode) { return rect; } @@ -1043,16 +1046,15 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, double height = size.height(); double blur = blurFloat; - uint32_t blurFlags = SkBlurDrawLooper::kHighQuality_BlurFlag | - SkBlurDrawLooper::kOverrideColor_BlurFlag; + uint32_t mfFlags = SkBlurMaskFilter::kHighQuality_BlurFlag; if (m_state.shadowsIgnoreTransforms) { // Currently only the GraphicsContext associated with the // CanvasRenderingContext for HTMLCanvasElement have shadows ignore // Transforms. So with this flag set, we know this state is associated // with a CanvasRenderingContext. - blurFlags |= SkBlurDrawLooper::kIgnoreTransform_BlurFlag; - + mfFlags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag; + // CG uses natural orientation for Y axis, but the HTML5 canvas spec // does not. // So we now flip the height since it was flipped in @@ -1068,9 +1070,32 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, // TODO(tc): Should we have a max value for the blur? CG clamps at 1000.0 // for perf reasons. - SkDrawLooper* dl = new SkBlurDrawLooper(blur / 2, width, height, c, blurFlags); + + SkLayerDrawLooper* dl = new SkLayerDrawLooper; + SkAutoUnref aur(dl); + + // top layer, we just draw unchanged + dl->addLayer(); + + // lower layer contains our offset, blur, and colorfilter + SkLayerDrawLooper::LayerInfo info; + + info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; // our blur + info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; + info.fColorMode = SkXfermode::kDst_Mode; + info.fOffset.set(width, height); + info.fPostTranslate = m_state.shadowsIgnoreTransforms; + + SkMaskFilter* mf = SkBlurMaskFilter::Create(blur / 2, SkBlurMaskFilter::kNormal_BlurStyle, mfFlags); + + SkColorFilter* cf = SkColorFilter::CreateModeFilter(c, SkXfermode::kSrcIn_Mode); + + SkPaint* paint = dl->addLayer(info); + SkSafeUnref(paint->setMaskFilter(mf)); + SkSafeUnref(paint->setColorFilter(cf)); + + // dl is now built, just install it platformContext()->setDrawLooper(dl); - dl->unref(); } void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace) diff --git a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index b89c68d..2352672 100644 --- a/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -66,19 +66,21 @@ ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& s : m_data(size) , m_size(size) { - if (!m_data.m_canvas.initialize(size.width(), size.height(), false)) { + SkCanvas* canvas = skia::CreateBitmapCanvas(size.width(), size.height(), false); + if (!canvas) { success = false; return; } - m_data.m_platformContext.setCanvas(&m_data.m_canvas); + m_data.m_canvas = canvas; + m_data.m_platformContext.setCanvas(m_data.m_canvas.get()); m_context.set(new GraphicsContext(&m_data.m_platformContext)); m_context->platformContext()->setDrawingToImageBuffer(true); // Make the background transparent. It would be nice if this wasn't // required, but the canvas is currently filled with the magic transparency // color. Can we have another way to manage this? - m_data.m_canvas.drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); + m_data.m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); success = true; } @@ -117,6 +119,7 @@ void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, con { if (m_data.m_platformContext.useGPU() && context->platformContext()->useGPU()) { if (context->platformContext()->canAccelerate()) { + m_data.m_platformContext.prepareForHardwareDraw(); DrawingBuffer* sourceDrawingBuffer = m_data.m_platformContext.gpuCanvas()->drawingBuffer(); unsigned sourceTexture = static_cast<unsigned>(sourceDrawingBuffer->platformColorBuffer()); FloatRect destRectNormalized(normalizeRect(destRect)); @@ -344,6 +347,8 @@ void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& so template <typename T> static String ImageToDataURL(T& source, const String& mimeType, const double* quality) { + ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); + Vector<unsigned char> encodedImage; if (mimeType == "image/jpeg") { int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; @@ -365,9 +370,6 @@ static String ImageToDataURL(T& source, const String& mimeType, const double* qu String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const { - ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); - - Vector<unsigned char> encodedImage; SkDevice* device = context()->platformContext()->canvas()->getDevice(); SkBitmap bitmap = device->accessBitmap(false); diff --git a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp index 72bec29..6987e00 100644 --- a/Source/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -66,6 +66,7 @@ enum ResamplingMode { RESAMPLE_AWESOME, }; +#if !ENABLE(SKIA_GPU) static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight) { if (platformContext->hasImageResamplingHint()) { @@ -150,6 +151,7 @@ static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext return RESAMPLE_LINEAR; } +#endif // Draws the given bitmap to the given canvas. The subset of the source bitmap // identified by src_rect is drawn to the given destination rect. The bitmap @@ -262,12 +264,17 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag paint.setAlpha(platformContext->getNormalizedAlpha()); paint.setLooper(platformContext->getDrawLooper()); - skia::PlatformCanvas* canvas = platformContext->canvas(); + SkCanvas* canvas = platformContext->canvas(); - ResamplingMode resampling = platformContext->isPrinting() ? RESAMPLE_NONE : + ResamplingMode resampling; +#if ENABLE(SKIA_GPU) + resampling = RESAMPLE_LINEAR; +#else + resampling = platformContext->printing() ? RESAMPLE_NONE : computeResamplingMode(platformContext, bitmap, srcRect.width(), srcRect.height(), SkScalarToFloat(destRect.width()), SkScalarToFloat(destRect.height())); +#endif if (resampling == RESAMPLE_AWESOME) { drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect); } else { @@ -363,13 +370,17 @@ void Image::drawPattern(GraphicsContext* context, // Compute the resampling mode. ResamplingMode resampling; - if (context->platformContext()->isPrinting()) +#if ENABLE(SKIA_GPU) + resampling = RESAMPLE_LINEAR; +#else + if (context->platformContext()->printing()) resampling = RESAMPLE_LINEAR; else { resampling = computeResamplingMode(context->platformContext(), *bitmap, srcRect.width(), srcRect.height(), destBitmapWidth, destBitmapHeight); } +#endif // Load the transform WebKit requested. SkMatrix matrix(patternTransform); diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index 8e1937f..4cc5457 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -213,8 +213,9 @@ SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const // PlatformContextSkia --------------------------------------------------------- // Danger: canvas can be NULL. -PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) +PlatformContextSkia::PlatformContextSkia(SkCanvas* canvas) : m_canvas(canvas) + , m_printing(false) , m_drawingToImageBuffer(false) , m_useGPU(false) #if ENABLE(ACCELERATED_2D_CANVAS) @@ -232,15 +233,18 @@ PlatformContextSkia::~PlatformContextSkia() if (m_gpuCanvas) { #if ENABLE(SKIA_GPU) // make sure everything related to this platform context has been flushed - if (!m_useGPU) - m_gpuCanvas->context()->grContext()->flush(0); + if (!m_useGPU) { + SharedGraphicsContext3D* context = m_gpuCanvas->context(); + context->makeContextCurrent(); + context->grContext()->flush(0); + } #endif m_gpuCanvas->drawingBuffer()->setWillPublishCallback(0); } #endif } -void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas) +void PlatformContextSkia::setCanvas(SkCanvas* canvas) { m_canvas = canvas; } @@ -609,12 +613,12 @@ const SkBitmap* PlatformContextSkia::bitmap() const return &m_canvas->getDevice()->accessBitmap(false); } -bool PlatformContextSkia::isPrinting() +bool PlatformContextSkia::isNativeFontRenderingAllowed() { #if ENABLE(SKIA_GPU) - return true; + return false; #else - return m_canvas->getTopPlatformDevice().IsVectorial(); + return skia::SupportsPlatformPaint(m_canvas); #endif } @@ -738,7 +742,12 @@ void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* co gr->resetContext(); drawingBuffer->setGrContext(gr); - SkDeviceFactory* factory = new SkGpuDeviceFactory(gr, SkGpuDevice::Current3DApiRenderTarget()); + GrPlatformSurfaceDesc drawBufDesc; + drawingBuffer->getGrPlatformSurfaceDesc(&drawBufDesc); + GrTexture* drawBufTex = static_cast<GrTexture*>(gr->createPlatformSurface(drawBufDesc)); + SkDeviceFactory* factory = new SkGpuDeviceFactory(gr, drawBufTex); + drawBufTex->unref(); + SkDevice* device = factory->newDevice(m_canvas, SkBitmap::kARGB_8888_Config, drawingBuffer->size().width(), drawingBuffer->size().height(), false, false); m_canvas->setDevice(device)->unref(); m_canvas->setDeviceFactory(factory); diff --git a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h index d7dd6a9..fc82221 100644 --- a/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -72,12 +72,12 @@ class PlatformContextSkia { public: // For printing, there shouldn't be any canvas. canvas can be NULL. If you // supply a NULL canvas, you can also call setCanvas later. - PlatformContextSkia(skia::PlatformCanvas*); + PlatformContextSkia(SkCanvas*); ~PlatformContextSkia(); // Sets the canvas associated with this context. Use when supplying NULL // to the constructor. - void setCanvas(skia::PlatformCanvas*); + void setCanvas(SkCanvas*); // 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). @@ -146,7 +146,8 @@ public: // by the current alpha. SkColor effectiveStrokeColor() const; - skia::PlatformCanvas* canvas() { return m_canvas; } + // Returns the canvas used for painting, NOT guaranteed to be non-null. + SkCanvas* canvas() { return m_canvas; } InterpolationQuality interpolationQuality() const; void setInterpolationQuality(InterpolationQuality interpolationQuality); @@ -159,17 +160,16 @@ public: const SkBitmap* bitmap() const; - // Returns the canvas used for painting, NOT guaranteed to be non-NULL. - // - // Warning: This function is deprecated so the users are reminded that they - // should use this layer of indirection instead of using the canvas - // directly. This is to help with the eventual serialization. - skia::PlatformCanvas* canvas() const; - // Returns if the context is a printing context instead of a display // context. Bitmap shouldn't be resampled when printing to keep the best // possible quality. - bool isPrinting(); + bool printing() const { return m_printing; } + void setPrinting(bool p) { m_printing = p; } + + // Returns if the context allows rendering of fonts using native platform + // APIs. If false is returned font rendering is performed using the skia + // text drawing APIs. + bool isNativeFontRenderingAllowed(); void getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const; void setImageResamplingHint(const IntSize& srcSize, const FloatSize& dstSize); @@ -186,10 +186,10 @@ public: GLES2Canvas* gpuCanvas() const { return 0; } #endif // Call these before making a call that manipulates the underlying - // skia::PlatformCanvas or WebCore::GLES2Canvas + // SkCanvas or WebCore::GLES2Canvas void prepareForSoftwareDraw() const; void prepareForHardwareDraw() const; - // Call to force the skia::PlatformCanvas to contain all rendering results. + // Call to force the SkCanvas to contain all rendering results. void syncSoftwareCanvas() const; void markDirtyRect(const IntRect& rect); @@ -206,7 +206,7 @@ private: struct State; // NULL indicates painting is disabled. Never delete this object. - skia::PlatformCanvas* m_canvas; + SkCanvas* m_canvas; // States stack. Enables local drawing state change with save()/restore() // calls. @@ -219,6 +219,7 @@ private: // Values are used in ImageSkia.cpp IntSize m_imageResamplingHintSrcSize; FloatSize m_imageResamplingHintDstSize; + bool m_printing; bool m_drawingToImageBuffer; bool m_useGPU; #if ENABLE(ACCELERATED_2D_CANVAS) diff --git a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp index b0cb0c7..8ab823e 100644 --- a/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp +++ b/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -39,16 +39,11 @@ #include "SkPaint.h" #include "SkShader.h" #include "SkTemplates.h" -#include "SkTypeface.h" +#include "SkTypeface_win.h" #include <wtf/ListHashSet.h> #include <wtf/Vector.h> -#if ENABLE(SKIA_TEXT) -// FIXME: a future role of skia will have this in a proper header -extern SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&); -#endif - namespace WebCore { struct CachedOutlineKey { @@ -235,11 +230,23 @@ bool windowsCanHandleDrawTextShadow(GraphicsContext *context) ColorSpace shadowColorSpace; bool hasShadow = context->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); - return (hasShadow && (shadowBlur == 0) && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255)); + return !hasShadow || (!shadowBlur && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255)); } bool windowsCanHandleTextDrawing(GraphicsContext* context) { + if (!windowsCanHandleTextDrawingWithoutShadow(context)) + return false; + + // Check for shadow effects. + if (!windowsCanHandleDrawTextShadow(context)) + return false; + + return true; +} + +bool windowsCanHandleTextDrawingWithoutShadow(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, @@ -261,8 +268,7 @@ bool windowsCanHandleTextDrawing(GraphicsContext* context) if (context->fillPattern() || context->strokePattern()) return false; - // Check for shadow effects. - if (context->platformContext()->getDrawLooper() && (!windowsCanHandleDrawTextShadow(context))) + if (!context->platformContext()->isNativeFontRenderingAllowed()) return false; return true; @@ -272,7 +278,7 @@ bool windowsCanHandleTextDrawing(GraphicsContext* context) // pattern may be NULL, in which case a solid colour is used. static bool skiaDrawText(HFONT hfont, HDC dc, - SkCanvas* canvas, + PlatformContextSkia* platformContext, const SkPoint& point, SkPaint* paint, const WORD* glyphs, @@ -280,47 +286,47 @@ static bool skiaDrawText(HFONT hfont, const GOFFSET* offsets, int numGlyphs) { -#if ENABLE(SKIA_TEXT) - SkASSERT(sizeof(WORD) == sizeof(uint16_t)); - - // Reserve space for 64 glyphs on the stack. If numGlyphs is larger, the array - // will dynamically allocate it space for numGlyph glyphs. - static const size_t kLocalGlyphMax = 64; - SkAutoSTArray<kLocalGlyphMax, SkPoint> posStorage(numGlyphs); - SkPoint* pos = posStorage.get(); - SkScalar x = point.fX; - SkScalar y = point.fY; - for (int i = 0; i < numGlyphs; i++) { - pos[i].set(x + (offsets ? offsets[i].du : 0), - y + (offsets ? offsets[i].dv : 0)); - x += SkIntToScalar(advances[i]); - } - canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, *paint); -#else - 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; + SkCanvas* canvas = platformContext->canvas(); + if (!platformContext->isNativeFontRenderingAllowed()) { + SkASSERT(sizeof(WORD) == sizeof(uint16_t)); + + // Reserve space for 64 glyphs on the stack. If numGlyphs is larger, the array + // will dynamically allocate it space for numGlyph glyphs. + static const size_t kLocalGlyphMax = 64; + SkAutoSTArray<kLocalGlyphMax, SkPoint> posStorage(numGlyphs); + SkPoint* pos = posStorage.get(); + SkScalar x = point.fX; + SkScalar y = point.fY; + for (int i = 0; i < numGlyphs; i++) { + pos[i].set(x + (offsets ? offsets[i].du : 0), + y + (offsets ? offsets[i].dv : 0)); + x += SkIntToScalar(advances[i]); } + canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, *paint); + } else { + 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 || offsets[i].dv)) { + offsetX = offsets[i].du; + offsetY = offsets[i].dv; + } - SkPath newPath; - newPath.addPath(*path, x + offsetX, y + offsetY); - canvas->drawPath(newPath, *paint); + SkPath newPath; + newPath.addPath(*path, x + offsetX, y + offsetY); + canvas->drawPath(newPath, *paint); - x += advances[i]; + x += advances[i]; + } } -#endif return true; } -#if ENABLE(SKIA_TEXT) static void setupPaintForFont(HFONT hfont, SkPaint* paint) { // FIXME: @@ -339,7 +345,6 @@ static void setupPaintForFont(HFONT hfont, SkPaint* paint) paint->setTypeface(face); SkSafeUnref(face); } -#endif bool paintSkiaText(GraphicsContext* context, HFONT hfont, @@ -359,14 +364,14 @@ bool paintSkiaText(GraphicsContext* context, SkPaint paint; platformContext->setupPaintForFilling(&paint); paint.setFlags(SkPaint::kAntiAlias_Flag); -#if ENABLE(SKIA_TEXT) - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - setupPaintForFont(hfont, &paint); -#endif + if (!platformContext->isNativeFontRenderingAllowed()) { + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + setupPaintForFont(hfont, &paint); + } bool didFill = false; - if ((textMode & TextModeFill) && SkColorGetA(paint.getColor())) { - if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint, + if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) { + if (!skiaDrawText(hfont, dc, platformContext, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs)) return false; didFill = true; @@ -380,10 +385,10 @@ bool paintSkiaText(GraphicsContext* context, paint.reset(); platformContext->setupPaintForStroking(&paint, 0, 0); paint.setFlags(SkPaint::kAntiAlias_Flag); -#if ENABLE(SKIA_TEXT) - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - setupPaintForFont(hfont, &paint); -#endif + if (!platformContext->isNativeFontRenderingAllowed()) { + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + setupPaintForFont(hfont, &paint); + } if (didFill) { // If there is a shadow and we filled above, there will already be @@ -398,7 +403,7 @@ bool paintSkiaText(GraphicsContext* context, paint.setLooper(0); } - if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint, + if (!skiaDrawText(hfont, dc, platformContext, *origin, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs)) return false; } diff --git a/Source/WebCore/platform/graphics/skia/SkiaFontWin.h b/Source/WebCore/platform/graphics/skia/SkiaFontWin.h index 40bee62..33b4aaf 100644 --- a/Source/WebCore/platform/graphics/skia/SkiaFontWin.h +++ b/Source/WebCore/platform/graphics/skia/SkiaFontWin.h @@ -76,6 +76,10 @@ bool windowsCanHandleDrawTextShadow(GraphicsContext*); // Returns true if advanced font rendering is recommended. bool windowsCanHandleTextDrawing(GraphicsContext*); +// Returns true if advanced font rendering is recommended if shadows are +// disregarded. +bool windowsCanHandleTextDrawingWithoutShadow(GraphicsContext*); + // Note that the offsets parameter is optional. If not NULL it represents a // per glyph offset (such as returned by ScriptPlace Windows API function). // diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.h b/Source/WebCore/platform/graphics/transforms/AffineTransform.h index 14431aa..176c41e 100644 --- a/Source/WebCore/platform/graphics/transforms/AffineTransform.h +++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.h @@ -32,9 +32,9 @@ #include <string.h> // for memcpy #include <wtf/FastAllocBase.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGAffineTransform.h> -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include <cairo.h> #elif PLATFORM(OPENVG) #include "VGUtils.h" @@ -157,9 +157,9 @@ public: return result; } -#if PLATFORM(CG) +#if USE(CG) operator CGAffineTransform() const; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) operator cairo_matrix_t() const; #elif PLATFORM(OPENVG) operator VGMatrix() const; diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h index adda46b..ff668bb 100644 --- a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -31,12 +31,12 @@ #include <string.h> //for memcpy #include <wtf/FastAllocBase.h> -#if PLATFORM(CA) +#if USE(CA) typedef struct CATransform3D CATransform3D; #endif -#if PLATFORM(CG) +#if USE(CG) typedef struct CGAffineTransform CGAffineTransform; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include <cairo.h> #elif PLATFORM(OPENVG) #include "VGUtils.h" @@ -308,14 +308,14 @@ public: return result; } -#if PLATFORM(CA) +#if USE(CA) TransformationMatrix(const CATransform3D&); operator CATransform3D() const; #endif -#if PLATFORM(CG) +#if USE(CG) TransformationMatrix(const CGAffineTransform&); operator CGAffineTransform() const; -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) operator cairo_matrix_t() const; #elif PLATFORM(OPENVG) operator VGMatrix() const; diff --git a/Source/WebCore/platform/graphics/win/DIBPixelData.cpp b/Source/WebCore/platform/graphics/win/DIBPixelData.cpp new file mode 100644 index 0000000..e45ba06 --- /dev/null +++ b/Source/WebCore/platform/graphics/win/DIBPixelData.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 Brent Fulgham <bfulgham@webkit.org> + * + * 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 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 "DIBPixelData.h" + +namespace WebCore { + +static const WORD bitmapType = 0x4d42; // BMP format +static const WORD bitmapPixelsPerMeter = 2834; // 72 dpi + +DIBPixelData::DIBPixelData(HBITMAP bitmap) +{ + initialize(bitmap); +} + +void DIBPixelData::initialize(HBITMAP bitmap) +{ + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + + m_bitmapBuffer = reinterpret_cast<UInt8*>(bmpInfo.bmBits); + m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + m_size = IntSize(bmpInfo.bmWidth, bmpInfo.bmHeight); + m_bytesPerRow = bmpInfo.bmWidthBytes; + m_bitsPerPixel = bmpInfo.bmBitsPixel; +} + +#ifndef NDEBUG +void DIBPixelData::writeToFile(LPCWSTR filePath) +{ + HANDLE hFile = ::CreateFile(filePath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (INVALID_HANDLE_VALUE == hFile) + return; + + BITMAPFILEHEADER header; + header.bfType = bitmapType; + header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + header.bfReserved1 = 0; + header.bfReserved2 = 0; + header.bfSize = sizeof(BITMAPFILEHEADER); + + BITMAPINFOHEADER info; + info.biSize = sizeof(BITMAPINFOHEADER); + info.biWidth = m_size.width(); + info.biHeight = m_size.height(); + info.biPlanes = 1; + info.biBitCount = m_bitsPerPixel; + info.biCompression = BI_RGB; + info.biSizeImage = bufferLength(); + info.biXPelsPerMeter = bitmapPixelsPerMeter; + info.biYPelsPerMeter = bitmapPixelsPerMeter; + info.biClrUsed = 0; + info.biClrImportant = 0; + + DWORD bytesWritten = 0; + ::WriteFile(hFile, &header, sizeof(header), &bytesWritten, 0); + ::WriteFile(hFile, &info, sizeof(info), &bytesWritten, 0); + ::WriteFile(hFile, buffer(), bufferLength(), &bytesWritten, 0); + + ::CloseHandle(hFile); +} +#endif + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/win/DIBPixelData.h b/Source/WebCore/platform/graphics/win/DIBPixelData.h new file mode 100644 index 0000000..40afa2b --- /dev/null +++ b/Source/WebCore/platform/graphics/win/DIBPixelData.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011 Brent Fulgham <bfulgham@webkit.org> + * + * 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 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 DIBPixelData_h +#define DIBPixelData_h + +#include "IntSize.h" +#include <windows.h> + +#if !USE(CG) +// UInt8 is defined in CoreFoundation/CFBase.h +typedef unsigned char UInt8; +#endif + +namespace WebCore { + +class DIBPixelData { + public: + DIBPixelData() + : m_bitmapBuffer(0) + , m_bitmapBufferLength(0) + , m_bytesPerRow(0) + , m_bitsPerPixel(0) + { + } + DIBPixelData(HBITMAP); + + void initialize(HBITMAP); + +#ifndef NDEBUG + void writeToFile(LPCWSTR); +#endif + + UInt8* buffer() const { return m_bitmapBuffer; } + unsigned bufferLength() const { return m_bitmapBufferLength; } + const IntSize& size() const { return m_size; } + unsigned bytesPerRow() const { return m_bytesPerRow; } + unsigned short bitsPerPixel() const { return m_bitsPerPixel; } + + private: + UInt8* m_bitmapBuffer; + unsigned m_bitmapBufferLength; + IntSize m_size; + unsigned m_bytesPerRow; + unsigned short m_bitsPerPixel; +}; + +} // namespace WebCore + +#endif // DIBPixelData_h diff --git a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp index 5382ef7..46f6f11 100644 --- a/Source/WebCore/platform/graphics/win/FontCacheWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -36,7 +36,7 @@ #include <windows.h> #include <wtf/StdLibExtras.h> #include <wtf/text/StringHash.h> -#if PLATFORM(CG) +#if USE(CG) #include <ApplicationServices/ApplicationServices.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> #endif @@ -48,7 +48,7 @@ namespace WebCore void FontCache::platformInit() { -#if PLATFORM(CG) +#if USE(CG) wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac. #endif } @@ -471,7 +471,7 @@ static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool matchData.m_chosen.lfUnderline = false; matchData.m_chosen.lfStrikeOut = false; matchData.m_chosen.lfCharSet = DEFAULT_CHARSET; -#if PLATFORM(CG) || PLATFORM(CAIRO) +#if USE(CG) || USE(CAIRO) matchData.m_chosen.lfOutPrecision = OUT_TT_ONLY_PRECIS; #else matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS; @@ -581,9 +581,9 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), synthesizeBold, synthesizeItalic, useGDI); -#if PLATFORM(CG) +#if USE(CG) bool fontCreationFailed = !result->cgFont(); -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) bool fontCreationFailed = !result->scaledFont(); #endif diff --git a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp index 301198d..d0b37bd 100644 --- a/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp +++ b/Source/WebCore/platform/graphics/win/FontPlatformDataWin.cpp @@ -41,9 +41,9 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq , m_orientation(Horizontal) , m_textOrientation(TextOrientationVerticalRight) , m_widthVariant(RegularWidth) -#if PLATFORM(CG) +#if USE(CG) , m_cgFont(0) -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) , m_scaledFont(0) #endif , m_isColorBitmapFont(false) diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index d0bd4e9..cb0c9a7 100644 --- a/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/Source/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -40,25 +40,24 @@ namespace WebCore { static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha) { HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); - BITMAP info; - GetObject(bitmap, sizeof(info), &info); + DIBPixelData pixelData(bitmap); // FIXME: We can get here because we asked for a bitmap that is too big // when we have a tiled layer and we're compositing. In that case // bmBitsPixel will be 0. This seems to be benign, so for now we will // exit gracefully and look at it later: // https://bugs.webkit.org/show_bug.cgi?id=52041 - // ASSERT(info.bmBitsPixel == 32); - if (info.bmBitsPixel != 32) + // ASSERT(bitmapBits.bitsPerPixel() == 32); + if (pixelData.bitsPerPixel() != 32) return 0; CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | (hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst); - CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, - info.bmWidthBytes, deviceRGBColorSpaceRef(), bitmapInfo); + CGContextRef context = CGBitmapContextCreate(pixelData.buffer(), pixelData.size().width(), pixelData.size().height(), 8, + pixelData.bytesPerRow(), deviceRGBColorSpaceRef(), bitmapInfo); // Flip coords - CGContextTranslateCTM(context, 0, info.bmHeight); + CGContextTranslateCTM(context, 0, pixelData.size().height()); CGContextScaleCTM(context, 1, -1); // Put the HDC In advanced mode so it will honor affine transforms. @@ -99,16 +98,14 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo if (dstRect.isEmpty()) return; - HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + OwnPtr<HBITMAP> bitmap = adoptPtr(static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP))); + + DIBPixelData pixelData(bitmap.get()); - // Need to make a CGImage out of the bitmap's pixel buffer and then draw - // it into our context. - BITMAP info; - GetObject(bitmap, sizeof(info), &info); - ASSERT(info.bmBitsPixel == 32); + ASSERT(pixelData.bitsPerPixel() == 32); - CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, - info.bmWidthBytes, deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | + CGContextRef bitmapContext = CGBitmapContextCreate(pixelData.buffer(), pixelData.size().width(), pixelData.size().height(), 8, + pixelData.bytesPerRow(), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst)); CGImageRef image = CGBitmapContextCreateImage(bitmapContext); @@ -118,7 +115,6 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo CGImageRelease(image); CGContextRelease(bitmapContext); ::DeleteDC(hdc); - ::DeleteObject(bitmap); } void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point) diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 7ce7ee9..9f7aece 100644 --- a/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/Source/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -78,7 +78,7 @@ void GraphicsContext::platformInit(HDC dc, bool hasAlpha) else setPaintingDisabled(true); - m_data = new GraphicsContextPlatformPrivateTopLevel(new PlatformContextCairo(cr)); + m_data = new GraphicsContextPlatformPrivateToplevel(new PlatformContextCairo(cr)); m_data->m_hdc = dc; if (platformContext()->cr()) { // Make sure the context starts in sync with our state. @@ -93,6 +93,33 @@ static void setRGBABitmapAlpha(unsigned char* bytes, size_t length, unsigned cha bytes[i + 3] = level; } +static void drawBitmapToContext(GraphicsContextPlatformPrivate* context, cairo_t* cr, const DIBPixelData& pixelData, const IntSize& translate) +{ + // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw + // it into our context. + cairo_surface_t* surface = cairo_image_surface_create_for_data(pixelData.buffer(), + CAIRO_FORMAT_ARGB32, + pixelData.size().width(), + pixelData.size().height(), + pixelData.bytesPerRow()); + + // Flip the target surface so that when we set the srcImage as + // the surface it will draw right-side-up. + cairo_save(cr); + cairo_translate(cr, static_cast<double>(translate.width()), static_cast<double>(translate.height())); + cairo_scale(cr, 1, -1); + cairo_set_source_surface(cr, surface, 0, 0); + + if (context->layers.size()) + cairo_paint_with_alpha(cr, context->layers.last()); + else + cairo_paint(cr); + + // Delete all our junk. + cairo_surface_destroy(surface); + cairo_restore(cr); +} + void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer()); @@ -104,46 +131,26 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo if (dstRect.isEmpty()) return; - HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + OwnPtr<HBITMAP> bitmap = adoptPtr(static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP))); - BITMAP info; - GetObject(bitmap, sizeof(info), &info); - ASSERT(info.bmBitsPixel == 32); + DIBPixelData pixelData(bitmap.get()); + ASSERT(pixelData.bitsPerPixel() == 32); // If this context does not support alpha blending, then it may have // been drawn with GDI functions which always set the alpha channel // to zero. We need to manually set the bitmap to be fully opaque. - unsigned char* bytes = reinterpret_cast<unsigned char*>(info.bmBits); + unsigned char* bytes = reinterpret_cast<unsigned char*>(pixelData.buffer()); if (!supportAlphaBlend) - setRGBABitmapAlpha(bytes, info.bmHeight * info.bmWidthBytes, 255); + setRGBABitmapAlpha(bytes, pixelData.size().height() * pixelData.bytesPerRow(), 255); - // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw - // it into our context. - cairo_surface_t* image = cairo_image_surface_create_for_data(bytes, - CAIRO_FORMAT_ARGB32, - info.bmWidth, - info.bmHeight, - info.bmWidthBytes); - - // Scale the target surface to the new image size, and flip it - // so that when we set the srcImage as the surface it will draw - // right-side-up. - cairo_t* cr = platformContext()->cr(); - cairo_save(cr); - cairo_translate(cr, dstRect.x(), dstRect.height() + dstRect.y()); - cairo_scale(cr, 1, -1); - cairo_set_source_surface(cr, image, 0, 0); + drawBitmapToContext(m_data, platformContext()->cr(), pixelData, IntSize(dstRect.x(), dstRect.height() + dstRect.y())); - if (m_data->layers.size()) - cairo_paint_with_alpha(cr, m_data->layers.last()); - else - cairo_paint(cr); - - // Delete all our junk. - cairo_surface_destroy(image); ::DeleteDC(hdc); - ::DeleteObject(bitmap); - cairo_restore(cr); +} + +void GraphicsContext::drawWindowsBitmap(WindowsBitmap* bitmap, const IntPoint& point) +{ + drawBitmapToContext(m_data, platformContext()->cr(), bitmap->windowsDIB(), IntSize(point.x(), bitmap->size().height() + point.y())); } void GraphicsContextPlatformPrivate::syncContext(cairo_t* cr) diff --git a/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp index f2850e4..28ce55a 100644 --- a/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp +++ b/Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp @@ -26,9 +26,9 @@ #include "config.h" #include "GraphicsContext.h" -#if PLATFORM(CG) +#if USE(CG) #include "GraphicsContextPlatformPrivateCG.h" -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include "GraphicsContextPlatformPrivateCairo.h" #endif @@ -65,21 +65,20 @@ bool GraphicsContext::shouldIncludeChildWindows() const GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size) : m_hdc(0) - , m_size(size) { - BitmapInfo bitmapInfo = BitmapInfo::create(m_size); + BitmapInfo bitmapInfo = BitmapInfo::create(size); - m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&m_bitmapBuffer), 0, 0); + void* storage = 0; + m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &storage, 0, 0); if (!m_bitmap) return; m_hdc = CreateCompatibleDC(hdc); SelectObject(m_hdc, m_bitmap); - BITMAP bmpInfo; - GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo); - m_bytesPerRow = bmpInfo.bmWidthBytes; - m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + m_pixelData.initialize(m_bitmap); + + ASSERT(storage == m_pixelData.buffer()); SetGraphicsMode(m_hdc, GM_ADVANCED); } diff --git a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp index dd3cd32..588146a 100644 --- a/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp +++ b/Source/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp @@ -30,7 +30,7 @@ #include "WebCoreInstanceHandle.h" #include <windows.h> -#if PLATFORM(CG) +#if USE(CG) #include <CoreGraphics/CGColor.h> #endif diff --git a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index 323ff73..db730ca 100644 --- a/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/Source/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -39,7 +39,7 @@ #include <winsock2.h> #include <wtf/MathExtras.h> -#if PLATFORM(CG) +#if USE(CG) #include <ApplicationServices/ApplicationServices.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> #endif diff --git a/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp index 19683df..e501621 100644 --- a/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp +++ b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp @@ -1300,7 +1300,7 @@ void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rec } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { notImplemented(); return frect; diff --git a/Source/WebCore/platform/graphics/wince/ImageBufferData.h b/Source/WebCore/platform/graphics/wince/ImageBufferDataWince.h index cbd49dc..dd46d38 100644 --- a/Source/WebCore/platform/graphics/wince/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/wince/ImageBufferDataWince.h @@ -17,9 +17,6 @@ * Boston, MA 02110-1301, USA. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - #include "SharedBitmap.h" namespace WebCore { @@ -33,5 +30,3 @@ public: }; } // namespace WebCore - -#endif // ImageBufferData_h diff --git a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index 830cd05..3d98aeb 100644 --- a/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/Source/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -99,12 +99,14 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri ) )); #endif -#if OS(DARWIN) && !defined(wxOSX_USE_CORE_TEXT) +#if OS(DARWIN) +#if !wxOSX_USE_CORE_TEXT #if wxCHECK_VERSION(2,9,0) m_atsuFontID = m_font->font()->OSXGetATSUFontID(); #else m_atsuFontID = m_font->font()->MacGetATSUFontID(); #endif +#endif m_nsFont = 0; cacheNSFont(); #endif diff --git a/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 47f3211..071df47 100644 --- a/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/Source/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -416,7 +416,7 @@ void GraphicsContext::scale(const FloatSize& scale) } -FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) { FloatRect result; diff --git a/Source/WebCore/platform/graphics/wx/ImageBufferData.h b/Source/WebCore/platform/graphics/wx/ImageBufferDataWx.h index d4a6114..9961fee 100644 --- a/Source/WebCore/platform/graphics/wx/ImageBufferData.h +++ b/Source/WebCore/platform/graphics/wx/ImageBufferDataWx.h @@ -23,10 +23,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ImageBufferData_h -#define ImageBufferData_h - - #include "OwnPtr.h" namespace WebCore { @@ -38,6 +34,4 @@ public: ImageBufferData(const IntSize&); }; -} // namespace WebCore - -#endif // ImageBufferData_h +} // namespace WebCore |