diff options
Diffstat (limited to 'WebCore/platform/graphics')
252 files changed, 16880 insertions, 5188 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h index 807c11b..0031df6 100644 --- a/WebCore/platform/graphics/BitmapImage.h +++ b/WebCore/platform/graphics/BitmapImage.h @@ -45,6 +45,10 @@ class NSImage; typedef struct HBITMAP__ *HBITMAP; #endif +#if PLATFORM(HAIKU) +class BBitmap; +#endif + namespace WebCore { struct FrameData; } @@ -136,12 +140,15 @@ public: virtual CGImageRef getCGImageRef(); #endif +#if PLATFORM(WIN) || (PLATFORM(QT) && PLATFORM(WIN_OS)) + static PassRefPtr<BitmapImage> create(HBITMAP); +#endif #if PLATFORM(WIN) virtual bool getHBITMAP(HBITMAP); virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE); #endif -#if PLATFORM(SGL) +#if PLATFORM(ANDROID) virtual void setURL(const String& str); #endif @@ -162,13 +169,19 @@ protected: BitmapImage(ImageObserver* = 0); #if PLATFORM(WIN) - virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator); + virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator); #endif - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); -#if PLATFORM(WX) || PLATFORM(WINCE) + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); + +#if PLATFORM(WX) || (PLATFORM(WINCE) && !PLATFORM(QT)) virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); -#endif + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); +#endif + +#if PLATFORM(HAIKU) + virtual BBitmap* getBBitmap() const; +#endif + size_t currentFrame() const { return m_currentFrame; } size_t frameCount(); NativeImagePtr frameAtIndex(size_t); diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h index 5baa56e..c348166 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -26,6 +26,7 @@ #ifndef Color_h #define Color_h +#include <wtf/FastAllocBase.h> #include <wtf/Platform.h> #if PLATFORM(CG) @@ -47,6 +48,10 @@ typedef struct _GdkColor GdkColor; class wxColour; #endif +#if PLATFORM(HAIKU) +struct rgb_color; +#endif + namespace WebCore { class String; @@ -64,7 +69,7 @@ RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a); int differenceSquared(const Color&, const Color&); -class Color { +class Color : public FastAllocBase { public: Color() : m_color(0), m_valid(false) { } Color(RGBA32 col) : m_color(col), m_valid(true) { } @@ -121,6 +126,11 @@ public: Color(CGColorRef); #endif +#if PLATFORM(HAIKU) + Color(const rgb_color&); + operator rgb_color() const; +#endif + static bool parseHexColor(const String& name, RGBA32& rgb); static const RGBA32 black = 0xFF000000; diff --git a/WebCore/platform/graphics/ColorSpace.h b/WebCore/platform/graphics/ColorSpace.h new file mode 100644 index 0000000..1bad58c --- /dev/null +++ b/WebCore/platform/graphics/ColorSpace.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE 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 ColorSpace_h +#define ColorSpace_h + +namespace WebCore { + + enum ColorSpace { DeviceColorSpace, sRGBColorSpace }; + +} // namespace WebCore + +#endif // ColorSpace_h diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h index 0c97c49..45a1e83 100644 --- a/WebCore/platform/graphics/FloatPoint.h +++ b/WebCore/platform/graphics/FloatPoint.h @@ -36,7 +36,7 @@ typedef struct CGPoint CGPoint; #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES typedef struct CGPoint NSPoint; #else @@ -51,6 +51,10 @@ class QPointF; QT_END_NAMESPACE #endif +#if PLATFORM(HAIKU) +class BPoint; +#endif + #if PLATFORM(SKIA) struct SkPoint; #endif @@ -80,7 +84,8 @@ public: operator CGPoint() const; #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) FloatPoint(const NSPoint&); operator NSPoint() const; #endif @@ -90,7 +95,12 @@ public: operator QPointF() const; #endif -#if (PLATFORM(SKIA) || PLATFORM(SGL)) +#if PLATFORM(HAIKU) + FloatPoint(const BPoint&); + operator BPoint() const; +#endif + +#if PLATFORM(SKIA) operator SkPoint() const; FloatPoint(const SkPoint&); #endif diff --git a/WebCore/platform/graphics/FloatRect.cpp b/WebCore/platform/graphics/FloatRect.cpp index 532f719..7a54f21 100644 --- a/WebCore/platform/graphics/FloatRect.cpp +++ b/WebCore/platform/graphics/FloatRect.cpp @@ -102,12 +102,12 @@ void FloatRect::unite(const FloatRect& other) m_size.setHeight(b - t); } -void FloatRect::scale(float s) +void FloatRect::scale(float sx, float sy) { - m_location.setX(x() * s); - m_location.setY(y() * s); - m_size.setWidth(width() * s); - m_size.setHeight(height() * s); + m_location.setX(x() * sx); + m_location.setY(y() * sy); + m_size.setWidth(width() * sx); + m_size.setHeight(height() * sy); } IntRect enclosingIntRect(const FloatRect& rect) diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h index e906812..2dc854d 100644 --- a/WebCore/platform/graphics/FloatRect.h +++ b/WebCore/platform/graphics/FloatRect.h @@ -33,7 +33,7 @@ typedef struct CGRect CGRect; #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES typedef struct CGRect NSRect; #else @@ -51,7 +51,11 @@ QT_END_NAMESPACE class wxRect2DDouble; #endif -#if (PLATFORM(SKIA) || PLATFORM(SGL)) +#if PLATFORM(HAIKU) +class BRect; +#endif + +#if PLATFORM(SKIA) struct SkRect; #endif @@ -116,14 +120,16 @@ public: m_size.setHeight(m_size.height() + dy + dy); } void inflate(float d) { inflateX(d); inflateY(d); } - void scale(float s); + void scale(float s) { scale(s, s); } + void scale(float sx, float sy); #if PLATFORM(CG) FloatRect(const CGRect&); operator CGRect() const; #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) FloatRect(const NSRect&); operator NSRect() const; #endif @@ -138,7 +144,12 @@ public: operator wxRect2DDouble() const; #endif -#if (PLATFORM(SKIA) || PLATFORM(SGL)) +#if PLATFORM(HAIKU) + FloatRect(const BRect&); + operator BRect() const; +#endif + +#if PLATFORM(SKIA) FloatRect(const SkRect&); operator SkRect() const; #endif diff --git a/WebCore/platform/graphics/FloatSize.h b/WebCore/platform/graphics/FloatSize.h index 6e792b6..5a84fd1 100644 --- a/WebCore/platform/graphics/FloatSize.h +++ b/WebCore/platform/graphics/FloatSize.h @@ -34,7 +34,7 @@ typedef struct CGSize CGSize; #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES typedef struct CGSize NSSize; #else @@ -79,7 +79,8 @@ public: operator CGSize() const; #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) explicit FloatSize(const NSSize &); // don't do this implicitly since it's lossy operator NSSize() const; #endif diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h index 3c0f2d9..4a6222b 100644 --- a/WebCore/platform/graphics/FontCache.h +++ b/WebCore/platform/graphics/FontCache.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2008 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -49,7 +50,7 @@ class FontDescription; class FontSelector; class SimpleFontData; -class FontCache { +class FontCache : public Noncopyable { public: friend FontCache* fontCache(); @@ -63,7 +64,15 @@ public: // Also implemented by the platform. void platformInit(); -#if PLATFORM(WIN) +#if PLATFORM(WINCE) && !PLATFORM(QT) +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + IMLangFontLink2* getFontLinkInterface(); +#else + IMLangFontLink* getFontLinkInterface(); +#endif + static void comInitialize(); + static void comUninitialize(); +#elif PLATFORM(WIN) IMLangFontLink2* getFontLinkInterface(); #endif diff --git a/WebCore/platform/graphics/FontDescription.h b/WebCore/platform/graphics/FontDescription.h index c893b8a..fc63db9 100644 --- a/WebCore/platform/graphics/FontDescription.h +++ b/WebCore/platform/graphics/FontDescription.h @@ -27,7 +27,9 @@ #include "FontFamily.h" #include "FontRenderingMode.h" +#include "FontSmoothingMode.h" #include "FontTraitsMask.h" +#include "TextRenderingMode.h" namespace WebCore { @@ -61,6 +63,8 @@ public: , m_usePrinterFont(false) , m_renderingMode(NormalRenderingMode) , m_keywordSize(0) + , m_fontSmoothing(AutoSmoothing) + , m_textRendering(AutoTextRendering) { } @@ -80,8 +84,12 @@ public: FontWeight bolderWeight() const; GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); } bool usePrinterFont() const { return m_usePrinterFont; } + // only use fixed default size when there is only one font family, and that family is "monospace" + bool useFixedDefaultSize() const { return genericFamily() == MonospaceFamily && !family().next() && family().family() == "-webkit-monospace"; } FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); } unsigned keywordSize() const { return m_keywordSize; } + FontSmoothingMode fontSmoothing() const { return static_cast<FontSmoothingMode>(m_fontSmoothing); } + TextRenderingMode textRenderingMode() const { return static_cast<TextRenderingMode>(m_textRendering); } FontTraitsMask traitsMask() const; @@ -96,6 +104,8 @@ public: void setUsePrinterFont(bool p) { m_usePrinterFont = p; } void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; } void setKeywordSize(unsigned s) { m_keywordSize = s; } + void setFontSmoothing(FontSmoothingMode smoothing) { m_fontSmoothing = smoothing; } + void setTextRenderingMode(TextRenderingMode rendering) { m_textRendering = rendering; } private: FontFamily m_familyList; // The list of font families to be used. @@ -117,6 +127,9 @@ private: unsigned m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, // then we can accurately translate across different generic families to adjust for different preference settings // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>). + + unsigned m_fontSmoothing : 2; // FontSmoothingMode + unsigned m_textRendering : 2; // TextRenderingMode }; inline bool FontDescription::operator==(const FontDescription& other) const @@ -131,7 +144,9 @@ inline bool FontDescription::operator==(const FontDescription& other) const && m_genericFamily == other.m_genericFamily && m_usePrinterFont == other.m_usePrinterFont && m_renderingMode == other.m_renderingMode - && m_keywordSize == other.m_keywordSize; + && m_keywordSize == other.m_keywordSize + && m_fontSmoothing == other.m_fontSmoothing + && m_textRendering == other.m_textRendering; } } diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp index b0e39db..5246593 100644 --- a/WebCore/platform/graphics/FontFastPath.cpp +++ b/WebCore/platform/graphics/FontFastPath.cpp @@ -251,6 +251,10 @@ bool Font::canUseGlyphCache(const TextRun& run) const return false; } + TextRenderingMode textMode = m_fontDescription.textRenderingMode(); + if (textMode == OptimizeLegibility || textMode == GeometricPrecision) + return false; + return true; } diff --git a/WebCore/platform/graphics/FontSmoothingMode.h b/WebCore/platform/graphics/FontSmoothingMode.h new file mode 100644 index 0000000..7c23394 --- /dev/null +++ b/WebCore/platform/graphics/FontSmoothingMode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE 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 FontSmoothingMode_h +#define FontSmoothingMode_h + +namespace WebCore { + + enum FontSmoothingMode { AutoSmoothing, NoSmoothing, Antialiased, SubpixelAntialiased }; + +} // namespace WebCore + +#endif // FontSmoothingMode_h diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp index bac9da0..eec7ffb 100644 --- a/WebCore/platform/graphics/GeneratedImage.cpp +++ b/WebCore/platform/graphics/GeneratedImage.cpp @@ -34,7 +34,7 @@ using namespace std; namespace WebCore { -void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp) +void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp) { context->save(); context->setCompositeOperation(compositeOp); @@ -48,7 +48,7 @@ void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, co } void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { // Create a BitmapImage and call drawPattern on it. OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size); @@ -62,7 +62,7 @@ void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcR Image* bitmap = imageBuffer->image(); // Now just call drawTiled on that image. - bitmap->drawPattern(context, srcRect, patternTransform, phase, compositeOp, destRect); + bitmap->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, compositeOp, destRect); } } diff --git a/WebCore/platform/graphics/GeneratedImage.h b/WebCore/platform/graphics/GeneratedImage.h index dea0c54..a4583e3 100644 --- a/WebCore/platform/graphics/GeneratedImage.h +++ b/WebCore/platform/graphics/GeneratedImage.h @@ -57,9 +57,9 @@ public: virtual unsigned decodedSize() const { return 0; } protected: - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); GeneratedImage(PassRefPtr<Generator> generator, const IntSize& size) : m_generator(generator) diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp index 6419e0c..9f53f0b 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -202,8 +202,10 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu GlyphPage* pageToFill = m_page.get(); for (unsigned i = 0; i < numRanges; i++) { const FontDataRange& range = segmentedFontData->rangeAt(i); - int from = max(0, range.from() - static_cast<int>(start)); - int to = 1 + min(range.to() - static_cast<int>(start), static_cast<int>(GlyphPage::size) - 1); + // all this casting is to ensure all the parameters to min and max have the same type, + // to avoid ambiguous template parameter errors on Windows + int from = max(0, static_cast<int>(range.from()) - static_cast<int>(start)); + int to = 1 + min(static_cast<int>(range.to()) - static_cast<int>(start), static_cast<int>(GlyphPage::size) - 1); if (from < static_cast<int>(GlyphPage::size) && to > 0) { if (haveGlyphs && !scratchPage) { scratchPage = GlyphPage::create(this); diff --git a/WebCore/platform/graphics/Gradient.cpp b/WebCore/platform/graphics/Gradient.cpp index 77a0d21..204a2b6 100644 --- a/WebCore/platform/graphics/Gradient.cpp +++ b/WebCore/platform/graphics/Gradient.cpp @@ -161,7 +161,7 @@ void Gradient::setGradientSpaceTransform(const TransformationMatrix& gradientSpa setPlatformGradientSpaceTransform(gradientSpaceTransformation); } -#if !PLATFORM(SKIA) +#if !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) void Gradient::setPlatformGradientSpaceTransform(const TransformationMatrix&) { } diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h index 7f01251..011a2cd 100644 --- a/WebCore/platform/graphics/Gradient.h +++ b/WebCore/platform/graphics/Gradient.h @@ -46,13 +46,15 @@ typedef QGradient* PlatformGradient; #elif PLATFORM(CAIRO) typedef struct _cairo_pattern cairo_pattern_t; typedef cairo_pattern_t* PlatformGradient; -#elif PLATFORM(ANDROID) && PLATFORM(SGL) +#elif PLATFORM(SKIA) +#if PLATFORM(ANDROID) #include "SkShader.h" typedef class PlatformGradientRec* PlatformGradient; -#elif PLATFORM(SKIA) +#else class SkShader; typedef class SkShader* PlatformGradient; typedef class SkShader* PlatformPattern; +#endif #else typedef void* PlatformGradient; #endif @@ -86,13 +88,11 @@ namespace WebCore { struct ColorStop; const Vector<ColorStop>& getStops() const; #else - -#if PLATFORM(ANDROID) && PLATFORM(SGL) +#if PLATFORM(ANDROID) SkShader* getShader(SkShader::TileMode); #endif PlatformGradient platformGradient(); #endif - struct ColorStop { float stop; float red; diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index a4e8408..e80004f 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -27,9 +27,9 @@ #include "GraphicsContext.h" #include "BidiResolver.h" +#include "Font.h" #include "Generator.h" #include "GraphicsContextPrivate.h" -#include "Font.h" using namespace std; @@ -89,7 +89,7 @@ void GraphicsContext::save() return; m_common->stack.append(m_common->state); - + savePlatformState(); } @@ -104,7 +104,7 @@ void GraphicsContext::restore() } m_common->state = m_common->stack.last(); m_common->stack.removeLast(); - + restorePlatformState(); } @@ -120,24 +120,21 @@ void GraphicsContext::setStrokeStyle(const StrokeStyle& style) setPlatformStrokeStyle(style); } -void GraphicsContext::setStrokeColor(const Color& color) +void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace) { - m_common->state.strokeColorSpace = SolidColorSpace; m_common->state.strokeColor = color; - setPlatformStrokeColor(color); -} - -ColorSpace GraphicsContext::strokeColorSpace() const -{ - return m_common->state.strokeColorSpace; + m_common->state.strokeColorSpace = colorSpace; + m_common->state.strokeGradient.clear(); + m_common->state.strokePattern.clear(); + setPlatformStrokeColor(color, colorSpace); } -void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color) +void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace) { m_common->state.shadowSize = size; m_common->state.shadowBlur = blur; m_common->state.shadowColor = color; - setPlatformShadow(size, blur, color); + setPlatformShadow(size, blur, color, colorSpace); } void GraphicsContext::clearShadow() @@ -172,6 +169,11 @@ Color GraphicsContext::strokeColor() const return m_common->state.strokeColor; } +ColorSpace GraphicsContext::strokeColorSpace() const +{ + return m_common->state.strokeColorSpace; +} + WindRule GraphicsContext::fillRule() const { return m_common->state.fillRule; @@ -182,11 +184,13 @@ void GraphicsContext::setFillRule(WindRule fillRule) m_common->state.fillRule = fillRule; } -void GraphicsContext::setFillColor(const Color& color) +void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace) { - m_common->state.fillColorSpace = SolidColorSpace; m_common->state.fillColor = color; - setPlatformFillColor(color); + m_common->state.fillColorSpace = colorSpace; + m_common->state.fillGradient.clear(); + m_common->state.fillPattern.clear(); + setPlatformFillColor(color, colorSpace); } Color GraphicsContext::fillColor() const @@ -194,6 +198,11 @@ Color GraphicsContext::fillColor() const return m_common->state.fillColor; } +ColorSpace GraphicsContext::fillColorSpace() const +{ + return m_common->state.fillColorSpace; +} + void GraphicsContext::setShouldAntialias(bool b) { m_common->state.shouldAntialias = b; @@ -209,10 +218,10 @@ void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); if (!pattern) { - setStrokeColor(Color::black); + setStrokeColor(Color::black, DeviceColorSpace); return; } - m_common->state.strokeColorSpace = PatternColorSpace; + m_common->state.strokeGradient.clear(); m_common->state.strokePattern = pattern; setPlatformStrokePattern(m_common->state.strokePattern.get()); } @@ -221,10 +230,10 @@ void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); if (!pattern) { - setFillColor(Color::black); + setFillColor(Color::black, DeviceColorSpace); return; } - m_common->state.fillColorSpace = PatternColorSpace; + m_common->state.fillGradient.clear(); m_common->state.fillPattern = pattern; setPlatformFillPattern(m_common->state.fillPattern.get()); } @@ -233,11 +242,11 @@ void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) { ASSERT(gradient); if (!gradient) { - setStrokeColor(Color::black); + setStrokeColor(Color::black, DeviceColorSpace); return; } - m_common->state.strokeColorSpace = GradientColorSpace; m_common->state.strokeGradient = gradient; + m_common->state.strokePattern.clear(); setPlatformStrokeGradient(m_common->state.strokeGradient.get()); } @@ -245,11 +254,11 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) { ASSERT(gradient); if (!gradient) { - setFillColor(Color::black); + setFillColor(Color::black, DeviceColorSpace); return; } - m_common->state.fillColorSpace = GradientColorSpace; m_common->state.fillGradient = gradient; + m_common->state.fillPattern.clear(); setPlatformFillGradient(m_common->state.fillGradient.get()); } @@ -258,11 +267,6 @@ Gradient* GraphicsContext::fillGradient() const return m_common->state.fillGradient.get(); } -ColorSpace GraphicsContext::fillColorSpace() const -{ - return m_common->state.fillColorSpace; -} - Gradient* GraphicsContext::strokeGradient() const { return m_common->state.strokeGradient.get(); @@ -304,24 +308,24 @@ bool GraphicsContext::paintingDisabled() const return m_common->state.paintingDisabled; } -void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op) -{ - drawImage(image, p, IntRect(0, 0, -1, -1), op); +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op) +{ + drawImage(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op); } -void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale) { - drawImage(image, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); + drawImage(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); } -void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) { - drawImage(image, IntRect(dest, srcRect.size()), srcRect, op); + drawImage(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op); } -void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) { - drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale); + drawImage(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale); } #if !PLATFORM(WINCE) || PLATFORM(QT) @@ -329,7 +333,7 @@ void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPo { if (paintingDisabled()) return; - + font.drawText(this, run, point, from, to); } #endif @@ -370,12 +374,12 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F bidiResolver.deleteRuns(); } -void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to) +void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to) { if (paintingDisabled()) return; - fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor); + fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace); } void GraphicsContext::initFocusRing(int width, int offset) @@ -383,7 +387,7 @@ void GraphicsContext::initFocusRing(int width, int offset) if (paintingDisabled()) return; clearFocusRing(); - + m_common->m_focusRingWidth = width; m_common->m_focusRingOffset = offset; } @@ -396,12 +400,12 @@ void GraphicsContext::clearFocusRing() IntRect GraphicsContext::focusRingBoundingRect() { IntRect result = IntRect(0, 0, 0, 0); - + const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); for (unsigned i = 0; i < rectCount; i++) result.unite(rects[i]); - + return result; } @@ -427,7 +431,7 @@ const Vector<IntRect>& GraphicsContext::focusRingRects() const return m_common->m_focusRingRects; } -void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) { if (paintingDisabled() || !image) return; @@ -436,7 +440,7 @@ void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const Float float tsh = src.height(); float tw = dest.width(); float th = dest.height(); - + if (tsw == -1) tsw = image->width(); if (tsh == -1) @@ -451,29 +455,29 @@ void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const Float save(); setImageInterpolationQuality(InterpolationNone); } - image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op); + image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op); if (useLowQualityScale) restore(); } -void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op) +void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op) { if (paintingDisabled() || !image) return; - image->drawTiled(this, rect, srcPoint, tileSize, op); + image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op); } -void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) +void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) { if (paintingDisabled() || !image) return; if (hRule == Image::StretchTile && vRule == Image::StretchTile) // Just do a scale. - return drawImage(image, dest, srcRect, op); + return drawImage(image, styleColorSpace, dest, srcRect, op); - image->drawTiled(this, dest, srcRect, hRule, vRule, op); + image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op); } void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, @@ -514,7 +518,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator) generator.fill(this, rect); } -#if !PLATFORM(SKIA) +#if !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) void GraphicsContext::setPlatformFillGradient(Gradient*) { } @@ -532,7 +536,7 @@ void GraphicsContext::setPlatformStrokePattern(Pattern*) } #endif -#if !PLATFORM(CG) && !PLATFORM(SKIA) +#if !PLATFORM(CG) && !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) // Implement this if you want to go ahead and push the drawing mode into your native context // immediately. void GraphicsContext::setPlatformTextDrawingMode(int mode) @@ -540,10 +544,39 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode) } #endif -#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA) +#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !(PLATFORM(SKIA) && !PLATFORM(ANDROID)) && !PLATFORM(HAIKU) void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&) { } #endif +void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle& penStyle) +{ + // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic + // works out. For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g., + // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave + // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. + if (penStyle == DottedStroke || penStyle == DashedStroke) { + if (p1.x() == p2.x()) { + p1.setY(p1.y() + strokeWidth); + p2.setY(p2.y() - strokeWidth); + } else { + p1.setX(p1.x() + strokeWidth); + p2.setX(p2.x() - strokeWidth); + } + } + + if (static_cast<int>(strokeWidth) % 2) { //odd + if (p1.x() == p2.x()) { + // We're a vertical line. Adjust our x. + p1.setX(p1.x() + 0.5f); + p2.setX(p2.x() + 0.5f); + } else { + // We're a horizontal line. Adjust our y. + p1.setY(p1.y() + 0.5f); + p2.setY(p2.y() + 0.5f); + } + } +} + } diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index b52344d..ecf2101 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008-2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without @@ -27,6 +27,7 @@ #ifndef GraphicsContext_h #define GraphicsContext_h +#include "ColorSpace.h" #include "DashArray.h" #include "FloatRect.h" #include "Image.h" @@ -45,18 +46,12 @@ QT_BEGIN_NAMESPACE class QPainter; QT_END_NAMESPACE typedef QPainter PlatformGraphicsContext; -#elif PLATFORM(SGL) -namespace WebCore { -class PlatformGraphicsContext; -} -class SkPaint; -struct SkPoint; #elif PLATFORM(WX) class wxGCDC; class wxWindowDC; -// wxGraphicsContext allows us to support Path, etc. -// but on some platforms, e.g. Linux, it requires fairly +// wxGraphicsContext allows us to support Path, etc. +// but on some platforms, e.g. Linux, it requires fairly // new software. #if USE(WXGC) // On OS X, wxGCDC is just a typedef for wxDC, so use wxDC explicitly to make @@ -71,7 +66,19 @@ class wxWindowDC; typedef wxWindowDC PlatformGraphicsContext; #endif #elif PLATFORM(SKIA) +#if PLATFORM(ANDROID) +namespace WebCore { +class PlatformGraphicsContext; +} +class SkPaint; +struct SkPoint; +#else typedef class PlatformContextSkia PlatformGraphicsContext; +#endif +#elif PLATFORM(HAIKU) +class BView; +typedef BView PlatformGraphicsContext; +struct pattern; #elif PLATFORM(WINCE) typedef struct HDC__ PlatformGraphicsContext; #else @@ -107,24 +114,24 @@ namespace WebCore { const int cMisspellingLinePatternWidth = 4; const int cMisspellingLinePatternGapWidth = 1; - class TransformationMatrix; class Font; class Generator; class Gradient; - class GraphicsContextPrivate; class GraphicsContextPlatformPrivate; + class GraphicsContextPrivate; class ImageBuffer; class KURL; class Path; class Pattern; class TextRun; + class TransformationMatrix; // These bits can be ORed together for a total of 8 possible text drawing modes. const int cTextInvisible = 0; const int cTextFill = 1; const int cTextStroke = 2; const int cTextClip = 4; - + enum StrokeStyle { NoStroke, SolidStroke, @@ -132,18 +139,6 @@ namespace WebCore { DashedStroke }; -// FIXME: This is a place-holder until we decide to add -// real color space support to WebCore. At that time, ColorSpace will be a -// class and instances will be held off of Colors. There will be -// special singleton Gradient and Pattern color spaces to mark when -// a fill or stroke is using a gradient or pattern instead of a solid color. -// https://bugs.webkit.org/show_bug.cgi?id=20558 - enum ColorSpace { - SolidColorSpace, - PatternColorSpace, - GradientColorSpace - }; - enum InterpolationQuality { InterpolationDefault, InterpolationNone, @@ -156,19 +151,18 @@ namespace WebCore { public: GraphicsContext(PlatformGraphicsContext*); ~GraphicsContext(); - + #if !PLATFORM(WINCE) || PLATFORM(QT) PlatformGraphicsContext* platformContext() const; #endif - + float strokeThickness() const; void setStrokeThickness(float); StrokeStyle strokeStyle() const; void setStrokeStyle(const StrokeStyle& style); Color strokeColor() const; - void setStrokeColor(const Color&); - ColorSpace strokeColorSpace() const; + void setStrokeColor(const Color&, ColorSpace); void setStrokePattern(PassRefPtr<Pattern>); Pattern* strokePattern() const; @@ -179,7 +173,8 @@ namespace WebCore { WindRule fillRule() const; void setFillRule(WindRule); Color fillColor() const; - void setFillColor(const Color&); + ColorSpace fillColorSpace() const; + void setFillColor(const Color&, ColorSpace); void setFillPattern(PassRefPtr<Pattern>); Pattern* fillPattern() const; @@ -187,8 +182,6 @@ namespace WebCore { void setFillGradient(PassRefPtr<Gradient>); Gradient* fillGradient() const; - ColorSpace fillColorSpace() const; - void setShadowsIgnoreTransforms(bool); void setShouldAntialias(bool); @@ -199,11 +192,9 @@ namespace WebCore { void applyFillPattern(); #endif -#if PLATFORM(SGL) - /* these should be pused to apple. needed for CanvasStyle.cpp */ - void setCMYKAFillColor(float c, float m, float y, float k, float a); - void setCMYKAStrokeColor(float c, float m, float y, float k, float a); - +#if PLATFORM(ANDROID) + // initialize a paint for bitmaps + void setupBitmapPaint(SkPaint*); // initialize a paint for filling void setupFillPaint(SkPaint*); // initialize a paint for stroking @@ -215,7 +206,7 @@ namespace WebCore { bool willFill() const; // returns true if there is a valid (non-transparent) stroke color bool willStroke() const; - + // may return NULL, since we lazily allocate the path. This is the path // that is drawn by drawPath() const SkPath* getCurrPath() const; @@ -248,24 +239,24 @@ namespace WebCore { void strokeArc(const IntRect&, int startAngle, int angleSpan); void fillRect(const FloatRect&); - void fillRect(const FloatRect&, const Color&); + void fillRect(const FloatRect&, const Color&, ColorSpace); void fillRect(const FloatRect&, Generator&); - void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&); + void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&, ColorSpace); void clearRect(const FloatRect&); void strokeRect(const FloatRect&); void strokeRect(const FloatRect&, float lineWidth); - void drawImage(Image*, const IntPoint&, CompositeOperator = CompositeSourceOver); - void drawImage(Image*, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawImage(Image*, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver); - void drawImage(Image*, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), + void drawImage(Image*, ColorSpace styleColorSpace, const IntPoint&, CompositeOperator = CompositeSourceOver); + void drawImage(Image*, ColorSpace styleColorSpace, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(Image*, ColorSpace styleColorSpace, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver); + void drawImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(Image*, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, + void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator = CompositeSourceOver); - void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, + void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect, Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile, CompositeOperator = CompositeSourceOver); @@ -286,23 +277,23 @@ namespace WebCore { void drawText(const Font&, const TextRun&, const IntPoint&, int from = 0, int to = -1); void drawBidiText(const Font&, const TextRun&, const FloatPoint&); - void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1); + void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1); FloatRect roundToDevicePixels(const FloatRect&); - + void drawLineForText(const IntPoint&, int width, bool printing); void drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar); - + bool paintingDisabled() const; void setPaintingDisabled(bool); - + bool updatingControlTints() const; void setUpdatingControlTints(bool); void beginTransparencyLayer(float opacity); void endTransparencyLayer(); - void setShadow(const IntSize&, int blur, const Color&); + void setShadow(const IntSize&, int blur, const Color&, ColorSpace); bool getShadow(IntSize&, int&, Color&) const; void clearShadow(); @@ -320,6 +311,8 @@ namespace WebCore { void setAlpha(float); #if PLATFORM(CAIRO) float getAlpha(); + void createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize); + static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const IntSize& shadowSize, int shadowBlur); #endif void setCompositeOperation(CompositeOperator); @@ -328,13 +321,18 @@ namespace WebCore { void addPath(const Path&); void clip(const Path&); + + // This clip function is used only by <canvas> code. It allows + // implementations to handle clipping on the canvas differently since + // the disipline is different. + void canvasClip(const Path&); void clipOut(const Path&); void scale(const FloatSize&); void rotate(float angleInRadians); void translate(float x, float y); IntPoint origin(); - + void setURLForRect(const KURL&, const IntRect&); void concatCTM(const TransformationMatrix&); @@ -398,12 +396,16 @@ namespace WebCore { void drawWindowsBitmap(WindowsBitmap*, const IntPoint&); #endif -#if PLATFORM(QT) && defined(Q_WS_WIN) +#if (PLATFORM(QT) && defined(Q_WS_WIN)) || (PLATFORM(WX) && PLATFORM(WIN_OS)) HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); bool shouldIncludeChildWindows() const { return false; } #endif +#if PLATFORM(WX) + bool inTransparencyLayer() const { return false; } +#endif + #if PLATFORM(QT) bool inTransparencyLayer() const; PlatformPath* currentPath(); @@ -416,6 +418,10 @@ namespace WebCore { GdkEventExpose* gdkExposeEvent() const; #endif +#if PLATFORM(HAIKU) + pattern getHaikuStrokeStyle(); +#endif + private: void savePlatformState(); void restorePlatformState(); @@ -423,21 +429,23 @@ namespace WebCore { void setPlatformTextDrawingMode(int); void setPlatformFont(const Font& font); - void setPlatformStrokeColor(const Color&); + void setPlatformStrokeColor(const Color&, ColorSpace); void setPlatformStrokeStyle(const StrokeStyle&); void setPlatformStrokeThickness(float); void setPlatformStrokeGradient(Gradient*); void setPlatformStrokePattern(Pattern*); - void setPlatformFillColor(const Color&); + void setPlatformFillColor(const Color&, ColorSpace); void setPlatformFillGradient(Gradient*); void setPlatformFillPattern(Pattern*); void setPlatformShouldAntialias(bool b); - void setPlatformShadow(const IntSize&, int blur, const Color&); + void setPlatformShadow(const IntSize&, int blur, const Color&, ColorSpace); void clearPlatformShadow(); + static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle&); + int focusRingWidth() const; int focusRingOffset() const; const Vector<IntRect>& focusRingRects() const; @@ -452,4 +460,3 @@ namespace WebCore { } // namespace WebCore #endif // GraphicsContext_h - diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h new file mode 100644 index 0000000..aad8dd4 --- /dev/null +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -0,0 +1,650 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GraphicsContext3D_h +#define GraphicsContext3D_h + +#include "PlatformString.h" + +#include <wtf/ListHashSet.h> +#include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> + +// FIXME: Find a better way to avoid the name confliction for NO_ERROR. +#if PLATFORM(CHROMIUM) && PLATFORM(WIN_OS) +#undef NO_ERROR +#endif + +#if PLATFORM(MAC) +#include <OpenGL/OpenGL.h> + +typedef void* PlatformGraphicsContext3D; +const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; +typedef GLuint Platform3DObject; +const Platform3DObject NullPlatform3DObject = 0; +#else +typedef void* PlatformGraphicsContext3D; +const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; +typedef int Platform3DObject; +const Platform3DObject NullPlatform3DObject = 0; +#endif + +namespace WebCore { + class WebGLActiveInfo; + class WebGLArray; + class WebGLBuffer; + class WebGLUnsignedByteArray; + class WebGLFloatArray; + class WebGLFramebuffer; + class WebGLIntArray; + class WebGLProgram; + class WebGLRenderbuffer; + class WebGLRenderingContext; + class WebGLShader; + class WebGLTexture; + class Image; + class HTMLVideoElement; + class ImageData; + class WebKitCSSMatrix; + + struct ActiveInfo { + String name; + unsigned type; + int size; + }; + + // FIXME: ideally this would be used on all platforms. +#if PLATFORM(CHROMIUM) + class GraphicsContext3DInternal; +#endif + + class GraphicsContext3D : public Noncopyable { + public: + enum WebGLEnumType { + DEPTH_BUFFER_BIT = 0x00000100, + STENCIL_BUFFER_BIT = 0x00000400, + COLOR_BUFFER_BIT = 0x00004000, + POINTS = 0x0000, + LINES = 0x0001, + LINE_LOOP = 0x0002, + LINE_STRIP = 0x0003, + TRIANGLES = 0x0004, + TRIANGLE_STRIP = 0x0005, + TRIANGLE_FAN = 0x0006, + ZERO = 0, + ONE = 1, + SRC_COLOR = 0x0300, + ONE_MINUS_SRC_COLOR = 0x0301, + SRC_ALPHA = 0x0302, + ONE_MINUS_SRC_ALPHA = 0x0303, + DST_ALPHA = 0x0304, + ONE_MINUS_DST_ALPHA = 0x0305, + DST_COLOR = 0x0306, + ONE_MINUS_DST_COLOR = 0x0307, + SRC_ALPHA_SATURATE = 0x0308, + FUNC_ADD = 0x8006, + BLEND_EQUATION = 0x8009, + BLEND_EQUATION_RGB = 0x8009, + BLEND_EQUATION_ALPHA = 0x883D, + FUNC_SUBTRACT = 0x800A, + FUNC_REVERSE_SUBTRACT = 0x800B, + BLEND_DST_RGB = 0x80C8, + BLEND_SRC_RGB = 0x80C9, + BLEND_DST_ALPHA = 0x80CA, + BLEND_SRC_ALPHA = 0x80CB, + CONSTANT_COLOR = 0x8001, + ONE_MINUS_CONSTANT_COLOR = 0x8002, + CONSTANT_ALPHA = 0x8003, + ONE_MINUS_CONSTANT_ALPHA = 0x8004, + BLEND_COLOR = 0x8005, + ARRAY_BUFFER = 0x8892, + ELEMENT_ARRAY_BUFFER = 0x8893, + ARRAY_BUFFER_BINDING = 0x8894, + ELEMENT_ARRAY_BUFFER_BINDING = 0x8895, + STREAM_DRAW = 0x88E0, + STATIC_DRAW = 0x88E4, + DYNAMIC_DRAW = 0x88E8, + BUFFER_SIZE = 0x8764, + BUFFER_USAGE = 0x8765, + CURRENT_VERTEX_ATTRIB = 0x8626, + FRONT = 0x0404, + BACK = 0x0405, + FRONT_AND_BACK = 0x0408, + TEXTURE_2D = 0x0DE1, + CULL_FACE = 0x0B44, + BLEND = 0x0BE2, + DITHER = 0x0BD0, + STENCIL_TEST = 0x0B90, + DEPTH_TEST = 0x0B71, + SCISSOR_TEST = 0x0C11, + POLYGON_OFFSET_FILL = 0x8037, + SAMPLE_ALPHA_TO_COVERAGE = 0x809E, + SAMPLE_COVERAGE = 0x80A0, + NO_ERROR = 0, + INVALID_ENUM = 0x0500, + INVALID_VALUE = 0x0501, + INVALID_OPERATION = 0x0502, + OUT_OF_MEMORY = 0x0505, + CW = 0x0900, + CCW = 0x0901, + LINE_WIDTH = 0x0B21, + ALIASED_POINT_SIZE_RANGE = 0x846D, + ALIASED_LINE_WIDTH_RANGE = 0x846E, + CULL_FACE_MODE = 0x0B45, + FRONT_FACE = 0x0B46, + DEPTH_RANGE = 0x0B70, + DEPTH_WRITEMASK = 0x0B72, + DEPTH_CLEAR_VALUE = 0x0B73, + DEPTH_FUNC = 0x0B74, + STENCIL_CLEAR_VALUE = 0x0B91, + STENCIL_FUNC = 0x0B92, + STENCIL_FAIL = 0x0B94, + STENCIL_PASS_DEPTH_FAIL = 0x0B95, + STENCIL_PASS_DEPTH_PASS = 0x0B96, + STENCIL_REF = 0x0B97, + STENCIL_VALUE_MASK = 0x0B93, + STENCIL_WRITEMASK = 0x0B98, + STENCIL_BACK_FUNC = 0x8800, + STENCIL_BACK_FAIL = 0x8801, + STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802, + STENCIL_BACK_PASS_DEPTH_PASS = 0x8803, + STENCIL_BACK_REF = 0x8CA3, + STENCIL_BACK_VALUE_MASK = 0x8CA4, + STENCIL_BACK_WRITEMASK = 0x8CA5, + VIEWPORT = 0x0BA2, + SCISSOR_BOX = 0x0C10, + COLOR_CLEAR_VALUE = 0x0C22, + COLOR_WRITEMASK = 0x0C23, + UNPACK_ALIGNMENT = 0x0CF5, + PACK_ALIGNMENT = 0x0D05, + MAX_TEXTURE_SIZE = 0x0D33, + MAX_VIEWPORT_DIMS = 0x0D3A, + SUBPIXEL_BITS = 0x0D50, + RED_BITS = 0x0D52, + GREEN_BITS = 0x0D53, + BLUE_BITS = 0x0D54, + ALPHA_BITS = 0x0D55, + DEPTH_BITS = 0x0D56, + STENCIL_BITS = 0x0D57, + POLYGON_OFFSET_UNITS = 0x2A00, + POLYGON_OFFSET_FACTOR = 0x8038, + TEXTURE_BINDING_2D = 0x8069, + SAMPLE_BUFFERS = 0x80A8, + SAMPLES = 0x80A9, + SAMPLE_COVERAGE_VALUE = 0x80AA, + SAMPLE_COVERAGE_INVERT = 0x80AB, + NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2, + COMPRESSED_TEXTURE_FORMATS = 0x86A3, + DONT_CARE = 0x1100, + FASTEST = 0x1101, + NICEST = 0x1102, + GENERATE_MIPMAP_HINT = 0x8192, + BYTE = 0x1400, + UNSIGNED_BYTE = 0x1401, + SHORT = 0x1402, + UNSIGNED_SHORT = 0x1403, + INT = 0x1404, + UNSIGNED_INT = 0x1405, + FLOAT = 0x1406, + FIXED = 0x140C, + DEPTH_COMPONENT = 0x1902, + ALPHA = 0x1906, + RGB = 0x1907, + RGBA = 0x1908, + LUMINANCE = 0x1909, + LUMINANCE_ALPHA = 0x190A, + UNSIGNED_SHORT_4_4_4_4 = 0x8033, + UNSIGNED_SHORT_5_5_5_1 = 0x8034, + UNSIGNED_SHORT_5_6_5 = 0x8363, + FRAGMENT_SHADER = 0x8B30, + VERTEX_SHADER = 0x8B31, + MAX_VERTEX_ATTRIBS = 0x8869, + MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB, + MAX_VARYING_VECTORS = 0x8DFC, + MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D, + MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C, + MAX_TEXTURE_IMAGE_UNITS = 0x8872, + MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD, + SHADER_TYPE = 0x8B4F, + DELETE_STATUS = 0x8B80, + LINK_STATUS = 0x8B82, + VALIDATE_STATUS = 0x8B83, + ATTACHED_SHADERS = 0x8B85, + ACTIVE_UNIFORMS = 0x8B86, + ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87, + ACTIVE_ATTRIBUTES = 0x8B89, + ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A, + SHADING_LANGUAGE_VERSION = 0x8B8C, + CURRENT_PROGRAM = 0x8B8D, + NEVER = 0x0200, + LESS = 0x0201, + EQUAL = 0x0202, + LEQUAL = 0x0203, + GREATER = 0x0204, + NOTEQUAL = 0x0205, + GEQUAL = 0x0206, + ALWAYS = 0x0207, + KEEP = 0x1E00, + REPLACE = 0x1E01, + INCR = 0x1E02, + DECR = 0x1E03, + INVERT = 0x150A, + INCR_WRAP = 0x8507, + DECR_WRAP = 0x8508, + VENDOR = 0x1F00, + RENDERER = 0x1F01, + VERSION = 0x1F02, + EXTENSIONS = 0x1F03, + NEAREST = 0x2600, + LINEAR = 0x2601, + NEAREST_MIPMAP_NEAREST = 0x2700, + LINEAR_MIPMAP_NEAREST = 0x2701, + NEAREST_MIPMAP_LINEAR = 0x2702, + LINEAR_MIPMAP_LINEAR = 0x2703, + TEXTURE_MAG_FILTER = 0x2800, + TEXTURE_MIN_FILTER = 0x2801, + TEXTURE_WRAP_S = 0x2802, + TEXTURE_WRAP_T = 0x2803, + TEXTURE = 0x1702, + TEXTURE_CUBE_MAP = 0x8513, + TEXTURE_BINDING_CUBE_MAP = 0x8514, + TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515, + TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516, + TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517, + TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518, + TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519, + TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A, + MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C, + TEXTURE0 = 0x84C0, + TEXTURE1 = 0x84C1, + TEXTURE2 = 0x84C2, + TEXTURE3 = 0x84C3, + TEXTURE4 = 0x84C4, + TEXTURE5 = 0x84C5, + TEXTURE6 = 0x84C6, + TEXTURE7 = 0x84C7, + TEXTURE8 = 0x84C8, + TEXTURE9 = 0x84C9, + TEXTURE10 = 0x84CA, + TEXTURE11 = 0x84CB, + TEXTURE12 = 0x84CC, + TEXTURE13 = 0x84CD, + TEXTURE14 = 0x84CE, + TEXTURE15 = 0x84CF, + TEXTURE16 = 0x84D0, + TEXTURE17 = 0x84D1, + TEXTURE18 = 0x84D2, + TEXTURE19 = 0x84D3, + TEXTURE20 = 0x84D4, + TEXTURE21 = 0x84D5, + TEXTURE22 = 0x84D6, + TEXTURE23 = 0x84D7, + TEXTURE24 = 0x84D8, + TEXTURE25 = 0x84D9, + TEXTURE26 = 0x84DA, + TEXTURE27 = 0x84DB, + TEXTURE28 = 0x84DC, + TEXTURE29 = 0x84DD, + TEXTURE30 = 0x84DE, + TEXTURE31 = 0x84DF, + ACTIVE_TEXTURE = 0x84E0, + REPEAT = 0x2901, + CLAMP_TO_EDGE = 0x812F, + MIRRORED_REPEAT = 0x8370, + FLOAT_VEC2 = 0x8B50, + FLOAT_VEC3 = 0x8B51, + FLOAT_VEC4 = 0x8B52, + INT_VEC2 = 0x8B53, + INT_VEC3 = 0x8B54, + INT_VEC4 = 0x8B55, + BOOL = 0x8B56, + BOOL_VEC2 = 0x8B57, + BOOL_VEC3 = 0x8B58, + BOOL_VEC4 = 0x8B59, + FLOAT_MAT2 = 0x8B5A, + FLOAT_MAT3 = 0x8B5B, + FLOAT_MAT4 = 0x8B5C, + SAMPLER_2D = 0x8B5E, + SAMPLER_CUBE = 0x8B60, + VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622, + VERTEX_ATTRIB_ARRAY_SIZE = 0x8623, + VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624, + VERTEX_ATTRIB_ARRAY_TYPE = 0x8625, + VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A, + VERTEX_ATTRIB_ARRAY_POINTER = 0x8645, + VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F, + IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A, + IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B, + COMPILE_STATUS = 0x8B81, + INFO_LOG_LENGTH = 0x8B84, + SHADER_SOURCE_LENGTH = 0x8B88, + SHADER_COMPILER = 0x8DFA, + SHADER_BINARY_FORMATS = 0x8DF8, + NUM_SHADER_BINARY_FORMATS = 0x8DF9, + LOW_FLOAT = 0x8DF0, + MEDIUM_FLOAT = 0x8DF1, + HIGH_FLOAT = 0x8DF2, + LOW_INT = 0x8DF3, + MEDIUM_INT = 0x8DF4, + HIGH_INT = 0x8DF5, + FRAMEBUFFER = 0x8D40, + RENDERBUFFER = 0x8D41, + RGBA4 = 0x8056, + RGB5_A1 = 0x8057, + RGB565 = 0x8D62, + DEPTH_COMPONENT16 = 0x81A5, + STENCIL_INDEX = 0x1901, + STENCIL_INDEX8 = 0x8D48, + RENDERBUFFER_WIDTH = 0x8D42, + RENDERBUFFER_HEIGHT = 0x8D43, + RENDERBUFFER_INTERNAL_FORMAT = 0x8D44, + RENDERBUFFER_RED_SIZE = 0x8D50, + RENDERBUFFER_GREEN_SIZE = 0x8D51, + RENDERBUFFER_BLUE_SIZE = 0x8D52, + RENDERBUFFER_ALPHA_SIZE = 0x8D53, + RENDERBUFFER_DEPTH_SIZE = 0x8D54, + RENDERBUFFER_STENCIL_SIZE = 0x8D55, + FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0, + FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1, + FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2, + FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3, + COLOR_ATTACHMENT0 = 0x8CE0, + DEPTH_ATTACHMENT = 0x8D00, + STENCIL_ATTACHMENT = 0x8D20, + NONE = 0, + FRAMEBUFFER_COMPLETE = 0x8CD5, + FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6, + FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7, + FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9, + FRAMEBUFFER_UNSUPPORTED = 0x8CDD, + FRAMEBUFFER_BINDING = 0x8CA6, + RENDERBUFFER_BINDING = 0x8CA7, + MAX_RENDERBUFFER_SIZE = 0x84E8, + INVALID_FRAMEBUFFER_OPERATION = 0x0506 + }; + + static PassOwnPtr<GraphicsContext3D> create(); + virtual ~GraphicsContext3D(); + +#if PLATFORM(MAC) + PlatformGraphicsContext3D platformGraphicsContext3D() const { return m_contextObj; } + Platform3DObject platformTexture() const { return m_texture; } +#elif PLATFORM(CHROMIUM) + PlatformGraphicsContext3D platformGraphicsContext3D() const; + Platform3DObject platformTexture() const; +#else + PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } + Platform3DObject platformTexture() const { return NullPlatform3DObject; } +#endif + void makeContextCurrent(); + + // Helper to return the size in bytes of OpenGL data types + // like GL_FLOAT, GL_INT, etc. + int sizeInBytes(int type); + + void activeTexture(unsigned long texture); + void attachShader(WebGLProgram* program, WebGLShader* shader); + void bindAttribLocation(WebGLProgram*, unsigned long index, const String& name); + void bindBuffer(unsigned long target, WebGLBuffer*); + void bindFramebuffer(unsigned long target, WebGLFramebuffer*); + void bindRenderbuffer(unsigned long target, WebGLRenderbuffer*); + void bindTexture(unsigned long target, WebGLTexture* texture); + void blendColor(double red, double green, double blue, double alpha); + void blendEquation(unsigned long mode); + void blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha); + void blendFunc(unsigned long sfactor, unsigned long dfactor); + void blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha); + + void bufferData(unsigned long target, int size, unsigned long usage); + void bufferData(unsigned long target, WebGLArray* data, unsigned long usage); + void bufferSubData(unsigned long target, long offset, WebGLArray* data); + + unsigned long checkFramebufferStatus(unsigned long target); + void clear(unsigned long mask); + void clearColor(double red, double green, double blue, double alpha); + void clearDepth(double depth); + void clearStencil(long s); + void colorMask(bool red, bool green, bool blue, bool alpha); + void compileShader(WebGLShader*); + + //void compressedTexImage2D(unsigned long target, long level, unsigned long internalformat, unsigned long width, unsigned long height, long border, unsigned long imageSize, const void* data); + //void compressedTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, unsigned long width, unsigned long height, unsigned long format, unsigned long imageSize, const void* data); + + void copyTexImage2D(unsigned long target, long level, unsigned long internalformat, long x, long y, unsigned long width, unsigned long height, long border); + void copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, unsigned long width, unsigned long height); + void cullFace(unsigned long mode); + void depthFunc(unsigned long func); + void depthMask(bool flag); + void depthRange(double zNear, double zFar); + void detachShader(WebGLProgram*, WebGLShader*); + void disable(unsigned long cap); + void disableVertexAttribArray(unsigned long index); + void drawArrays(unsigned long mode, long first, long count); + void drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset); + + void enable(unsigned long cap); + void enableVertexAttribArray(unsigned long index); + void finish(); + void flush(); + void framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer*); + void framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture*, long level); + void frontFace(unsigned long mode); + void generateMipmap(unsigned long target); + + bool getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo&); + bool getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo&); + + int getAttribLocation(WebGLProgram*, const String& name); + + void getBooleanv(unsigned long pname, unsigned char* value); + + void getBufferParameteriv(unsigned long target, unsigned long pname, int* value); + + unsigned long getError(); + + void getFloatv(unsigned long pname, float* value); + + void getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value); + + void getIntegerv(unsigned long pname, int* value); + + void getProgramiv(WebGLProgram* program, unsigned long pname, int* value); + + String getProgramInfoLog(WebGLProgram*); + + void getRenderbufferParameteriv(unsigned long target, unsigned long pname, int* value); + + void getShaderiv(WebGLShader*, unsigned long pname, int* value); + + String getShaderInfoLog(WebGLShader*); + + // TBD + // void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + + String getShaderSource(WebGLShader*); + String getString(unsigned long name); + + void getTexParameterfv(unsigned long target, unsigned long pname, float* value); + void getTexParameteriv(unsigned long target, unsigned long pname, int* value); + + void getUniformfv(WebGLProgram* program, long location, float* value); + void getUniformiv(WebGLProgram* program, long location, int* value); + + long getUniformLocation(WebGLProgram*, const String& name); + + void getVertexAttribfv(unsigned long index, unsigned long pname, float* value); + void getVertexAttribiv(unsigned long index, unsigned long pname, int* value); + + long getVertexAttribOffset(unsigned long index, unsigned long pname); + + void hint(unsigned long target, unsigned long mode); + bool isBuffer(WebGLBuffer*); + bool isEnabled(unsigned long cap); + bool isFramebuffer(WebGLFramebuffer*); + bool isProgram(WebGLProgram*); + bool isRenderbuffer(WebGLRenderbuffer*); + bool isShader(WebGLShader*); + bool isTexture(WebGLTexture*); + void lineWidth(double); + void linkProgram(WebGLProgram*); + void pixelStorei(unsigned long pname, long param); + void polygonOffset(double factor, double units); + + PassRefPtr<WebGLArray> readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type); + + void releaseShaderCompiler(); + void renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height); + void sampleCoverage(double value, bool invert); + void scissor(long x, long y, unsigned long width, unsigned long height); + void shaderSource(WebGLShader*, const String& string); + void stencilFunc(unsigned long func, long ref, unsigned long mask); + void stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask); + void stencilMask(unsigned long mask); + void stencilMaskSeparate(unsigned long face, unsigned long mask); + void stencilOp(unsigned long fail, unsigned long zfail, unsigned long zpass); + void stencilOpSeparate(unsigned long face, unsigned long fail, unsigned long zfail, unsigned long zpass); + + // These next several functions return an error code (0 if no errors) rather than using an ExceptionCode. + // Currently they return -1 on any error. + int texImage2D(unsigned target, unsigned level, unsigned internalformat, + unsigned width, unsigned height, unsigned border, + unsigned format, unsigned type, WebGLArray* pixels); + int texImage2D(unsigned target, unsigned level, unsigned internalformat, + unsigned width, unsigned height, unsigned border, + unsigned format, unsigned type, ImageData* pixels); + int texImage2D(unsigned target, unsigned level, Image* image, + bool flipY, bool premultiplyAlpha); + int texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, + bool flipY, bool premultiplyAlpha); + + void texParameterf(unsigned target, unsigned pname, float param); + void texParameteri(unsigned target, unsigned pname, int param); + + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, + unsigned format, unsigned type, WebGLArray* pixels); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, + unsigned format, unsigned type, ImageData* pixels); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, Image* image, + bool flipY, bool premultiplyAlpha); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, HTMLVideoElement* video, + bool flipY, bool premultiplyAlpha); + + void uniform1f(long location, float x); + void uniform1fv(long location, float* v, int size); + void uniform1i(long location, int x); + void uniform1iv(long location, int* v, int size); + void uniform2f(long location, float x, float y); + void uniform2fv(long location, float* v, int size); + void uniform2i(long location, int x, int y); + void uniform2iv(long location, int* v, int size); + void uniform3f(long location, float x, float y, float z); + void uniform3fv(long location, float* v, int size); + void uniform3i(long location, int x, int y, int z); + void uniform3iv(long location, int* v, int size); + void uniform4f(long location, float x, float y, float z, float w); + void uniform4fv(long location, float* v, int size); + void uniform4i(long location, int x, int y, int z, int w); + void uniform4iv(long location, int* v, int size); + void uniformMatrix2fv(long location, bool transpose, float* value, int size); + void uniformMatrix3fv(long location, bool transpose, float* value, int size); + void uniformMatrix4fv(long location, bool transpose, float* value, int size); + + void useProgram(WebGLProgram*); + void validateProgram(WebGLProgram*); + + void vertexAttrib1f(unsigned long indx, float x); + void vertexAttrib1fv(unsigned long indx, float* values); + void vertexAttrib2f(unsigned long indx, float x, float y); + void vertexAttrib2fv(unsigned long indx, float* values); + void vertexAttrib3f(unsigned long indx, float x, float y, float z); + void vertexAttrib3fv(unsigned long indx, float* values); + void vertexAttrib4f(unsigned long indx, float x, float y, float z, float w); + void vertexAttrib4fv(unsigned long indx, float* values); + void vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, + unsigned long stride, unsigned long offset); + + void viewport(long x, long y, unsigned long width, unsigned long height); + + void reshape(int width, int height); + + // Helpers for notification about paint events + void beginPaint(WebGLRenderingContext* context); + void endPaint(); + + // Support for buffer creation and deletion + unsigned createBuffer(); + unsigned createFramebuffer(); + unsigned createProgram(); + unsigned createRenderbuffer(); + unsigned createShader(unsigned long); + unsigned createTexture(); + + void deleteBuffer(unsigned); + void deleteFramebuffer(unsigned); + void deleteProgram(unsigned); + void deleteRenderbuffer(unsigned); + void deleteShader(unsigned); + void deleteTexture(unsigned); + + // Synthesizes an OpenGL error which will be returned from a + // later call to getError. This is used to emulate OpenGL ES + // 2.0 behavior on the desktop and to enforce additional error + // checking mandated by WebGL. + // + // Per the behavior of glGetError, this stores at most one + // instance of any given error, and returns them from calls to + // getError in the order they were added. + void synthesizeGLError(unsigned long error); + + private: + GraphicsContext3D(); + + int m_currentWidth, m_currentHeight; + +#if PLATFORM(MAC) + Vector<Vector<float> > m_vertexArray; + + CGLContextObj m_contextObj; + GLuint m_texture; + GLuint m_fbo; + GLuint m_depthBuffer; + // Errors raised by synthesizeGLError(). + ListHashSet<unsigned long> m_syntheticErrors; +#endif + + // FIXME: ideally this would be used on all platforms. +#if PLATFORM(CHROMIUM) + friend class GraphicsContext3DInternal; + OwnPtr<GraphicsContext3DInternal> m_internal; +#endif + }; + +} // namespace WebCore + +#endif // GraphicsContext3D_h diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h index 98baab1..c532162 100644 --- a/WebCore/platform/graphics/GraphicsContextPrivate.h +++ b/WebCore/platform/graphics/GraphicsContextPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,10 +26,10 @@ #ifndef GraphicsContextPrivate_h #define GraphicsContextPrivate_h -#include "TransformationMatrix.h" #include "Gradient.h" #include "GraphicsContext.h" #include "Pattern.h" +#include "TransformationMatrix.h" namespace WebCore { @@ -38,18 +38,18 @@ namespace WebCore { : textDrawingMode(cTextFill) , strokeStyle(SolidStroke) , strokeThickness(0) -#if PLATFORM(CAIRO) - , globalAlpha(1.0f) -#endif - , strokeColorSpace(SolidColorSpace) , strokeColor(Color::black) + , strokeColorSpace(DeviceColorSpace) , fillRule(RULE_NONZERO) - , fillColorSpace(SolidColorSpace) , fillColor(Color::black) + , fillColorSpace(DeviceColorSpace) , shouldAntialias(true) , paintingDisabled(false) , shadowBlur(0) , shadowsIgnoreTransforms(false) +#if PLATFORM(CAIRO) + , globalAlpha(1.0f) +#endif { } @@ -57,19 +57,14 @@ namespace WebCore { StrokeStyle strokeStyle; float strokeThickness; -#if PLATFORM(CAIRO) - float globalAlpha; -#elif PLATFORM(QT) - TransformationMatrix pathTransform; -#endif - ColorSpace strokeColorSpace; Color strokeColor; + ColorSpace strokeColorSpace; RefPtr<Gradient> strokeGradient; RefPtr<Pattern> strokePattern; WindRule fillRule; - ColorSpace fillColorSpace; Color fillColor; + ColorSpace fillColorSpace; RefPtr<Gradient> fillGradient; RefPtr<Pattern> fillPattern; @@ -82,9 +77,14 @@ namespace WebCore { Color shadowColor; bool shadowsIgnoreTransforms; +#if PLATFORM(CAIRO) + float globalAlpha; +#elif PLATFORM(QT) + TransformationMatrix pathTransform; +#endif }; - class GraphicsContextPrivate { + class GraphicsContextPrivate : public Noncopyable { public: GraphicsContextPrivate() : m_focusRingWidth(0) diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index 7d43832..e215097 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -59,9 +59,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) : m_client(client) , m_anchorPoint(0.5f, 0.5f, 0) , m_opacity(1) -#ifndef NDEBUG , m_zPosition(0) -#endif , m_backgroundColorSet(false) , m_contentsOpaque(false) , m_preserves3D(false) @@ -69,13 +67,12 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) , m_usingTiledLayer(false) , m_masksToBounds(false) , m_drawsContent(false) - , m_paintingPhase(GraphicsLayerPaintAllMask) + , m_paintingPhase(GraphicsLayerPaintAll) , m_geometryOrientation(CompositingCoordinatesTopDown) , m_contentsOrientation(CompositingCoordinatesTopDown) , m_parent(0) -#ifndef NDEBUG + , m_maskLayer(0) , m_repaintCount(0) -#endif { } @@ -85,6 +82,31 @@ GraphicsLayer::~GraphicsLayer() removeFromParent(); } +bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const +{ + for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) { + if (curr == ancestor) + return true; + } + + return false; +} + +bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren) +{ + // If the contents of the arrays are the same, nothing to do. + if (newChildren == m_children) + return false; + + removeAllChildren(); + + size_t listSize = newChildren.size(); + for (size_t i = 0; i < listSize; ++i) + addChild(newChildren[i]); + + return true; +} + void GraphicsLayer::addChild(GraphicsLayer* childLayer) { ASSERT(childLayer != this); @@ -218,7 +240,6 @@ void GraphicsLayer::resumeAnimations() { } -#ifndef NDEBUG void GraphicsLayer::updateDebugIndicators() { if (GraphicsLayer::showDebugBorders()) { @@ -240,7 +261,6 @@ void GraphicsLayer::setZPosition(float position) { m_zPosition = position; } -#endif float GraphicsLayer::accumulatedOpacity() const { diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 4d7668a..0456bad 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -33,11 +33,15 @@ #include "FloatPoint.h" #include "FloatPoint3D.h" #include "FloatSize.h" +#if ENABLE(3D_CANVAS) +#include "GraphicsContext3D.h" +#endif #include "GraphicsLayerClient.h" #include "IntRect.h" #include "TransformationMatrix.h" #include "TransformOperations.h" #include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> #if PLATFORM(MAC) #ifdef __OBJC__ @@ -49,6 +53,12 @@ typedef CALayer* NativeLayer; typedef void* PlatformLayer; typedef void* NativeLayer; #endif +#elif PLATFORM(WIN) +namespace WebCore { +class WKCACFLayer; +typedef WKCACFLayer PlatformLayer; +typedef void* NativeLayer; +} #else typedef void* PlatformLayer; typedef void* NativeLayer; @@ -152,7 +162,7 @@ protected: class GraphicsLayer { public: - static GraphicsLayer* createGraphicsLayer(GraphicsLayerClient*); + static PassOwnPtr<GraphicsLayer> create(GraphicsLayerClient*); virtual ~GraphicsLayer(); @@ -168,7 +178,12 @@ public: GraphicsLayer* parent() const { return m_parent; }; void setParent(GraphicsLayer* layer) { m_parent = layer; } // Internal use only. + // Returns true if the layer has the given layer as an ancestor (excluding self). + bool hasAncestor(GraphicsLayer*) const; + const Vector<GraphicsLayer*>& children() const { return m_children; } + // Returns true if the child list changed. + virtual bool setChildren(const Vector<GraphicsLayer*>&); // Add child layers. If the child is already parented, it will be removed from its old parent. virtual void addChild(GraphicsLayer*); @@ -180,6 +195,9 @@ public: void removeAllChildren(); virtual void removeFromParent(); + GraphicsLayer* maskLayer() const { return m_maskLayer; } + virtual void setMaskLayer(GraphicsLayer* layer) { m_maskLayer = layer; } + // Offset is origin of the renderer minus origin of the graphics layer (so either zero or negative). IntSize offsetFromRenderer() const { return m_offsetFromRenderer; } void setOffsetFromRenderer(const IntSize& offset) { m_offsetFromRenderer = offset; } @@ -229,8 +247,8 @@ public: virtual void setOpacity(float opacity) { m_opacity = opacity; } // Some GraphicsLayers paint only the foreground or the background content - GraphicsLayerPaintingPhase drawingPhase() const { return m_paintingPhase; } - void setDrawingPhase(GraphicsLayerPaintingPhase phase) { m_paintingPhase = phase; } + GraphicsLayerPaintingPhase paintingPhase() const { return m_paintingPhase; } + void setPaintingPhase(GraphicsLayerPaintingPhase phase) { m_paintingPhase = phase; } virtual void setNeedsDisplay() = 0; // mark the given rect (in layer coords) as needing dispay. Never goes deep. @@ -255,6 +273,10 @@ public: virtual void setContentsToVideo(PlatformLayer*) { } virtual void setContentsBackgroundColor(const Color&) { } +#if ENABLE(3D_CANVAS) + virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*) { } + virtual void setGraphicsContext3DNeedsDisplay() { } +#endif // Callback from the underlying graphics system to draw layer contents. void paintGraphicsLayerContents(GraphicsContext&, const IntRect& clip); @@ -262,10 +284,8 @@ public: void dumpLayer(TextStream&, int indent = 0) const; -#ifndef NDEBUG int repaintCount() const { return m_repaintCount; } int incrementRepaintCount() { return ++m_repaintCount; } -#endif // Report whether the underlying compositing system uses a top-down // or a bottom-up coordinate system. @@ -280,9 +300,8 @@ public: virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; } CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; } -#ifndef NDEBUG - static bool showDebugBorders(); - static bool showRepaintCounter(); + bool showDebugBorders() { return m_client ? m_client->showDebugBorders() : false; } + bool showRepaintCounter() { return m_client ? m_client->showRepaintCounter() : false; } void updateDebugIndicators(); @@ -291,7 +310,6 @@ public: // z-position is the z-equivalent of position(). It's only used for debugging purposes. virtual float zPosition() const { return m_zPosition; } virtual void setZPosition(float); -#endif virtual void distributeOpacity(float); virtual float accumulatedOpacity() const; @@ -328,9 +346,7 @@ protected: Color m_backgroundColor; float m_opacity; -#ifndef NDEBUG float m_zPosition; -#endif bool m_backgroundColorSet : 1; bool m_contentsOpaque : 1; @@ -347,11 +363,11 @@ protected: Vector<GraphicsLayer*> m_children; GraphicsLayer* m_parent; + GraphicsLayer* m_maskLayer; // Reference to mask layer. We don't own this. + IntRect m_contentsRect; -#ifndef NDEBUG int m_repaintCount; -#endif }; diff --git a/WebCore/platform/graphics/GraphicsLayerClient.h b/WebCore/platform/graphics/GraphicsLayerClient.h index 8c0b7ed..afb297d 100644 --- a/WebCore/platform/graphics/GraphicsLayerClient.h +++ b/WebCore/platform/graphics/GraphicsLayerClient.h @@ -37,9 +37,10 @@ class IntRect; class FloatPoint; enum GraphicsLayerPaintingPhase { - GraphicsLayerPaintBackgroundMask = (1 << 0), - GraphicsLayerPaintForegroundMask = (1 << 1), - GraphicsLayerPaintAllMask = (GraphicsLayerPaintBackgroundMask | GraphicsLayerPaintForegroundMask) + GraphicsLayerPaintBackground = (1 << 0), + GraphicsLayerPaintForeground = (1 << 1), + GraphicsLayerPaintMask = (1 << 2), + GraphicsLayerPaintAll = (GraphicsLayerPaintBackground | GraphicsLayerPaintForeground | GraphicsLayerPaintMask) }; enum AnimatedPropertyID { @@ -61,6 +62,9 @@ public: virtual void notifySyncRequired(const GraphicsLayer*) = 0; virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0; + + virtual bool showDebugBorders() const = 0; + virtual bool showRepaintCounter() const = 0; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/Icon.h b/WebCore/platform/graphics/Icon.h index 444c67c..d7d694a 100644 --- a/WebCore/platform/graphics/Icon.h +++ b/WebCore/platform/graphics/Icon.h @@ -51,7 +51,6 @@ class String; class Icon : public RefCounted<Icon> { public: - static PassRefPtr<Icon> createIconForFile(const String& filename); static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames); ~Icon(); diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp index 80b5457..611216a 100644 --- a/WebCore/platform/graphics/Image.cpp +++ b/WebCore/platform/graphics/Image.cpp @@ -75,14 +75,14 @@ bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived) return dataChanged(allDataReceived); } -void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op) +void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, ColorSpace styleColorSpace, CompositeOperator op) { if (color.alpha() <= 0) return; ctxt->save(); ctxt->setCompositeOperation(!color.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); - ctxt->fillRect(dstRect, color); + ctxt->fillRect(dstRect, color, styleColorSpace); ctxt->restore(); } @@ -104,10 +104,10 @@ static inline FloatSize calculatePatternScale(const FloatRect& dstRect, const Fl } -void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op) +void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, destRect, solidColor(), op); + fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, op); return; } @@ -132,22 +132,22 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); visibleSrcRect.setWidth(destRect.width() / scale.width()); visibleSrcRect.setHeight(destRect.height() / scale.height()); - draw(ctxt, destRect, visibleSrcRect, op); + draw(ctxt, destRect, visibleSrcRect, styleColorSpace, op); return; } TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height()); FloatRect tileRect(FloatPoint(), intrinsicTileSize); - drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect); + drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), styleColorSpace, op, destRect); startAnimation(); } // FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. -void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator op) +void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dstRect, solidColor(), op); + fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, op); return; } @@ -170,7 +170,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const Flo vPhase -= fmodf(dstRect.height(), scale.height() * srcRect.height()) / 2.0f; FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); - drawPattern(ctxt, srcRect, patternTransform, patternPhase, op, dstRect); + drawPattern(ctxt, srcRect, patternTransform, patternPhase, styleColorSpace, op, dstRect); startAnimation(); } diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h index 294ddf6..f25169b 100644 --- a/WebCore/platform/graphics/Image.h +++ b/WebCore/platform/graphics/Image.h @@ -28,6 +28,7 @@ #define Image_h #include "Color.h" +#include "ColorSpace.h" #include "GraphicsTypes.h" #include "ImageSource.h" #include "IntRect.h" @@ -147,7 +148,7 @@ public: virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE) { return false; } #endif -#if PLATFORM(SGL) +#if PLATFORM(ANDROID) virtual void setURL(const String& str) {} #endif @@ -158,21 +159,22 @@ public: protected: Image(ImageObserver* = 0); - static void fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op); + static void fillWithSolidColor(GraphicsContext*, const FloatRect& dstRect, const Color&, ColorSpace styleColorSpace, CompositeOperator); + // The ColorSpace parameter will only be used for untagged images. #if PLATFORM(WIN) - virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator) { } + virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator) { } #endif - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator) = 0; - void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, CompositeOperator); - void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator) = 0; + void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, ColorSpace styleColorSpace, CompositeOperator); + void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator); // Supporting tiled drawing virtual bool mayFillWithSolidColor() { return false; } virtual Color solidColor() const { return Color(); } virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); private: RefPtr<SharedBuffer> m_data; // The encoded raw data for the image. diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h index 2a96d3b..9432058 100644 --- a/WebCore/platform/graphics/ImageBuffer.h +++ b/WebCore/platform/graphics/ImageBuffer.h @@ -50,6 +50,11 @@ namespace WebCore { LinearRGB }; + enum Multiply { + Premultiplied, + Unmultiplied + }; + class ImageBuffer : public Noncopyable { public: // Will return a null pointer on allocation failure. @@ -71,8 +76,11 @@ namespace WebCore { void clearImage() { m_image.clear(); } - PassRefPtr<ImageData> getImageData(const IntRect& rect) const; - void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint); + PassRefPtr<ImageData> getUnmultipliedImageData(const IntRect&) const; + PassRefPtr<ImageData> getPremultipliedImageData(const IntRect&) const; + + void putUnmultipliedImageData(ImageData*, const IntRect& sourceRect, const IntPoint& destPoint); + void putPremultipliedImageData(ImageData*, const IntRect& sourceRect, const IntPoint& destPoint); String toDataURL(const String& mimeType) const; #if !PLATFORM(CG) diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/ImageSource.cpp index df62618..bf7ae21 100644 --- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp +++ b/WebCore/platform/graphics/ImageSource.cpp @@ -1,6 +1,8 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + * Copyright (C) 2008, Google Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,64 +29,20 @@ #include "config.h" #include "ImageSource.h" -#if PLATFORM(CAIRO) +#if PLATFORM(QT) +#include "ImageDecoderQt.h" +#else +#include "ImageDecoder.h" +#endif -#include "BMPImageDecoder.h" -#include "GIFImageDecoder.h" -#include "ICOImageDecoder.h" -#include "JPEGImageDecoder.h" -#include "PNGImageDecoder.h" -#include "XBMImageDecoder.h" -#include "SharedBuffer.h" -#include <cairo.h> +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) +#ifndef IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS +#define IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS (1024 * 1024) +#endif +#endif namespace WebCore { -ImageDecoder* createDecoder(const Vector<char>& data) -{ - // We need at least 4 bytes to figure out what kind of image we're dealing with. - int length = data.size(); - if (length < 4) - return 0; - - const unsigned char* uContents = (const unsigned char*)data.data(); - const char* contents = data.data(); - - // GIFs begin with GIF8(7 or 9). - if (strncmp(contents, "GIF8", 4) == 0) - return new GIFImageDecoder(); - - // Test for PNG. - if (uContents[0]==0x89 && - uContents[1]==0x50 && - uContents[2]==0x4E && - uContents[3]==0x47) - return new PNGImageDecoder(); - - // JPEG - if (uContents[0]==0xFF && - uContents[1]==0xD8 && - uContents[2]==0xFF) - return new JPEGImageDecoder(); - - // BMP - if (strncmp(contents, "BM", 2) == 0) - return new BMPImageDecoder(); - - // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. - // CURs begin with 2-byte 0 followed by 2-byte 2. - if (!memcmp(contents, "\000\000\001\000", 4) || - !memcmp(contents, "\000\000\002\000", 4)) - return new ICOImageDecoder(); - - // XBMs require 8 bytes of info. - if (length >= 8 && strncmp(contents, "#define ", 8) == 0) - return new XBMImageDecoder(); - - // Give up. We don't know what the heck this is. - return 0; -} - ImageSource::ImageSource() : m_decoder(0) { @@ -120,53 +78,41 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) // This method will examine the data and instantiate an instance of the appropriate decoder plugin. // If insufficient bytes are available to determine the image type, no decoder plugin will be // made. - if (!m_decoder) - m_decoder = createDecoder(data->buffer()); - - if (!m_decoder) - return; + if (!m_decoder) { + m_decoder = static_cast<NativeImageSourcePtr>(ImageDecoder::create(*data)); +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (m_decoder) + m_decoder->setMaxNumPixels(IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS); +#endif + } - m_decoder->setData(data, allDataReceived); + if (m_decoder) + m_decoder->setData(data, allDataReceived); } String ImageSource::filenameExtension() const { - if (!m_decoder) - return String(); - - return m_decoder->filenameExtension(); + return m_decoder ? m_decoder->filenameExtension() : String(); } bool ImageSource::isSizeAvailable() { - if (!m_decoder) - return false; - - return m_decoder->isSizeAvailable(); + return m_decoder && m_decoder->isSizeAvailable(); } IntSize ImageSource::size() const { - if (!m_decoder) - return IntSize(); - - return m_decoder->size(); + return m_decoder ? m_decoder->size() : IntSize(); } IntSize ImageSource::frameSizeAtIndex(size_t index) const { - if (!m_decoder) - return IntSize(); - - return m_decoder->frameSizeAtIndex(index); + return m_decoder ? m_decoder->frameSizeAtIndex(index) : IntSize(); } int ImageSource::repetitionCount() { - if (!m_decoder) - return cAnimationNone; - - return m_decoder->repetitionCount(); + return m_decoder ? m_decoder->repetitionCount() : cAnimationNone; } size_t ImageSource::frameCount() const @@ -176,9 +122,6 @@ size_t ImageSource::frameCount() const NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { - if (!initialized()) - return 0; - if (!m_decoder) return 0; @@ -186,23 +129,16 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index) if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; - // Cairo does not like zero height images. - // If we have a zero height image, just pretend we don't have enough data yet. - if (!size().height()) + // Zero-height images can cause problems for some ports. If we have an + // empty image dimension, just bail. + if (size().isEmpty()) return 0; + // Return the buffer contents as a native image. For some ports, the data + // is already in a native container, and this just increments its refcount. return buffer->asNewNativeImage(); } -bool ImageSource::frameIsCompleteAtIndex(size_t index) -{ - if (!m_decoder) - return false; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - return buffer && buffer->status() == RGBA32Buffer::FrameComplete; -} - float ImageSource::frameDurationAtIndex(size_t index) { if (!m_decoder) @@ -223,17 +159,23 @@ float ImageSource::frameDurationAtIndex(size_t index) bool ImageSource::frameHasAlphaAtIndex(size_t index) { - // When a frame has not finished decoding, always mark it as having alpha, - // so we don't get a black background for the undecoded sections. - // TODO: A better solution is probably to have the underlying buffer's - // hasAlpha() return true in these cases, since it is, in fact, technically - // true. - if (!frameIsCompleteAtIndex(index)) - return true; - - return m_decoder->frameBufferAtIndex(index)->hasAlpha(); + // When a frame has not finished decoding, always mark it as having alpha. + // Ports that check the result of this function to determine their + // compositing op need this in order to not draw the undecoded portion as + // black. + // TODO: Perhaps we should ensure that each individual decoder returns true + // in this case. + return !frameIsCompleteAtIndex(index) + || m_decoder->frameBufferAtIndex(index)->hasAlpha(); } +bool ImageSource::frameIsCompleteAtIndex(size_t index) +{ + if (!m_decoder) + return false; + + RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); + return buffer && buffer->status() == RGBA32Buffer::FrameComplete; } -#endif // PLATFORM(CAIRO) +} diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h index 173d50b..083c7b0 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -45,12 +45,16 @@ QT_END_NAMESPACE #elif PLATFORM(CAIRO) struct _cairo_surface; typedef struct _cairo_surface cairo_surface_t; -#elif PLATFORM(ANDROID) && PLATFORM(SGL) +#elif PLATFORM(SKIA) +#if PLATFORM(ANDROID) #include "SkString.h" class SkBitmapRef; class PrivateAndroidImageSourceRec; -#elif PLATFORM(SKIA) +#else class NativeImageSkia; +#endif +#elif PLATFORM(HAIKU) +class BBitmap; #elif PLATFORM(WINCE) #include "SharedBitmap.h" #endif @@ -61,30 +65,21 @@ class IntSize; class SharedBuffer; class String; -#if PLATFORM(WX) -class ImageDecoder; -typedef ImageDecoder* NativeImageSourcePtr; -typedef const Vector<char>* NativeBytePtr; -#if USE(WXGC) -typedef wxGraphicsBitmap* NativeImagePtr; -#else -typedef wxBitmap* NativeImagePtr; -#endif -#elif PLATFORM(CG) +#if PLATFORM(CG) typedef CGImageSourceRef NativeImageSourcePtr; typedef CGImageRef NativeImagePtr; #elif PLATFORM(QT) class ImageDecoderQt; typedef ImageDecoderQt* NativeImageSourcePtr; typedef QPixmap* NativeImagePtr; -#elif PLATFORM(ANDROID) -#if PLATFORM(SGL) +#elif PLATFORM(SKIA) +#if PLATFORM(ANDROID) class String; #ifdef ANDROID_ANIMATED_GIF class ImageDecoder; #endif struct NativeImageSourcePtr { - SkString m_url; + SkString m_url; PrivateAndroidImageSourceRec* m_image; #ifdef ANDROID_ANIMATED_GIF ImageDecoder* m_gifDecoder; @@ -92,24 +87,28 @@ struct NativeImageSourcePtr { }; typedef const Vector<char>* NativeBytePtr; typedef SkBitmapRef* NativeImagePtr; -#elif PLATFORM(SKIA) // ANDROID +#else class ImageDecoder; typedef ImageDecoder* NativeImageSourcePtr; typedef NativeImageSkia* NativeImagePtr; #endif -#elif PLATFORM(CAIRO) +#else class ImageDecoder; typedef ImageDecoder* NativeImageSourcePtr; +#if PLATFORM(WX) +#if USE(WXGC) +typedef wxGraphicsBitmap* NativeImagePtr; +#else +typedef wxBitmap* NativeImagePtr; +#endif +#elif PLATFORM(CAIRO) typedef cairo_surface_t* NativeImagePtr; -#elif PLATFORM(SKIA) -class ImageDecoder; -typedef ImageDecoder* NativeImageSourcePtr; -typedef NativeImageSkia* NativeImagePtr; +#elif PLATFORM(HAIKU) +typedef BBitmap* NativeImagePtr; #elif PLATFORM(WINCE) -class ImageDecoder; -typedef ImageDecoder* NativeImageSourcePtr; typedef RefPtr<SharedBitmap> NativeImagePtr; #endif +#endif const int cAnimationLoopOnce = -1; const int cAnimationNone = -2; @@ -167,11 +166,9 @@ public: bool frameIsCompleteAtIndex(size_t); // Whether or not the frame is completely decoded. #if PLATFORM(ANDROID) -#if PLATFORM(SGL) void clearURL(); void setURL(const String& url); #endif -#endif private: #if PLATFORM(ANDROID) // FIXME: This is protected only to allow ImageSourceSkia to set ICO decoder diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h index e6d4816..ab5f3ec 100644 --- a/WebCore/platform/graphics/IntPoint.h +++ b/WebCore/platform/graphics/IntPoint.h @@ -55,13 +55,15 @@ class QPoint; QT_END_NAMESPACE #elif PLATFORM(GTK) typedef struct _GdkPoint GdkPoint; +#elif PLATFORM(HAIKU) +class BPoint; #endif #if PLATFORM(WX) class wxPoint; #endif -#if (PLATFORM(SKIA) || PLATFORM(SGL)) +#if PLATFORM(SKIA) struct SkPoint; struct SkIPoint; #endif @@ -121,6 +123,9 @@ public: #elif PLATFORM(GTK) IntPoint(const GdkPoint&); operator GdkPoint() const; +#elif PLATFORM(HAIKU) + explicit IntPoint(const BPoint&); + operator BPoint() const; #endif #if PLATFORM(WX) @@ -128,7 +133,7 @@ public: operator wxPoint() const; #endif -#if (PLATFORM(SKIA) || PLATFORM(SGL)) +#if PLATFORM(SKIA) IntPoint(const SkIPoint&); operator SkIPoint() const; operator SkPoint() const; diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h index 0b607f5..97b21bc 100644 --- a/WebCore/platform/graphics/IntRect.h +++ b/WebCore/platform/graphics/IntRect.h @@ -33,7 +33,7 @@ typedef struct CGRect CGRect; #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES typedef struct CGRect NSRect; #else @@ -49,13 +49,15 @@ class QRect; QT_END_NAMESPACE #elif PLATFORM(GTK) typedef struct _GdkRectangle GdkRectangle; +#elif PLATFORM(HAIKU) +class BRect; #endif #if PLATFORM(WX) class wxRect; #endif -#if (PLATFORM(SKIA) || PLATFORM(SGL)) +#if PLATFORM(SKIA) struct SkRect; struct SkIRect; #endif @@ -144,19 +146,23 @@ public: #elif PLATFORM(GTK) IntRect(const GdkRectangle&); operator GdkRectangle() const; +#elif PLATFORM(HAIKU) + explicit IntRect(const BRect&); + operator BRect() const; #endif #if PLATFORM(CG) operator CGRect() const; #endif -#if (PLATFORM(SKIA) || PLATFORM(SGL)) +#if PLATFORM(SKIA) IntRect(const SkIRect&); operator SkRect() const; operator SkIRect() const; #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) operator NSRect() const; #endif @@ -193,7 +199,8 @@ inline bool operator!=(const IntRect& a, const IntRect& b) IntRect enclosingIntRect(const CGRect&); #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) IntRect enclosingIntRect(const NSRect&); #endif diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h index dc7a85d..b242784 100644 --- a/WebCore/platform/graphics/IntSize.h +++ b/WebCore/platform/graphics/IntSize.h @@ -47,6 +47,12 @@ typedef struct tagSIZE SIZE; QT_BEGIN_NAMESPACE class QSize; QT_END_NAMESPACE +#elif PLATFORM(HAIKU) +class BSize; +#endif + +#if PLATFORM(WX) +class wxSize; #endif namespace WebCore { @@ -113,6 +119,15 @@ public: operator QSize() const; #endif +#if PLATFORM(HAIKU) + explicit IntSize(const BSize&); + operator BSize() const; +#endif + +#if PLATFORM(WX) + IntSize(const wxSize&); + operator wxSize() const; +#endif private: int m_width, m_height; diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index 531c598..4c66c50 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -35,10 +35,11 @@ #include "FrameView.h" #include "Frame.h" #include "Document.h" +#include "TimeRanges.h" #if PLATFORM(MAC) #include "MediaPlayerPrivateQTKit.h" -#elif PLATFORM(WINCE) +#elif PLATFORM(WINCE) && !PLATFORM(QT) #include "MediaPlayerPrivateWince.h" #elif PLATFORM(WIN) #include "MediaPlayerPrivateQuickTimeWin.h" @@ -63,14 +64,16 @@ public: virtual void load(const String&) { } virtual void cancelLoad() { } + virtual void prepareToPlay() { } virtual void play() { } virtual void pause() { } - virtual bool supportsFullscreen() const { return false; } + virtual PlatformMedia platformMedia() const { return NoPlatformMedia; } virtual IntSize naturalSize() const { return IntSize(0, 0); } virtual bool hasVideo() const { return false; } + virtual bool hasAudio() const { return false; } virtual void setVisible(bool) { } @@ -88,11 +91,14 @@ public: virtual void setVolume(float) { } + virtual bool hasClosedCaptions() const { return false; } + virtual void setClosedCaptionsVisible(bool) { }; + virtual MediaPlayer::NetworkState networkState() const { return MediaPlayer::Empty; } virtual MediaPlayer::ReadyState readyState() const { return MediaPlayer::HaveNothing; } virtual float maxTimeSeekable() const { return 0; } - virtual float maxTimeBuffered() const { return 0; } + virtual PassRefPtr<TimeRanges> buffered() const { return TimeRanges::create(); } virtual int dataRate() const { return 0; } @@ -104,14 +110,10 @@ public: virtual void paint(GraphicsContext*, const IntRect&) { } -#if PLATFORM(ANDROID) virtual bool canLoadPoster() const { return false; } virtual void setPoster(const String&) { } - virtual void prepareToPlay() { } -#endif #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - virtual void setPoster(const String& /*url*/) { } virtual void deliverNotification(MediaPlayerProxyNotificationType) { } virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) { } #endif @@ -127,7 +129,7 @@ static MediaPlayerPrivateInterface* createNullMediaPlayer(MediaPlayer* player) // engine support -struct MediaPlayerFactory { +struct MediaPlayerFactory : Noncopyable { MediaPlayerFactory(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsTypeAndCodecs) : constructor(constructor) , getSupportedTypes(getSupportedTypes) @@ -259,30 +261,26 @@ void MediaPlayer::load(const String& url, const ContentType& contentType) m_private.set(createNullMediaPlayer(this)); } -#if PLATFORM(ANDROID) bool MediaPlayer::canLoadPoster() const { return m_private->canLoadPoster(); } - -void MediaPlayer::prepareToPlay() -{ - m_private->prepareToPlay(); -} -#endif - -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) || PLATFORM(ANDROID) + void MediaPlayer::setPoster(const String& url) { m_private->setPoster(url); -} -#endif +} void MediaPlayer::cancelLoad() { m_private->cancelLoad(); } +void MediaPlayer::prepareToPlay() +{ + m_private->prepareToPlay(); +} + void MediaPlayer::play() { m_private->play(); @@ -338,11 +336,16 @@ IntSize MediaPlayer::naturalSize() return m_private->naturalSize(); } -bool MediaPlayer::hasVideo() +bool MediaPlayer::hasVideo() const { return m_private->hasVideo(); } +bool MediaPlayer::hasAudio() const +{ + return m_private->hasAudio(); +} + bool MediaPlayer::inMediaDocument() { Frame* frame = m_frameView ? m_frameView->frame() : 0; @@ -351,6 +354,11 @@ bool MediaPlayer::inMediaDocument() return document && document->isMediaDocument(); } +PlatformMedia MediaPlayer::platformMedia() const +{ + return m_private->platformMedia(); +} + MediaPlayer::NetworkState MediaPlayer::networkState() { return m_private->networkState(); @@ -372,6 +380,16 @@ void MediaPlayer::setVolume(float volume) m_private->setVolume(volume); } +bool MediaPlayer::hasClosedCaptions() const +{ + return m_private->hasClosedCaptions(); +} + +void MediaPlayer::setClosedCaptionsVisible(bool closedCaptionsVisible) +{ + m_private->setClosedCaptionsVisible(closedCaptionsVisible); +} + float MediaPlayer::rate() const { return m_rate; @@ -404,9 +422,9 @@ void MediaPlayer::setEndTime(float time) m_private->setEndTime(time); } -float MediaPlayer::maxTimeBuffered() +PassRefPtr<TimeRanges> MediaPlayer::buffered() { - return m_private->maxTimeBuffered(); + return m_private->buffered(); } float MediaPlayer::maxTimeSeekable() diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 8eade50..ec8ac33 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,9 +37,26 @@ #include <wtf/HashSet.h> #include <wtf/OwnPtr.h> #include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> + +#ifdef __OBJC__ +@class QTMovie; +#else +class QTMovie; +#endif namespace WebCore { +// Structure that will hold every native +// types supported by the current media player. +// We have to do that has multiple media players +// backend can live at runtime. +typedef struct PlatformMedia { + QTMovie* qtMovie; +} PlatformMedia; + +static const PlatformMedia NoPlatformMedia = { 0 }; + class ContentType; class FrameView; class GraphicsContext; @@ -48,6 +65,7 @@ class IntSize; class MediaPlayer; class MediaPlayerPrivateInterface; class String; +class TimeRanges; #if USE(ACCELERATED_COMPOSITING) class GraphicsLayer; @@ -98,7 +116,11 @@ public: class MediaPlayer : public Noncopyable { public: - MediaPlayer(MediaPlayerClient*); + + static PassOwnPtr<MediaPlayer> create(MediaPlayerClient* client) + { + return new MediaPlayer(client); + } virtual ~MediaPlayer(); // media engine support @@ -109,8 +131,11 @@ public: bool supportsFullscreen() const; bool supportsSave() const; + PlatformMedia platformMedia() const; + IntSize naturalSize(); - bool hasVideo(); + bool hasVideo() const; + bool hasAudio() const; void setFrameView(FrameView* frameView) { m_frameView = frameView; } FrameView* frameView() { return m_frameView; } @@ -125,6 +150,7 @@ public: bool visible() const; void setVisible(bool); + void prepareToPlay(); void play(); void pause(); @@ -145,7 +171,7 @@ public: bool preservesPitch() const; void setPreservesPitch(bool); - float maxTimeBuffered(); + PassRefPtr<TimeRanges> buffered(); float maxTimeSeekable(); unsigned bytesLoaded(); @@ -154,7 +180,10 @@ public: float volume() const; void setVolume(float); - + + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool closedCaptionsVisible); + int dataRate() const; bool autobuffer() const; @@ -184,14 +213,10 @@ public: MediaPlayerClient* mediaPlayerClient() const { return m_mediaPlayerClient; } -#if PLATFORM(ANDROID) bool canLoadPoster() const; void setPoster(const String&); - void prepareToPlay(); -#endif #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - void setPoster(const String& url); void deliverNotification(MediaPlayerProxyNotificationType notification); void setMediaPlayerProxy(WebMediaPlayerProxy* proxy); #endif @@ -206,6 +231,8 @@ public: bool hasSingleSecurityOrigin() const; private: + MediaPlayer(MediaPlayerClient*); + static void initializeMediaEngines(); MediaPlayerClient* m_mediaPlayerClient; diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h index 109ad10..03906bd 100644 --- a/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -36,13 +36,16 @@ class IntRect; class IntSize; class String; -class MediaPlayerPrivateInterface { +class MediaPlayerPrivateInterface : public Noncopyable { public: virtual ~MediaPlayerPrivateInterface() { } virtual void load(const String& url) = 0; virtual void cancelLoad() = 0; + virtual void prepareToPlay() { } + virtual PlatformMedia platformMedia() const { return NoPlatformMedia; } + virtual void play() = 0; virtual void pause() = 0; @@ -52,6 +55,7 @@ public: virtual IntSize naturalSize() const = 0; virtual bool hasVideo() const = 0; + virtual bool hasAudio() const = 0; virtual void setVisible(bool) = 0; @@ -72,11 +76,14 @@ public: virtual void setVolume(float) = 0; + virtual bool hasClosedCaptions() const { return false; } + virtual void setClosedCaptionsVisible(bool) { } + virtual MediaPlayer::NetworkState networkState() const = 0; virtual MediaPlayer::ReadyState readyState() const = 0; virtual float maxTimeSeekable() const = 0; - virtual float maxTimeBuffered() const = 0; + virtual PassRefPtr<TimeRanges> buffered() const = 0; virtual int dataRate() const = 0; @@ -92,14 +99,10 @@ public: virtual void setAutobuffer(bool) { }; -#if PLATFORM(ANDROID) virtual bool canLoadPoster() const { return false; } virtual void setPoster(const String&) { } - virtual void prepareToPlay() { } -#endif #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - virtual void setPoster(const String& url) = 0; virtual void deliverNotification(MediaPlayerProxyNotificationType) = 0; virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) = 0; #endif diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index da324bc..6618fb7 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -29,6 +29,7 @@ #define Path_h #include <algorithm> +#include <wtf/FastAllocBase.h> #if PLATFORM(CG) typedef struct CGPath PlatformPath; @@ -38,9 +39,6 @@ QT_BEGIN_NAMESPACE class QPainterPath; QT_END_NAMESPACE typedef QPainterPath PlatformPath; -#elif PLATFORM(SGL) -class SkPath; -typedef SkPath PlatformPath; #elif PLATFORM(WX) && USE(WXGC) class wxGraphicsPath; typedef wxGraphicsPath PlatformPath; @@ -52,6 +50,9 @@ typedef WebCore::CairoPath PlatformPath; #elif PLATFORM(SKIA) class SkPath; typedef SkPath PlatformPath; +#elif PLATFORM(HAIKU) +class BRegion; +typedef BRegion PlatformPath; #elif PLATFORM(WINCE) namespace WebCore { class PlatformPath; @@ -90,7 +91,7 @@ namespace WebCore { typedef void (*PathApplierFunction)(void* info, const PathElement*); - class Path { + class Path : public FastAllocBase { public: Path(); ~Path(); diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h index 02ad3ec..aa0a357 100644 --- a/WebCore/platform/graphics/Pattern.h +++ b/WebCore/platform/graphics/Pattern.h @@ -39,7 +39,7 @@ typedef CGPatternRef PlatformPatternPtr; #elif PLATFORM(CAIRO) #include <cairo.h> typedef cairo_pattern_t* PlatformPatternPtr; -#elif PLATFORM(SKIA) || PLATFORM(SGL) +#elif PLATFORM(SKIA) class SkShader; typedef SkShader* PlatformPatternPtr; #elif PLATFORM(QT) @@ -53,6 +53,9 @@ typedef wxGraphicsBrush* PlatformPatternPtr; class wxBrush; typedef wxBrush* PlatformPatternPtr; #endif // USE(WXGC) +#elif PLATFORM(HAIKU) +#include <interface/GraphicsDefs.h> +typedef pattern* PlatformPatternPtr; #elif PLATFORM(WINCE) typedef void* PlatformPatternPtr; #endif diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp index c879228..2ec8abb 100644 --- a/WebCore/platform/graphics/SimpleFontData.cpp +++ b/WebCore/platform/graphics/SimpleFontData.cpp @@ -48,7 +48,9 @@ using namespace std; namespace WebCore { SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) - : m_unitsPerEm(defaultUnitsPerEm) + : m_maxCharWidth(-1) + , m_avgCharWidth(-1) + , m_unitsPerEm(defaultUnitsPerEm) , m_platformData(f) , m_treatAsFixedPitch(false) #if ENABLE(SVG_FONTS) diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h index cb472b0..387a5c7 100644 --- a/WebCore/platform/graphics/SimpleFontData.h +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -2,6 +2,7 @@ * This file is part of the internal font implementation. * * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007-2008 Torch Mobile, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,13 +28,14 @@ #include "FontPlatformData.h" #include "GlyphPageTreeNode.h" #include "GlyphWidthMap.h" +#include "TextRenderingMode.h" #include <wtf/OwnPtr.h> #if USE(ATSUI) typedef struct OpaqueATSUStyle* ATSUStyle; #endif -#if PLATFORM(WIN) +#if PLATFORM(WIN) && !PLATFORM(WINCE) #include <usp10.h> #endif @@ -45,6 +47,10 @@ typedef struct OpaqueATSUStyle* ATSUStyle; #include <QFont> #endif +#if PLATFORM(HAIKU) +#include <Font.h> +#endif + namespace WebCore { class FontDescription; @@ -115,7 +121,7 @@ public: #if USE(CORE_TEXT) CTFontRef getCTFont() const; - CFDictionaryRef getCFStringAttributes() const; + CFDictionaryRef getCFStringAttributes(TextRenderingMode) const; #endif #if USE(ATSUI) @@ -134,17 +140,14 @@ public: #if PLATFORM(WIN) bool isSystemFont() const { return m_isSystemFont; } +#if !PLATFORM(WINCE) // disable unused members to save space SCRIPT_FONTPROPERTIES* scriptFontProperties() const; SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; } - +#endif static void setShouldApplyMacAscentHack(bool); static bool shouldApplyMacAscentHack(); #endif -#if PLATFORM(CAIRO) - void setFont(cairo_t*) const; -#endif - #if PLATFORM(WX) wxFont* getWxFont() const { return m_platformData.font(); } #endif @@ -159,7 +162,7 @@ private: void commonInit(); -#if PLATFORM(WIN) +#if PLATFORM(WIN) && !PLATFORM(WINCE) void initGDIFont(); void platformCommonDestroy(); float widthForGDIGlyph(Glyph glyph) const; @@ -224,9 +227,11 @@ private: #if PLATFORM(WIN) bool m_isSystemFont; +#if !PLATFORM(WINCE) // disable unused members to save space mutable SCRIPT_CACHE m_scriptCache; mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties; #endif +#endif }; diff --git a/WebCore/platform/graphics/TextRenderingMode.h b/WebCore/platform/graphics/TextRenderingMode.h new file mode 100644 index 0000000..4f817a4 --- /dev/null +++ b/WebCore/platform/graphics/TextRenderingMode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE 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 TextRenderingMode_h +#define TextRenderingMode_h + +namespace WebCore { + + enum TextRenderingMode { AutoTextRendering, OptimizeSpeed, OptimizeLegibility, GeometricPrecision }; + +} // namespace WebCore + +#endif // TextRenderingMode_h diff --git a/WebCore/platform/graphics/android/AndroidAnimation.cpp b/WebCore/platform/graphics/android/AndroidAnimation.cpp new file mode 100644 index 0000000..9cdb0c7 --- /dev/null +++ b/WebCore/platform/graphics/android/AndroidAnimation.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include "AndroidAnimation.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "Animation.h" +#include "GraphicsLayerAndroid.h" + +#include "Timer.h" +#include "TimingFunction.h" +#include "UnitBezier.h" + +#include <wtf/CurrentTime.h> + +namespace WebCore { + +void AndroidTransformAnimationValue::apply() +{ + if (m_doTranslation) + m_layer->setTranslation(m_translation); + + if (m_doScaling) + m_layer->setScale(m_scale); + + if (m_doRotation) + m_layer->setRotation(m_rotation); +} + +void AndroidAnimationTimer::fired() +{ + if (!m_notificationSent) { + m_notificationSent = true; + if (m_layer && m_layer->client()) + m_layer->client()->notifyAnimationStarted(m_layer, WTF::currentTime()); + } +} + +static long gDebugAndroidAnimationInstances; + +long AndroidAnimation::instancesCount() +{ + return gDebugAndroidAnimationInstances; +} + +AndroidAnimation::AndroidAnimation(LayerAndroid* contentLayer, + const Animation* animation, + double beginTime) : + m_contentLayer(contentLayer), + m_beginTime(beginTime), + m_duration(animation->duration()), + m_iterationCount(animation->iterationCount()), + m_currentIteration(0), + m_direction(animation->direction()), + m_timingFunction(animation->timingFunction()) +{ + if (!static_cast<int>(beginTime)) // time not set + m_beginTime = WTF::currentTime(); + + gDebugAndroidAnimationInstances++; +} + +AndroidAnimation::AndroidAnimation(AndroidAnimation* anim) : + m_contentLayer(anim->m_contentLayer), + m_beginTime(anim->m_beginTime), + m_duration(anim->m_duration), + m_iterationCount(anim->m_iterationCount), + m_currentIteration(0), + m_direction(anim->m_direction), + m_timingFunction(anim->m_timingFunction) +{ + gDebugAndroidAnimationInstances++; +} + +AndroidAnimation::~AndroidAnimation() +{ + gDebugAndroidAnimationInstances--; +} + +float AndroidAnimation::currentProgress(double time) +{ + if (m_beginTime <= 0.000001) // overflow or not correctly set + m_beginTime = time; + + m_elapsedTime = time - m_beginTime; + + if (m_duration <= 0) + m_duration = 0.000001; + + if (m_elapsedTime < 0) // animation not yet started. + return 0; + + return m_elapsedTime / m_duration; +} + +bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress) +{ + float progress = currentProgress(time); + + int currentIteration = static_cast<int>(progress); + if (currentIteration != m_currentIteration) + if (m_direction == Animation::AnimationDirectionAlternate) + swapDirection(); + + m_currentIteration = currentIteration; + progress -= m_currentIteration; + + if ((m_currentIteration >= m_iterationCount) + && (m_iterationCount != Animation::IterationCountInfinite)) + return false; + + if (m_timingFunction.type() != LinearTimingFunction) { + UnitBezier bezier(m_timingFunction.x1(), + m_timingFunction.y1(), + m_timingFunction.x2(), + m_timingFunction.y2()); + if (m_duration > 0) + progress = bezier.solve(progress, 1.0f / (200.0f * m_duration)); + } + + *finalProgress = progress; + return true; +} + +PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create(LayerAndroid* contentLayer, + float fromValue, float toValue, + const Animation* animation, double beginTime) +{ + return adoptRef(new AndroidOpacityAnimation(contentLayer, + fromValue, toValue, animation, beginTime)); +} + +AndroidOpacityAnimation::AndroidOpacityAnimation(LayerAndroid* contentLayer, + float fromValue, float toValue, + const Animation* animation, + double beginTime) + : AndroidAnimation(contentLayer, animation, beginTime), + m_fromValue(fromValue), m_toValue(toValue) +{ +} + +AndroidOpacityAnimation::AndroidOpacityAnimation(AndroidOpacityAnimation* anim) + : AndroidAnimation(anim), + m_fromValue(anim->m_fromValue), + m_toValue(anim->m_toValue) +{ +} + +AndroidAnimation* AndroidOpacityAnimation::copy() +{ + return new AndroidOpacityAnimation(this); +} + +void AndroidOpacityAnimation::swapDirection() +{ + float v = m_toValue; + m_toValue = m_fromValue; + m_fromValue = m_toValue; +} + +bool AndroidOpacityAnimation::evaluate(double time) +{ + float progress; + if (!checkIterationsAndProgress(time, &progress)) + return false; + + if (progress < 0) // we still want to be evaluated until we get progress > 0 + return true; + + float value = m_fromValue + ((m_toValue - m_fromValue) * progress); + m_result = AndroidOpacityAnimationValue::create(m_contentLayer.get(), value); + return true; +} + +PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create(LayerAndroid* contentLayer, + const Animation* animation, double beginTime) +{ + return adoptRef(new AndroidTransformAnimation(contentLayer, animation, beginTime)); +} + +AndroidTransformAnimation::AndroidTransformAnimation(LayerAndroid* contentLayer, + const Animation* animation, + double beginTime) + : AndroidAnimation(contentLayer, animation, beginTime), + m_doTranslation(false), + m_doScaling(false), + m_doRotation(false) +{ +} + +AndroidTransformAnimation::AndroidTransformAnimation(AndroidTransformAnimation* anim) + : AndroidAnimation(anim), + m_doTranslation(anim->m_doTranslation), + m_doScaling(anim->m_doScaling), + m_doRotation(anim->m_doRotation), + m_position(anim->m_position), + m_fromX(anim->m_fromX), m_fromY(anim->m_fromY), m_fromZ(anim->m_fromZ), + m_toX(anim->m_toX), m_toY(anim->m_toY), m_toZ(anim->m_toZ), + m_fromAngle(anim->m_fromAngle), m_toAngle(anim->m_toAngle), + m_fromScaleX(anim->m_fromScaleX), m_fromScaleY(anim->m_fromScaleY), m_fromScaleZ(anim->m_fromScaleZ), + m_toScaleX(anim->m_toScaleX), m_toScaleY(anim->m_toScaleY), m_toScaleZ(anim->m_toScaleZ) +{ +} + +AndroidAnimation* AndroidTransformAnimation::copy() +{ + return new AndroidTransformAnimation(this); +} + +void AndroidTransformAnimation::setRotation(float fA, float tA) +{ + m_fromAngle = fA; + m_toAngle = tA; + m_doRotation = true; +} + +void AndroidTransformAnimation::setTranslation(float fX, float fY, float fZ, + float tX, float tY, float tZ) +{ + m_fromX = fX; + m_fromY = fY; + m_fromZ = fZ; + m_toX = tX; + m_toY = tY; + m_toZ = tZ; + m_doTranslation = true; +} + +void AndroidTransformAnimation::setScale(float fX, float fY, float fZ, + float tX, float tY, float tZ) +{ + m_fromScaleX = fX; + m_fromScaleY = fY; + m_fromScaleZ = fZ; + m_toScaleX = tX; + m_toScaleY = tY; + m_toScaleZ = tZ; + m_doScaling = true; +} + +void AndroidTransformAnimation::swapDirection() +{ + if (m_doTranslation) { + float tx = m_toX; + m_toX = m_fromX; + m_fromX = tx; + float ty = m_toY; + m_toY = m_fromY; + m_fromY = ty; + float tz = m_toZ; + m_toZ = m_fromZ; + m_fromZ = tz; + } + if (m_doScaling) { + float sx = m_toScaleX; + m_toScaleX = m_fromScaleX; + m_fromScaleX = sx; + float sy = m_toScaleY; + m_toScaleY = m_fromScaleY; + m_fromScaleY = sy; + } + if (m_doRotation) { + float a = m_toAngle; + m_toAngle = m_fromAngle; + m_fromAngle = a; + } +} + +bool AndroidTransformAnimation::evaluate(double time) +{ + float progress; + if (!checkIterationsAndProgress(time, &progress)) + return false; + + if (progress < 0) // we still want to be evaluated until we get progress > 0 + return true; + + float x = m_fromX + (m_toX - m_fromX) * progress; + float y = m_fromY + (m_toY - m_fromY) * progress; + float z = m_fromZ + (m_toZ - m_fromZ) * progress; + float sx = m_fromScaleX + (m_toScaleX - m_fromScaleX) * progress; + float sy = m_fromScaleY + (m_toScaleY - m_fromScaleY) * progress; + float sz = m_fromScaleZ + (m_toScaleZ - m_fromScaleZ) * progress; + float a = m_fromAngle + (m_toAngle - m_fromAngle) * progress; + + FloatPoint translation(x, y); + FloatPoint3D scale(sx, sy, sz); + m_result = AndroidTransformAnimationValue::create(m_contentLayer.get(), + translation, scale, a); + m_result->setDoTranslation(m_doTranslation); + m_result->setDoScaling(m_doScaling); + m_result->setDoRotation(m_doRotation); + return true; +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/android/AndroidAnimation.h b/WebCore/platform/graphics/android/AndroidAnimation.h new file mode 100644 index 0000000..05d6a76 --- /dev/null +++ b/WebCore/platform/graphics/android/AndroidAnimation.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AndroidAnimation_h +#define AndroidAnimation_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "FloatPoint.h" +#include "FloatPoint3D.h" +#include "HashMap.h" +#include "LayerAndroid.h" +#include "RefPtr.h" +#include "Timer.h" +#include "Vector.h" + +namespace WebCore { + +class AndroidAnimation; +class GraphicsLayerAndroid; +class TimingFunction; + +typedef Vector<RefPtr<AndroidAnimation> > AnimsVector; +typedef HashMap<RefPtr<LayerAndroid>, AnimsVector* > LayersAnimsMap; + +class AndroidAnimationValue : public RefCounted<AndroidAnimationValue> { + public: + AndroidAnimationValue(LayerAndroid* layer) : m_layer(layer) { } + virtual ~AndroidAnimationValue() { } + virtual void apply() = 0; + protected: + RefPtr<LayerAndroid> m_layer; +}; + +class AndroidOpacityAnimationValue : public AndroidAnimationValue { + public: + static PassRefPtr<AndroidOpacityAnimationValue> create( + LayerAndroid* layer, float value) { + return adoptRef(new AndroidOpacityAnimationValue(layer, value)); + } + AndroidOpacityAnimationValue(LayerAndroid* layer, float value) : + AndroidAnimationValue(layer), m_value(value) { } + virtual void apply() { m_layer->setOpacity(m_value); } + private: + float m_value; +}; + +class AndroidTransformAnimationValue : public AndroidAnimationValue { + public: + static PassRefPtr<AndroidTransformAnimationValue> create( + LayerAndroid* layer, + FloatPoint translation, + FloatPoint3D scale, + float rotation) { + return adoptRef(new AndroidTransformAnimationValue(layer, translation, scale, rotation)); + } + + AndroidTransformAnimationValue(LayerAndroid* layer, + FloatPoint translation, + FloatPoint3D scale, + float rotation) : + AndroidAnimationValue(layer), + m_doTranslation(false), m_doScaling(false), m_doRotation(false), + m_translation(translation), m_scale(scale), m_rotation(rotation) { } + void setDoTranslation(bool doTranslation) { m_doTranslation = doTranslation; } + void setDoScaling(bool doScaling) { m_doScaling = doScaling; } + void setDoRotation(bool doRotation) { m_doRotation = doRotation; } + + virtual void apply(); + + private: + bool m_doTranslation; + bool m_doScaling; + bool m_doRotation; + FloatPoint m_translation; + FloatPoint3D m_scale; + float m_rotation; +}; + +class AndroidAnimation : public RefCounted<AndroidAnimation> { + public: + AndroidAnimation(LayerAndroid* contentLayer, + const Animation* animation, + double beginTime); + AndroidAnimation(AndroidAnimation* anim); + + virtual ~AndroidAnimation(); + virtual AndroidAnimation* copy() = 0; + float currentProgress(double time); + bool checkIterationsAndProgress(double time, float* finalProgress); + virtual void swapDirection() = 0; + virtual bool evaluate(double time) = 0; + LayerAndroid* contentLayer() { return m_contentLayer.get(); } + static long instancesCount(); + void setLayer(LayerAndroid* layer) { m_contentLayer = layer; } + void setName(const String& name) { m_name = name; } + String name() { return m_name; } + virtual PassRefPtr<AndroidAnimationValue> result() = 0; + + protected: + RefPtr<LayerAndroid> m_contentLayer; + double m_beginTime; + double m_elapsedTime; + double m_duration; + int m_iterationCount; + int m_currentIteration; + int m_direction; + TimingFunction m_timingFunction; + String m_name; +}; + +class AndroidOpacityAnimation : public AndroidAnimation { + public: + static PassRefPtr<AndroidOpacityAnimation> create(LayerAndroid* contentLayer, + float fromValue, float toValue, + const Animation* animation, + double beginTime); + AndroidOpacityAnimation(LayerAndroid* contentLayer, + float fromValue, float toValue, + const Animation* animation, + double beginTime); + AndroidOpacityAnimation(AndroidOpacityAnimation* anim); + virtual AndroidAnimation* copy(); + virtual PassRefPtr<AndroidAnimationValue> result() { return m_result.release(); } + + virtual void swapDirection(); + virtual bool evaluate(double time); + + private: + RefPtr<AndroidOpacityAnimationValue> m_result; + float m_fromValue; + float m_toValue; +}; + +class AndroidTransformAnimation : public AndroidAnimation { + public: + static PassRefPtr<AndroidTransformAnimation> create(LayerAndroid* contentLayer, + const Animation* animation, + double beginTime); + AndroidTransformAnimation(LayerAndroid* contentLayer, + const Animation* animation, + double beginTime); + + AndroidTransformAnimation(AndroidTransformAnimation* anim); + virtual AndroidAnimation* copy(); + + void setOriginalPosition(FloatPoint position) { m_position = position; } + void setRotation(float fA, float tA); + void setTranslation(float fX, float fY, float fZ, + float tX, float tY, float tZ); + void setScale(float fX, float fY, float fZ, + float tX, float tY, float tZ); + virtual void swapDirection(); + virtual bool evaluate(double time); + virtual PassRefPtr<AndroidAnimationValue> result() { return m_result.release(); } + + private: + RefPtr<AndroidTransformAnimationValue> m_result; + bool m_doTranslation; + bool m_doScaling; + bool m_doRotation; + FloatPoint m_position; + float m_fromX, m_fromY, m_fromZ; + float m_toX, m_toY, m_toZ; + float m_fromAngle, m_toAngle; + float m_fromScaleX, m_fromScaleY, m_fromScaleZ; + float m_toScaleX, m_toScaleY, m_toScaleZ; +}; + +class AndroidAnimationTimer : public TimerBase { + public: + + AndroidAnimationTimer(GraphicsLayerAndroid* layer, double beginTime) + { + m_layer = layer; + m_notificationSent = false; + m_beginTime = beginTime; + } + + private: + void fired(); + GraphicsLayerAndroid* m_layer; + double m_beginTime; + bool m_notificationSent; +}; + +} // namespace WebCore + + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // AndroidAnimation_h diff --git a/WebCore/platform/graphics/android/BitmapAllocatorAndroid.cpp b/WebCore/platform/graphics/android/BitmapAllocatorAndroid.cpp index 0f6057d..66340ee 100644 --- a/WebCore/platform/graphics/android/BitmapAllocatorAndroid.cpp +++ b/WebCore/platform/graphics/android/BitmapAllocatorAndroid.cpp @@ -1,17 +1,26 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright 2009, The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -60,4 +69,3 @@ bool BitmapAllocatorAndroid::allocPixelRef(SkBitmap* bitmap, SkColorTable*) } } - diff --git a/WebCore/platform/graphics/android/BitmapAllocatorAndroid.h b/WebCore/platform/graphics/android/BitmapAllocatorAndroid.h index f2b2223..7b401d0 100644 --- a/WebCore/platform/graphics/android/BitmapAllocatorAndroid.h +++ b/WebCore/platform/graphics/android/BitmapAllocatorAndroid.h @@ -1,17 +1,26 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright 2009, The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WebCore_BitmapAllocatorAndroid_DEFINED diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp index a430b07..36c6248 100644 --- a/WebCore/platform/graphics/android/FontAndroid.cpp +++ b/WebCore/platform/graphics/android/FontAndroid.cpp @@ -5,23 +5,23 @@ * 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 + * * 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 + * * 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 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp index 0b3655f..ef795de 100644 --- a/WebCore/platform/graphics/android/FontCacheAndroid.cpp +++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp @@ -5,26 +5,23 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -131,4 +128,3 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne } } - diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.cpp b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp index bb465ef..d954e70 100644 --- a/WebCore/platform/graphics/android/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.h b/WebCore/platform/graphics/android/FontCustomPlatformData.h index 910d616..1d11e59 100644 --- a/WebCore/platform/graphics/android/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/android/FontCustomPlatformData.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -54,4 +54,3 @@ namespace WebCore { } // namespace WebCore #endif // FontCustomPlatformData_h_ - diff --git a/WebCore/platform/graphics/android/FontDataAndroid.cpp b/WebCore/platform/graphics/android/FontDataAndroid.cpp index 2bb53e4..ca54eb3 100644 --- a/WebCore/platform/graphics/android/FontDataAndroid.cpp +++ b/WebCore/platform/graphics/android/FontDataAndroid.cpp @@ -5,26 +5,23 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" diff --git a/WebCore/platform/graphics/android/FontPlatformData.h b/WebCore/platform/graphics/android/FontPlatformData.h index d7761a8..bb6b1c3 100644 --- a/WebCore/platform/graphics/android/FontPlatformData.h +++ b/WebCore/platform/graphics/android/FontPlatformData.h @@ -1,27 +1,32 @@ /* - * This file is part of the internal font implementation. It should not be included by anyone other than - * FontMac.cpp, FontWin.cpp and Font.cpp. - * * Copyright 2009, The Android Open Source Project * Copyright (C) 2006 Apple Computer, Inc. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// This file is part of the internal font implementation. It should not be included by anyone other than +// FontMac.cpp, FontWin.cpp and Font.cpp. + #ifndef FontPlatformData_H #define FontPlatformData_H diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp index 3fcf3fe..640940f 100644 --- a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp +++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp @@ -1,27 +1,32 @@ /* - * This file is part of the internal font implementation. It should not be included by anyone other than - * FontMac.cpp, FontWin.cpp and Font.cpp. - * * Copyright 2009, The Android Open Source Project * Copyright (C) 2006 Apple Computer, Inc. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +//This file is part of the internal font implementation. It should not be included by anyone other than +// FontMac.cpp, FontWin.cpp and Font.cpp. + #include "config.h" #include "FontPlatformData.h" @@ -181,4 +186,3 @@ unsigned FontPlatformData::hash() const } } - diff --git a/WebCore/platform/graphics/android/GlyphMapAndroid.cpp b/WebCore/platform/graphics/android/GlyphMapAndroid.cpp index fe64c9a..da9d99a 100644 --- a/WebCore/platform/graphics/android/GlyphMapAndroid.cpp +++ b/WebCore/platform/graphics/android/GlyphMapAndroid.cpp @@ -5,26 +5,23 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -87,4 +84,3 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b } } - diff --git a/WebCore/platform/graphics/android/GradientAndroid.cpp b/WebCore/platform/graphics/android/GradientAndroid.cpp index 8334d1c..72ae336 100644 --- a/WebCore/platform/graphics/android/GradientAndroid.cpp +++ b/WebCore/platform/graphics/android/GradientAndroid.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -90,9 +90,11 @@ SkShader* Gradient::getShader(SkShader::TileMode mode) SkShader* s; if (m_radial) - // FIXME: SVG always passes 0 for m_r0 - s = SkGradientShader::CreateRadial(pts[0], - SkFloatToScalar(m_r0 ? m_r0 : m_r1), colors, pos, count, mode); + s = SkGradientShader::CreateTwoPointRadial(pts[0], + SkFloatToScalar(m_r0), + pts[1], + SkFloatToScalar(m_r1), + colors, pos, count, mode); else s = SkGradientShader::CreateLinear(pts, colors, pos, count, mode); diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp index 34b709b..9a86b84 100644 --- a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -247,6 +247,13 @@ public: paint->setColor(mState->applyAlpha(mState->mFillColor)); } + void setup_paint_bitmap(SkPaint* paint) const { + this->setup_paint_common(paint); + // we only want the global alpha for bitmaps, + // so just give applyAlpha opaque black + paint->setColor(mState->applyAlpha(0xFF000000)); + } + /* sets up the paint for stroking. Returns true if the style is really just a dash of squares (the size of the paint's stroke-width. */ @@ -323,23 +330,15 @@ static SkShader::TileMode SpreadMethod2TileMode(GradientSpreadMethod sm) { return mode; } -static void extactShader(SkPaint* paint, ColorSpace cs, Pattern* pat, - Gradient* grad) +static void extactShader(SkPaint* paint, Pattern* pat, Gradient* grad) { - switch (cs) { - case PatternColorSpace: - // createPlatformPattern() returns a new inst - paint->setShader(pat->createPlatformPattern( - TransformationMatrix()))->safeUnref(); - break; - case GradientColorSpace: { - // grad->getShader() returns a cached obj - GradientSpreadMethod sm = grad->spreadMethod(); - paint->setShader(grad->getShader(SpreadMethod2TileMode(sm))); - break; - } - default: - break; + if (pat) { + // createPlatformPattern() returns a new inst + paint->setShader(pat->createPlatformPattern(TransformationMatrix()))->safeUnref(); + } else if (grad) { + // grad->getShader() returns a cached obj + GradientSpreadMethod sm = grad->spreadMethod(); + paint->setShader(grad->getShader(SpreadMethod2TileMode(sm))); } } @@ -639,7 +638,7 @@ void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* poin } void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, - const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) + const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace) { if (paintingDisabled()) return; @@ -668,14 +667,14 @@ void GraphicsContext::fillRect(const FloatRect& rect) m_data->setup_paint_fill(&paint); - extactShader(&paint, m_common->state.fillColorSpace, + extactShader(&paint, m_common->state.fillPattern.get(), m_common->state.fillGradient.get()); GC2Canvas(this)->drawRect(rect, paint); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace) { if (paintingDisabled()) return; @@ -752,6 +751,11 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness GC2Canvas(this)->clipPath(path); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const IntRect& r) { if (paintingDisabled()) @@ -831,10 +835,14 @@ void GraphicsContext::endTransparencyLayer() /////////////////////////////////////////////////////////////////////////// + void GraphicsContext::setupBitmapPaint(SkPaint* paint) { + m_data->setup_paint_bitmap(paint); + } + void GraphicsContext::setupFillPaint(SkPaint* paint) { m_data->setup_paint_fill(paint); } - + void GraphicsContext::setupStrokePaint(SkPaint* paint) { m_data->setup_paint_stroke(paint, NULL); } @@ -842,24 +850,8 @@ void GraphicsContext::endTransparencyLayer() bool GraphicsContext::setupShadowPaint(SkPaint* paint, SkPoint* offset) { return m_data->mState->setupShadowPaint(paint, offset); } - - // referenced from CanvasStyle.cpp - void GraphicsContext::setCMYKAFillColor(float c, float m, float y, float k, float a) { - float r = 1 - (c + k); - float g = 1 - (m + k); - float b = 1 - (y + k); - return this->setFillColor(Color(r, g, b, a)); - } - // referenced from CanvasStyle.cpp - void GraphicsContext::setCMYKAStrokeColor(float c, float m, float y, float k, float a) { - float r = 1 - (c + k); - float g = 1 - (m + k); - float b = 1 - (y + k); - return this->setStrokeColor(Color(r, g, b, a)); - } - - void GraphicsContext::setPlatformStrokeColor(const Color& c) { + void GraphicsContext::setPlatformStrokeColor(const Color& c, ColorSpace) { m_data->setStrokeColor(c); } @@ -867,11 +859,11 @@ void GraphicsContext::endTransparencyLayer() m_data->setStrokeThickness(f); } - void GraphicsContext::setPlatformFillColor(const Color& c) { + void GraphicsContext::setPlatformFillColor(const Color& c, ColorSpace) { m_data->setFillColor(c); } -void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color) +void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color, ColorSpace) { if (paintingDisabled()) return; @@ -1038,16 +1030,21 @@ void GraphicsContext::concatCTM(const TransformationMatrix& xform) GC2Canvas(this)->concat((SkMatrix) xform); } +/* This is intended to round the rect to device pixels (through the CTM) + and then invert the result back into source space, with the hope that when + it is drawn (through the matrix), it will land in the "right" place (i.e. + on pixel boundaries). + + For android, we record this geometry once and then draw it though various + scale factors as the user zooms, without re-recording. Thus this routine + should just leave the original geometry alone. + + If we instead draw into bitmap tiles, we should then perform this + transform -> round -> inverse step. + */ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) { - if (paintingDisabled()) - return FloatRect(); - - const SkMatrix& matrix = GC2Canvas(this)->getTotalMatrix(); - SkRect r(rect); - matrix.mapRect(&r); - FloatRect result(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop), SkScalarToFloat(r.width()), SkScalarToFloat(r.height())); - return result; + return rect; } ////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1126,7 +1123,7 @@ void GraphicsContext::fillPath() SkPaint paint; m_data->setup_paint_fill(&paint); - extactShader(&paint, m_common->state.fillColorSpace, + extactShader(&paint, m_common->state.fillPattern.get(), m_common->state.fillGradient.get()); @@ -1142,7 +1139,7 @@ void GraphicsContext::strokePath() SkPaint paint; m_data->setup_paint_stroke(&paint, NULL); - extactShader(&paint, m_common->state.strokeColorSpace, + extactShader(&paint, m_common->state.strokePattern.get(), m_common->state.strokeGradient.get()); @@ -1175,4 +1172,3 @@ SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc) { return gc->platformContext()->mCanvas; } - diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp new file mode 100644 index 0000000..fa012b0 --- /dev/null +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -0,0 +1,851 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" +#include "GraphicsLayerAndroid.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "AndroidAnimation.h" +#include "Animation.h" +#include "CString.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "PlatformBridge.h" +#include "PlatformGraphicsContext.h" +#include "RenderLayerBacking.h" +#include "RenderView.h" +#include "RotateTransformOperation.h" +#include "ScaleTransformOperation.h" +#include "SkCanvas.h" +#include "TransformationMatrix.h" +#include "TranslateTransformOperation.h" + +#include <cutils/log.h> +#include <wtf/CurrentTime.h> + +#undef LOG +#define LOG(...) android_printLog(ANDROID_LOG_DEBUG, "GraphicsLayer", __VA_ARGS__) +#define MLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GraphicsLayer", __VA_ARGS__) +#define TLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GraphicsLayer", __VA_ARGS__) + +#undef LOG +#define LOG(...) +#undef MLOG +#define MLOG(...) +#undef TLOG +#define TLOG(...) +#undef LAYER_DEBUG + +using namespace std; + +static bool gPaused; +static double gPausedDelay; + +namespace WebCore { + +static int gDebugGraphicsLayerAndroidInstances = 0; +inline int GraphicsLayerAndroid::instancesCount() +{ + return gDebugGraphicsLayerAndroidInstances; +} + +static String propertyIdToString(AnimatedPropertyID property) +{ + switch (property) { + case AnimatedPropertyWebkitTransform: + return "transform"; + case AnimatedPropertyOpacity: + return "opacity"; + case AnimatedPropertyBackgroundColor: + return "backgroundColor"; + case AnimatedPropertyInvalid: + ASSERT_NOT_REACHED(); + } + ASSERT_NOT_REACHED(); + return ""; +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation() +{ + return CompositingCoordinatesBottomUp; +} + +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) +{ + return new GraphicsLayerAndroid(client); +} + +GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : + GraphicsLayer(client), + m_needsSyncChildren(false), + m_needsSyncMask(false), + m_needsRepaint(false), + m_needsDisplay(false), + m_haveContents(false), + m_haveImage(false), + m_translateX(0), + m_translateY(0), + m_currentTranslateX(0), + m_currentTranslateY(0), + m_currentPosition(0, 0) +{ + m_contentLayer = new LayerAndroid(true); + if (client) { + RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(client); + RenderLayer* renderLayer = backing->owningLayer(); + m_contentLayer->setIsRootLayer(renderLayer->isRootLayer()); + RenderView* view = static_cast<RenderView*>(renderLayer->renderer()); + if (view->isPositioned() && view->style()->position() == FixedPosition) { + m_contentLayer->setFixedPosition(view->style()->left(), + view->style()->top(), + view->style()->right(), + view->style()->bottom()); + } + } + gDebugGraphicsLayerAndroidInstances++; +} + +GraphicsLayerAndroid::~GraphicsLayerAndroid() +{ + gDebugGraphicsLayerAndroidInstances--; +} + +void GraphicsLayerAndroid::setName(const String& name) +{ + GraphicsLayer::setName(name); +} + +NativeLayer GraphicsLayerAndroid::nativeLayer() const +{ + LOG("(%x) nativeLayer", this); + return 0; +} + +bool GraphicsLayerAndroid::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + if (childrenChanged) { + m_needsSyncChildren = true; + askForSync(); + } + + return childrenChanged; +} + +void GraphicsLayerAndroid::addChild(GraphicsLayer* childLayer) +{ +#ifndef NDEBUG + const char* n = (static_cast<GraphicsLayerAndroid*>(childLayer))->m_name.latin1().data(); + LOG("(%x) addChild: %x (%s)", this, childLayer, n); +#endif + GraphicsLayer::addChild(childLayer); + m_needsSyncChildren = true; + askForSync(); +} + +void GraphicsLayerAndroid::addChildAtIndex(GraphicsLayer* childLayer, int index) +{ + LOG("(%x) addChild %x AtIndex %d", this, childLayer, index); + GraphicsLayer::addChildAtIndex(childLayer, index); + m_needsSyncChildren = true; + askForSync(); +} + +void GraphicsLayerAndroid::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + LOG("(%x) addChild %x Below %x", this, childLayer, sibling); + GraphicsLayer::addChildBelow(childLayer, sibling); + m_needsSyncChildren = true; + askForSync(); +} + +void GraphicsLayerAndroid::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + LOG("(%x) addChild %x Above %x", this, childLayer, sibling); + GraphicsLayer::addChildAbove(childLayer, sibling); + m_needsSyncChildren = true; + askForSync(); +} + +bool GraphicsLayerAndroid::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + LOG("(%x) replaceChild %x by %x", this, oldChild, newChild); + bool ret = GraphicsLayer::replaceChild(oldChild, newChild); + m_needsSyncChildren = true; + askForSync(); + return ret; +} + +void GraphicsLayerAndroid::removeFromParent() +{ + LOG("(%x) removeFromParent()", this); + if (m_parent) + static_cast<GraphicsLayerAndroid*>(m_parent)->needsSyncChildren(); + GraphicsLayer::removeFromParent(); + m_needsSyncChildren = true; + askForSync(); +} + +void GraphicsLayerAndroid::needsSyncChildren() +{ + m_needsSyncChildren = true; + askForSync(); +} + +void GraphicsLayerAndroid::setPosition(const FloatPoint& point) +{ + m_currentPosition = point; + m_needsDisplay = true; +#ifdef LAYER_DEBUG_2 + LOG("(%x) setPosition(%.2f,%.2f) pos(%.2f, %.2f) anchor(%.2f,%.2f) size(%.2f, %.2f)", + this, point.x(), point.y(), m_currentPosition.x(), m_currentPosition.y(), + m_anchorPoint.x(), m_anchorPoint.y(), m_size.width(), m_size.height()); +#endif + askForSync(); +} + +void GraphicsLayerAndroid::setAnchorPoint(const FloatPoint3D& point) +{ + GraphicsLayer::setAnchorPoint(point); + m_contentLayer->setAnchorPoint(point); + askForSync(); +} + +void GraphicsLayerAndroid::setSize(const FloatSize& size) +{ + if ((size.width() != m_size.width()) + || (size.height() != m_size.height())) { + MLOG("(%x) setSize (%.2f,%.2f)", this, size.width(), size.height()); + GraphicsLayer::setSize(size); + m_contentLayer->setSize(size); + askForSync(); + } +} + +void GraphicsLayerAndroid::setTransform(const TransformationMatrix& t) +{ + TransformationMatrix::DecomposedType tDecomp; + t.decompose(tDecomp); + LOG("(%x) setTransform, translate (%.2f, %.2f), mpos(%.2f,%.2f)", + this, tDecomp.translateX, tDecomp.translateY, + m_position.x(), m_position.y()); + + if ((m_currentTranslateX != tDecomp.translateX) + || (m_currentTranslateY != tDecomp.translateY)) { + m_currentTranslateX = tDecomp.translateX; + m_currentTranslateY = tDecomp.translateY; + m_needsDisplay = true; + askForSync(); + } +} + +void GraphicsLayerAndroid::setChildrenTransform(const TransformationMatrix& t) +{ + if (t == m_childrenTransform) + return; + LOG("(%x) setChildrenTransform", this); + + GraphicsLayer::setChildrenTransform(t); + for (unsigned int i = 0; i < m_children.size(); i++) { + GraphicsLayer* layer = m_children[i]; + layer->setTransform(t); + if (layer->children().size()) + layer->setChildrenTransform(t); + } + askForSync(); +} + +void GraphicsLayerAndroid::setMaskLayer(GraphicsLayer* layer) +{ + if (layer == m_maskLayer) + return; + + GraphicsLayer::setMaskLayer(layer); + m_needsSyncMask = true; + askForSync(); +} + +void GraphicsLayerAndroid::setMasksToBounds(bool masksToBounds) +{ + GraphicsLayer::setMasksToBounds(masksToBounds); + m_needsSyncMask = true; + askForSync(); +} + +void GraphicsLayerAndroid::setDrawsContent(bool drawsContent) +{ + GraphicsLayer::setDrawsContent(drawsContent); + m_contentLayer->setDrawsContent(m_drawsContent); + + if (m_drawsContent) { + m_haveContents = true; + m_contentLayer->setHaveContents(true); + setNeedsDisplay(); + } + askForSync(); +} + +void GraphicsLayerAndroid::setBackgroundColor(const Color& color) +{ + LOG("(%x) setBackgroundColor", this); + GraphicsLayer::setBackgroundColor(color); + m_contentLayer->setBackgroundColor(color); + m_haveContents = true; + askForSync(); +} + +void GraphicsLayerAndroid::clearBackgroundColor() +{ + LOG("(%x) clearBackgroundColor", this); + GraphicsLayer::clearBackgroundColor(); + askForSync(); +} + +void GraphicsLayerAndroid::setContentsOpaque(bool opaque) +{ + LOG("(%x) setContentsOpaque (%d)", this, opaque); + GraphicsLayer::setContentsOpaque(opaque); + m_haveContents = true; + m_contentLayer->setHaveContents(true); + m_contentLayer->setDrawsContent(true); + askForSync(); +} + +void GraphicsLayerAndroid::setOpacity(float opacity) +{ + LOG("(%x) setOpacity: %.2f", this, opacity); + float clampedOpacity = max(0.0f, min(opacity, 1.0f)); + + if (clampedOpacity == m_opacity) + return; + + MLOG("(%x) setFinalOpacity: %.2f=>%.2f (%.2f)", this, + opacity, clampedOpacity, m_opacity); + GraphicsLayer::setOpacity(clampedOpacity); + m_contentLayer->setOpacity(clampedOpacity); + askForSync(); +} + +bool GraphicsLayerAndroid::repaintAll() +{ + LOG("(%x) repaintAll", this); + bool ret = false; + for (unsigned int i = 0; i < m_children.size(); i++) { + GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]); + if (layer && layer->repaintAll()) + ret = true; + } + int nbRects = m_invalidatedRects.size(); + + for (int i = 0; !gPaused && i < nbRects; i++) { + FloatRect rect = m_invalidatedRects[i]; + if (repaint(rect)) + ret = true; + } + if (!gPaused) { + m_needsRepaint = false; + m_invalidatedRects.clear(); + } + return ret; +} + +void GraphicsLayerAndroid::setNeedsDisplay() +{ + LOG("(%x) setNeedsDisplay()", this); + FloatRect rect(0, 0, m_size.width(), m_size.height()); + setNeedsDisplayInRect(rect); +} + +void GraphicsLayerAndroid::setFrame(Frame* f) +{ + m_frame = f; +} + +void GraphicsLayerAndroid::sendImmediateRepaint() +{ + LOG("(%x) sendImmediateRepaint()", this); + GraphicsLayerAndroid* rootGraphicsLayer = this; + + while (rootGraphicsLayer->parent()) + rootGraphicsLayer = static_cast<GraphicsLayerAndroid*>(rootGraphicsLayer->parent()); + + if (rootGraphicsLayer->m_frame + && rootGraphicsLayer->m_frame->view()) { + LayerAndroid* copyLayer = new LayerAndroid(m_contentLayer.get()); + TLOG("(%x) sendImmediateRepaint, copy the layer, (%.2f,%.2f => %.2f,%.2f)", + this, m_contentLayer->size().width(), m_contentLayer->size().height(), + copyLayer->size().width(), copyLayer->size().height()); + PlatformBridge::setRootLayer(m_frame->view(), (int)copyLayer); + PlatformBridge::immediateRepaint(m_frame->view()); + } +} + +bool GraphicsLayerAndroid::repaint(const FloatRect& rect) +{ + LOG("(%x) repaint(%.2f,%.2f,%.2f,%.2f), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", + this, rect.x(), rect.y(), rect.width(), rect.height(), + gPaused, m_needsRepaint, m_haveContents); + + m_contentLayer->setDrawsContent(true); + + if (!gPaused && m_haveContents && m_needsRepaint) { + SkAutoPictureRecord arp(m_contentLayer->recordContext(), m_size.width(), m_size.height()); + SkCanvas* recordingCanvas = arp.getRecordingCanvas(); + + if (!recordingCanvas) + return false; + + if ((rect.width() > 0.5) && (rect.height() > 0.5)) { + IntRect r((int)rect.x(), (int)rect.y(), + (int)rect.width(), (int)rect.height()); + + PlatformGraphicsContext pgc(recordingCanvas, 0); + GraphicsContext gc(&pgc); + + // with SkPicture, we request the entire layer's content. + r.setX(0); + r.setY(0); + r.setWidth(m_contentLayer->size().width()); + r.setHeight(m_contentLayer->size().height()); + paintGraphicsLayerContents(gc, r); + + TLOG("(%x) repaint(%.2f,%.2f,%.2f,%.2f) on (%.2f,%.2f) contentlayer(%.2f,%.2f,%.2f,%.2f)paintGraphicsLayer called!", + this, rect.x(), rect.y(), rect.width(), + rect.height(), m_size.width(), m_size.height(), + m_contentLayer->position().x(), + m_contentLayer->position().y(), + m_contentLayer->size().width(), + m_contentLayer->size().height()); + } + return true; + } + return false; +} + +void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) +{ + for (unsigned int i = 0; i < m_children.size(); i++) { + GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]); + if (layer) { + FloatRect childrenRect(m_position.x() + m_translateX + rect.x(), + m_position.y() + m_translateY + rect.y(), + rect.width(), rect.height()); + layer->setNeedsDisplayInRect(childrenRect); + } + } + if (!m_haveImage && !drawsContent()) { + LOG("(%x) setNeedsDisplay(%.2f,%.2f,%.2f,%.2f) doesn't have content, bypass...", + this, rect.x(), rect.y(), rect.width(), rect.height()); + return; + } + + const size_t maxDirtyRects = 8; + for (size_t i = 0; i < m_invalidatedRects.size(); ++i) { + if (m_invalidatedRects[i].contains(rect)) + return; + } + +#ifdef LAYER_DEBUG + LOG("(%x) setNeedsDisplayInRect(%d) - (%.2f, %.2f, %.2f, %.2f)", this, + m_needsRepaint, rect.x(), rect.y(), rect.width(), rect.height()); +#endif + + if (m_invalidatedRects.size() < maxDirtyRects) + m_invalidatedRects.append(rect); + else + m_invalidatedRects[0].unite(rect); + + m_needsRepaint = true; + askForSync(); +} + +void GraphicsLayerAndroid::pauseDisplay(bool state) +{ + gPaused = state; + if (gPaused) + gPausedDelay = WTF::currentTime() + 1; +} + +bool GraphicsLayerAndroid::addAnimation(const KeyframeValueList& valueList, + const IntSize& boxSize, + const Animation* anim, + const String& keyframesName, + double beginTime) +{ + if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) + return false; + + bool createdAnimations = false; + if (valueList.property() == AnimatedPropertyWebkitTransform) { + createdAnimations = createTransformAnimationsFromKeyframes(valueList, + anim, + keyframesName, + beginTime, + boxSize); + } else { + createdAnimations = createAnimationFromKeyframes(valueList, + anim, + keyframesName, + beginTime); + } + askForSync(); + return createdAnimations; +} + +bool GraphicsLayerAndroid::createAnimationFromKeyframes(const KeyframeValueList& valueList, + const Animation* animation, const String& keyframesName, double beginTime) +{ + bool isKeyframe = valueList.size() > 2; + TLOG("createAnimationFromKeyframes(%d), name(%s) beginTime(%.2f)", + isKeyframe, keyframesName.latin1().data(), beginTime); + // TODO: handles keyframe animations correctly + + switch (valueList.property()) { + case AnimatedPropertyInvalid: break; + case AnimatedPropertyWebkitTransform: break; + case AnimatedPropertyBackgroundColor: break; + case AnimatedPropertyOpacity: { + MLOG("ANIMATEDPROPERTYOPACITY"); + const FloatAnimationValue* startVal = + static_cast<const FloatAnimationValue*>(valueList.at(0)); + const FloatAnimationValue* endVal = + static_cast<const FloatAnimationValue*>(valueList.at(1)); + RefPtr<AndroidOpacityAnimation> anim = AndroidOpacityAnimation::create(m_contentLayer.get(), + startVal->value(), + endVal->value(), + animation, + beginTime); + if (keyframesName.isEmpty()) + anim->setName(propertyIdToString(valueList.property())); + else + anim->setName(keyframesName); + + m_contentLayer->addAnimation(anim.release()); + AndroidAnimationTimer* timer = new AndroidAnimationTimer(this, WTF::currentTime()); + timer->startOneShot(0); + return true; + } break; + } + return false; +} + +bool GraphicsLayerAndroid::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, + const Animation* animation, + const String& keyframesName, + double beginTime, + const IntSize& boxSize) +{ + ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); + TLOG("createTransformAnimationFromKeyframes, name(%s) beginTime(%.2f)", + keyframesName.latin1().data(), beginTime); + + TransformOperationList functionList; + bool listsMatch, hasBigRotation; + fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation); + + // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation. + // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation + // if that's not true as well. + + bool isMatrixAnimation = !listsMatch; + size_t numAnimations = isMatrixAnimation ? 1 : functionList.size(); + bool isKeyframe = valueList.size() > 2; + + float fromTranslateX = 0; + float fromTranslateY = 0; + float fromTranslateZ = 0; + float toTranslateX = 0; + float toTranslateY = 0; + float toTranslateZ = 0; + float fromAngle = 0; + float toAngle = 0; + float fromScaleX = 1; + float fromScaleY = 1; + float fromScaleZ = 1; + float toScaleX = 1; + float toScaleY = 1; + float toScaleZ = 1; + + bool doTranslation = false; + bool doRotation = false; + bool doScaling = false; + + TLOG("(%x) animateTransform, valueList(%d) functionList(%d) duration(%.2f)", this, + valueList.size(), functionList.size(), animation->duration()); + + for (unsigned int i = 0; i < valueList.size(); i++) { + const TransformOperations* operation = ((TransformAnimationValue*)valueList.at(i))->value(); + Vector<RefPtr<TransformOperation> > ops = operation->operations(); + TLOG("(%x) animateTransform, dealing with the %d operation, with %d ops", this, i, ops.size()); + for (unsigned int j = 0; j < ops.size(); j++) { + TransformOperation* op = ops[j].get(); + TLOG("(%x) animateTransform, dealing with the %d:%d operation, current op: %d (translate is %d, rotate %d, scale %d)", + this, i, j, op->getOperationType(), TransformOperation::TRANSLATE, TransformOperation::ROTATE, TransformOperation::SCALE); + if (op->getOperationType() == TransformOperation::TRANSLATE) { + TranslateTransformOperation* translateOperation = (TranslateTransformOperation*) op; + IntSize bounds(m_size.width(), m_size.height()); + float x = translateOperation->x(bounds); + float y = translateOperation->y(bounds); + float z = translateOperation->z(bounds); + if (!i) { + fromTranslateX = x; + fromTranslateY = y; + fromTranslateZ = z; + } else { + toTranslateX = x; + toTranslateY = y; + toTranslateZ = z; + } + TLOG("(%x) animateTransform, the %d operation is a translation(%.2f,%.2f,%.2f)", + this, j, x, y, z); + doTranslation = true; + } else if (op->getOperationType() == TransformOperation::TRANSLATE_X) { + TranslateTransformOperation* translateOperation = (TranslateTransformOperation*) op; + IntSize bounds(m_size.width(), m_size.height()); + float x = translateOperation->x(bounds); + if (!i) + fromTranslateX = x; + else + toTranslateX = x; + TLOG("(%x) animateTransform, the %d operation is a translation_x(%.2f)", + this, j, x); + doTranslation = true; + } else if (op->getOperationType() == TransformOperation::TRANSLATE_Y) { + TranslateTransformOperation* translateOperation = (TranslateTransformOperation*) op; + IntSize bounds(m_size.width(), m_size.height()); + float y = translateOperation->y(bounds); + if (!i) + fromTranslateY = y; + else + toTranslateY = y; + TLOG("(%x) animateTransform, the %d operation is a translation_y(%.2f)", + this, j, y); + doTranslation = true; + } else if ((op->getOperationType() == TransformOperation::ROTATE) + || (op->getOperationType() == TransformOperation::ROTATE_X) + || (op->getOperationType() == TransformOperation::ROTATE_Y)) { + LOG("(%x) animateTransform, the %d operation is a rotation", this, j); + RotateTransformOperation* rotateOperation = (RotateTransformOperation*) op; + float angle = rotateOperation->angle(); + TLOG("(%x) animateTransform, the %d operation is a rotation (%d), of angle %.2f", + this, j, op->getOperationType(), angle); + + if (!i) + fromAngle = angle; + else + toAngle = angle; + doRotation = true; + } else if (op->getOperationType() == TransformOperation::SCALE_X) { + ScaleTransformOperation* scaleOperation = (ScaleTransformOperation*) op; + if (!i) + fromScaleX = scaleOperation->x(); + else + toScaleX = scaleOperation->x(); + doScaling = true; + } else if (op->getOperationType() == TransformOperation::SCALE_Y) { + ScaleTransformOperation* scaleOperation = (ScaleTransformOperation*) op; + if (!i) + fromScaleY = scaleOperation->y(); + else + toScaleY = scaleOperation->y(); + doScaling = true; + } else if (op->getOperationType() == TransformOperation::SCALE_Z) { + ScaleTransformOperation* scaleOperation = (ScaleTransformOperation*) op; + if (!i) + fromScaleZ = scaleOperation->z(); + else + toScaleZ = scaleOperation->z(); + doScaling = true; + } else if (op->getOperationType() == TransformOperation::SCALE) { + ScaleTransformOperation* scaleOperation = (ScaleTransformOperation*) op; + if (!i) { + fromScaleX = scaleOperation->x(); + fromScaleY = scaleOperation->y(); + fromScaleZ = scaleOperation->z(); + } else { + toScaleX = scaleOperation->x(); + toScaleY = scaleOperation->y(); + toScaleZ = scaleOperation->z(); + } + doScaling = true; + } else { + TLOG("(%x) animateTransform, the %d operation is not a rotation (%d)", + this, j, op->getOperationType()); + } + } + } + + RefPtr<AndroidTransformAnimation> anim = AndroidTransformAnimation::create(m_contentLayer.get(), + animation, beginTime); + + if (keyframesName.isEmpty()) + anim->setName(propertyIdToString(valueList.property())); + else + anim->setName(keyframesName); + + anim->setOriginalPosition(m_position); + + if (doTranslation) + anim->setTranslation(fromTranslateX, fromTranslateY, fromTranslateZ, + toTranslateX, toTranslateY, toTranslateZ); + if (doRotation) + anim->setRotation(fromAngle, toAngle); + if (doScaling) + anim->setScale(fromScaleX, fromScaleY, fromScaleZ, + toScaleX, toScaleY, toScaleZ); + m_contentLayer->addAnimation(anim.release()); + + AndroidAnimationTimer* timer = new AndroidAnimationTimer(this, WTF::currentTime()); + timer->startOneShot(0); + return true; +} + +void GraphicsLayerAndroid::removeAnimationsForProperty(AnimatedPropertyID anID) +{ + TLOG("NRO removeAnimationsForProperty(%d)", anID); + m_contentLayer->removeAnimation(propertyIdToString(anID)); + askForSync(); +} + +void GraphicsLayerAndroid::removeAnimationsForKeyframes(const String& keyframesName) +{ + TLOG("NRO removeAnimationsForKeyframes(%s)", keyframesName.latin1().data()); + m_contentLayer->removeAnimation(keyframesName); + askForSync(); +} + +void GraphicsLayerAndroid::pauseAnimation(const String& keyframesName) +{ + TLOG("NRO pauseAnimation(%s)", keyframesName.latin1().data()); +} + +void GraphicsLayerAndroid::suspendAnimations(double time) +{ + TLOG("NRO suspendAnimations(%.2f)", time); +} + +void GraphicsLayerAndroid::resumeAnimations() +{ + TLOG("NRO resumeAnimations()"); +} + +void GraphicsLayerAndroid::setContentsToImage(Image* image) +{ + TLOG("(%x) setContentsToImage", this, image); + if (image) { + m_haveContents = true; + m_contentLayer->setHaveContents(true); + m_contentLayer->setDrawsContent(true); + m_contentLayer->setHaveImage(true); + if (!m_haveImage) { + m_haveImage = true; + setNeedsDisplay(); + askForSync(); + } + } else + m_contentLayer->setHaveImage(false); +} + +PlatformLayer* GraphicsLayerAndroid::platformLayer() const +{ + LOG("platformLayer"); + return (PlatformLayer*) m_contentLayer.get(); +} + +#ifndef NDEBUG +void GraphicsLayerAndroid::setDebugBackgroundColor(const Color& color) +{ +} + +void GraphicsLayerAndroid::setDebugBorder(const Color& color, float borderWidth) +{ +} +#endif + +void GraphicsLayerAndroid::setZPosition(float position) +{ + LOG("(%x) setZPosition: %.2f", this, position); + GraphicsLayer::setZPosition(position); + askForSync(); +} + +void GraphicsLayerAndroid::askForSync() +{ + if (m_client) + m_client->notifySyncRequired(this); +} + +void GraphicsLayerAndroid::syncChildren() +{ + if (m_needsSyncChildren) { + m_contentLayer->removeAllChildren(); + for (unsigned int i = 0; i < m_children.size(); i++) { + m_contentLayer->addChildren( + (static_cast<GraphicsLayerAndroid*>(m_children[i]))->contentLayer()); + } + m_needsSyncChildren = false; + } +} + +void GraphicsLayerAndroid::syncMask() +{ + if (m_needsSyncMask) { + if (m_maskLayer) { + GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_maskLayer); + LayerAndroid* mask = reinterpret_cast<LayerAndroid*>(layer->platformLayer()); + m_contentLayer->setMaskLayer(mask); + } else + m_contentLayer->setMaskLayer(0); + + m_contentLayer->setMasksToBounds(m_masksToBounds); + m_needsSyncMask = false; + } +} + +void GraphicsLayerAndroid::syncPositionState() +{ + if (m_needsDisplay) { + m_translateX = m_currentTranslateX; + m_translateY = m_currentTranslateY; + m_position = m_currentPosition; + FloatPoint translation(m_currentTranslateX, m_currentTranslateY); + m_contentLayer->setTranslation(translation); + m_contentLayer->setPosition(m_currentPosition); + m_needsDisplay = false; + } +} + +void GraphicsLayerAndroid::syncCompositingState() +{ + for (unsigned int i = 0; i < m_children.size(); i++) { + GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]); + layer->syncCompositingState(); + } + + syncChildren(); + syncMask(); + syncPositionState(); + + if (!gPaused || WTF::currentTime() >= gPausedDelay) + repaintAll(); +} + + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h new file mode 100644 index 0000000..fc88fbf --- /dev/null +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GraphicsLayerAndroid_h +#define GraphicsLayerAndroid_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "FloatRect.h" +#include "Frame.h" +#include "GraphicsLayer.h" +#include "GraphicsLayerClient.h" +#include "LayerAndroid.h" +#include "RefPtr.h" +#include "Vector.h" + +class FloatPoint3D; +class Image; + +namespace WebCore { + +class GraphicsLayerAndroid : public GraphicsLayer { +public: + + GraphicsLayerAndroid(GraphicsLayerClient*); + virtual ~GraphicsLayerAndroid(); + + virtual void setName(const String&); + + // for hosting this GraphicsLayer in a native layer hierarchy + virtual NativeLayer nativeLayer() const; + + virtual bool setChildren(const Vector<GraphicsLayer*>&); + virtual void addChild(GraphicsLayer*); + virtual void addChildAtIndex(GraphicsLayer*, int index); + virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling); + virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling); + virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild); + + virtual void removeFromParent(); + + virtual void setPosition(const FloatPoint&); + virtual void setAnchorPoint(const FloatPoint3D&); + virtual void setSize(const FloatSize&); + + virtual void setTransform(const TransformationMatrix&); + + virtual void setChildrenTransform(const TransformationMatrix&); + + virtual void setMaskLayer(GraphicsLayer*); + virtual void setMasksToBounds(bool); + virtual void setDrawsContent(bool); + + virtual void setBackgroundColor(const Color&); + virtual void clearBackgroundColor(); + + virtual void setContentsOpaque(bool); + + virtual void setOpacity(float); + + virtual void setNeedsDisplay(); + virtual void setNeedsDisplayInRect(const FloatRect&); + + virtual bool addAnimation(const KeyframeValueList& valueList, + const IntSize& boxSize, + const Animation* anim, + const String& keyframesName, + double beginTime); + bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, + const Animation*, + const String& keyframesName, + double beginTime, + const IntSize& boxSize); + bool createAnimationFromKeyframes(const KeyframeValueList&, + const Animation*, + const String& keyframesName, + double beginTime); + + virtual void removeAnimationsForProperty(AnimatedPropertyID); + virtual void removeAnimationsForKeyframes(const String& keyframesName); + virtual void pauseAnimation(const String& keyframesName); + + virtual void suspendAnimations(double time); + virtual void resumeAnimations(); + + virtual void setContentsToImage(Image*); + bool repaintAll(); + virtual PlatformLayer* platformLayer() const; + + void pauseDisplay(bool state); + +#ifndef NDEBUG + virtual void setDebugBackgroundColor(const Color&); + virtual void setDebugBorder(const Color&, float borderWidth); +#endif + + virtual void setZPosition(float); + + void askForSync(); + void syncPositionState(); + void needsSyncChildren(); + void syncChildren(); + void syncMask(); + virtual void syncCompositingState(); + void setFrame(Frame*); + + void sendImmediateRepaint(); + LayerAndroid* contentLayer() { return m_contentLayer.get(); } + + static int instancesCount(); + +private: + + bool repaint(const FloatRect& rect); + + bool m_needsSyncChildren; + bool m_needsSyncMask; + bool m_needsRepaint; + bool m_needsDisplay; + + bool m_haveContents; + bool m_haveImage; + + float m_translateX; + float m_translateY; + float m_currentTranslateX; + float m_currentTranslateY; + + FloatPoint m_currentPosition; + + RefPtr<Frame> m_frame; + + Vector<FloatRect> m_invalidatedRects; + + RefPtr<LayerAndroid> m_contentLayer; +}; + +} // namespace WebCore + + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // GraphicsLayerAndroid_h diff --git a/WebCore/platform/graphics/android/ImageAndroid.cpp b/WebCore/platform/graphics/android/ImageAndroid.cpp index 16a450f..486200d 100644 --- a/WebCore/platform/graphics/android/ImageAndroid.cpp +++ b/WebCore/platform/graphics/android/ImageAndroid.cpp @@ -5,23 +5,23 @@ * 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 + * * 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 + * * 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 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -186,7 +186,8 @@ static inline void fixPaintForBitmapsThatMaySeam(SkPaint* paint) { } void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, - const FloatRect& srcRect, CompositeOperator compositeOp) + const FloatRect& srcRect, ColorSpace, + CompositeOperator compositeOp) { startAnimation(); @@ -224,7 +225,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, SkCanvas* canvas = ctxt->platformContext()->mCanvas; SkPaint paint; - ctxt->setupFillPaint(&paint); // need global alpha among other things + ctxt->setupBitmapPaint(&paint); // need global alpha among other things paint.setFilterBitmap(true); paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp)); fixPaintForBitmapsThatMaySeam(&paint); @@ -249,8 +250,8 @@ void BitmapImage::setURL(const String& str) void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator compositeOp, - const FloatRect& destRect) + const FloatPoint& phase, ColorSpace, + CompositeOperator compositeOp, const FloatRect& destRect) { SkBitmapRef* image = this->nativeImageForCurrentFrame(); if (!image) { // If it's too early we won't have an image yet. @@ -292,7 +293,7 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, SkCanvas* canvas = ctxt->platformContext()->mCanvas; SkPaint paint; - ctxt->setupFillPaint(&paint); // need global alpha among other things + ctxt->setupBitmapPaint(&paint); // need global alpha among other things SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kRepeat_TileMode, @@ -366,4 +367,3 @@ PassRefPtr<Image> Image::loadPlatformResource(const char *name) } } // namespace - diff --git a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp index 89d841d..6efccfe 100644 --- a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp +++ b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -86,7 +86,7 @@ Image* ImageBuffer::image() const return m_image.get(); } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { GraphicsContext* gc = this->context(); if (!gc) { @@ -149,7 +149,7 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) { GraphicsContext* gc = this->context(); if (!gc) { diff --git a/WebCore/platform/graphics/android/ImageBufferData.h b/WebCore/platform/graphics/android/ImageBufferData.h index 7d8cd3b..269b365 100644 --- a/WebCore/platform/graphics/android/ImageBufferData.h +++ b/WebCore/platform/graphics/android/ImageBufferData.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp index 5c75a15..ba65e92 100644 --- a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp +++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -37,6 +37,12 @@ #include "SkStream.h" #include "SkTemplates.h" +// need a flag to tell us when we're on a large-ram device (e.g. >= 256M) +// for now just use this hack +#if 1 + #define ON_LARGE_RAM_DEVICE +#endif + #ifdef ANDROID_ANIMATED_GIF #include "EmojiFont.h" #include "gif/GIFImageDecoder.h" @@ -44,15 +50,25 @@ using namespace android; #endif +// TODO: We should make use of some of the common code in platform/graphics/ImageSource.cpp. + SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src); //#define TRACE_SUBSAMPLE_BITMAPS //#define TRACE_RLE_BITMAPS -// don't use RLE for images smaller than this, since they incur a drawing cost -// (and don't work as patterns yet) we only want to use RLE when we must -#define MIN_RLE_ALLOC_SIZE (2*1024*1024) +#ifdef ON_LARGE_RAM_DEVICE + // don't use RLE for images smaller than this, since they incur a drawing cost + // (and don't work as patterns yet) we only want to use RLE when we must + #define MIN_RLE_ALLOC_SIZE (8*1024*1024) + + // see dox for computeMaxBitmapSizeForCache() + #define MAX_SIZE_BEFORE_SUBSAMPLE (8*1024*1024) +#else + #define MIN_RLE_ALLOC_SIZE (2*1024*1024) + #define MAX_SIZE_BEFORE_SUBSAMPLE (2*1024*1024) +#endif /* Images larger than this should be subsampled. Using ashmem, the decoded pixels will be purged as needed, so this value can be pretty large. Making @@ -65,7 +81,7 @@ SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src); Perhaps this value should be some fraction of the available RAM... */ static size_t computeMaxBitmapSizeForCache() { - return 2*1024*1024; + return MAX_SIZE_BEFORE_SUBSAMPLE; } /* 8bit images larger than this should be recompressed in RLE, to reduce diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp new file mode 100644 index 0000000..3b5d5b5 --- /dev/null +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -0,0 +1,383 @@ +#include "config.h" +#include "LayerAndroid.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "AndroidAnimation.h" +#include "CString.h" +#include "GraphicsLayerAndroid.h" +#include "PlatformGraphicsContext.h" +#include "RenderLayer.h" +#include "RenderLayerBacking.h" +#include "RenderView.h" +#include "SkDevice.h" +#include "SkDrawFilter.h" +#include <wtf/CurrentTime.h> + +#define LAYER_DEBUG // Add diagonals for debugging +#undef LAYER_DEBUG + +namespace WebCore { + +static int gDebugLayerAndroidInstances; +inline int LayerAndroid::instancesCount() +{ + return gDebugLayerAndroidInstances; +} + +class OpacityDrawFilter : public SkDrawFilter { + public: + OpacityDrawFilter(int opacity) : m_opacity(opacity) { } + virtual bool filter(SkCanvas* canvas, SkPaint* paint, Type) + { + m_previousOpacity = paint->getAlpha(); + paint->setAlpha(m_opacity); + return true; + } + virtual void restore(SkCanvas* canvas, SkPaint* paint, Type) + { + paint->setAlpha(m_previousOpacity); + } + private: + int m_opacity; + int m_previousOpacity; +}; + +PassRefPtr<LayerAndroid> LayerAndroid::create(bool isRootLayer) +{ + return adoptRef(new LayerAndroid(isRootLayer)); +} + +LayerAndroid::LayerAndroid(bool isRootLayer) : + m_doRotation(false), + m_isRootLayer(isRootLayer), + m_isFixed(false), + m_haveContents(false), + m_drawsContent(true), + m_haveImage(false), + m_haveClip(false), + m_backgroundColorSet(false), + m_angleTransform(0), + m_opacity(1), + m_size(0, 0), + m_position(0, 0), + m_translation(0, 0), + m_anchorPoint(0, 0, 0), + m_scale(1, 1, 1), + m_fixedLeft(Auto), + m_fixedTop(Auto), + m_fixedRight(Auto), + m_fixedBottom(Auto), + m_recordingPicture(0) +{ + gDebugLayerAndroidInstances++; +} + +LayerAndroid::LayerAndroid(LayerAndroid* layer) : + m_doRotation(layer->m_doRotation), + m_isRootLayer(layer->m_isRootLayer), + m_isFixed(layer->m_isFixed), + m_haveContents(layer->m_haveContents), + m_drawsContent(layer->m_drawsContent), + m_haveImage(layer->m_haveImage), + m_haveClip(layer->m_haveClip), + m_backgroundColorSet(layer->m_backgroundColorSet), + m_angleTransform(layer->m_angleTransform), + m_opacity(layer->m_opacity), + m_size(layer->m_size), + m_position(layer->m_position), + m_translation(layer->m_translation), + m_anchorPoint(layer->m_anchorPoint), + m_scale(layer->m_scale), + m_fixedLeft(layer->m_fixedLeft), + m_fixedRight(layer->m_fixedRight), + m_fixedTop(layer->m_fixedTop), + m_fixedBottom(layer->m_fixedBottom) +{ + if (layer->m_recordingPicture) { + layer->m_recordingPicture->ref(); + m_recordingPicture = layer->m_recordingPicture; + } else + m_recordingPicture = 0; + + for (unsigned int i = 0; i < layer->m_children.size(); i++) + m_children.append(adoptRef(new LayerAndroid(layer->m_children[i].get()))); + + KeyframesMap::const_iterator end = layer->m_animations.end(); + for (KeyframesMap::const_iterator it = layer->m_animations.begin(); it != end; ++it) + m_animations.add((it->second)->name(), adoptRef((it->second)->copy())); + + end = m_animations.end(); + for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) + (it->second)->setLayer(this); + + gDebugLayerAndroidInstances++; +} + +LayerAndroid::~LayerAndroid() +{ + m_recordingPicture->safeUnref(); + m_children.clear(); + m_animations.clear(); + gDebugLayerAndroidInstances--; +} + +static int gDebugNbAnims = 0; + +Vector<RefPtr<AndroidAnimationValue> >* LayerAndroid::evaluateAnimations() const +{ + double time = WTF::currentTime(); + Vector<RefPtr<AndroidAnimationValue> >* result = new Vector<RefPtr<AndroidAnimationValue> >(); + gDebugNbAnims = 0; + if (evaluateAnimations(time, result)) + return result; + return 0; +} + +bool LayerAndroid::hasAnimations() const +{ + for (unsigned int i = 0; i < m_children.size(); i++) { + if (m_children[i]->hasAnimations()) + return true; + } + return !!m_animations.size(); +} + +bool LayerAndroid::evaluateAnimations(double time, + Vector<RefPtr<AndroidAnimationValue> >* result) const +{ + bool hasRunningAnimations = false; + for (unsigned int i = 0; i < m_children.size(); i++) { + if (m_children[i]->evaluateAnimations(time, result)) + hasRunningAnimations = true; + } + KeyframesMap::const_iterator end = m_animations.end(); + for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) { + gDebugNbAnims++; + if ((it->second)->evaluate(time)) { + result->append((it->second)->result()); + hasRunningAnimations = true; + } + } + + return hasRunningAnimations; +} + +void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> anim) +{ + m_animations.add(anim->name(), anim); +} + +void LayerAndroid::removeAnimation(const String& name) +{ + m_animations.remove(name); +} + +void LayerAndroid::setFixedPosition(Length left, Length top, + Length right, Length bottom) +{ + m_fixedLeft = left; + m_fixedTop = top; + m_fixedRight = right; + m_fixedBottom = bottom; + m_isFixed = true; +} + +void LayerAndroid::setDrawsContent(bool drawsContent) +{ + m_drawsContent = drawsContent; + for (unsigned int i = 0; i < m_children.size(); i++) { + LayerAndroid* layer = m_children[i].get(); + layer->setDrawsContent(drawsContent); + } +} + +// We only use the bounding rect of the layer as mask... +// TODO: use a real mask? +void LayerAndroid::setMaskLayer(LayerAndroid* layer) +{ + if (layer) + m_haveClip = true; +} + +void LayerAndroid::setMasksToBounds(bool masksToBounds) +{ + m_haveClip = masksToBounds; +} + +void LayerAndroid::setBackgroundColor(const Color& color) +{ + m_backgroundColor = color; + m_backgroundColorSet = true; + setHaveContents(true); + setDrawsContent(true); +} + +static int gDebugChildLevel; + +void LayerAndroid::paintOn(int scrollX, int scrollY, + int width, int height, + float scale, SkCanvas* canvas) +{ + gDebugChildLevel = 0; + paintChildren(scrollX, scrollY, width, height, scale, canvas, 1); +} + +void LayerAndroid::setClip(SkCanvas* canvas) +{ + SkRect clip; + clip.fLeft = m_position.x() + m_translation.x(); + clip.fTop = m_position.y() + m_translation.y(); + clip.fRight = clip.fLeft + m_size.width(); + clip.fBottom = clip.fTop + m_size.height(); + canvas->clipRect(clip); +} + +void LayerAndroid::paintChildren(int scrollX, int scrollY, + int width, int height, + float scale, SkCanvas* canvas, + float opacity) +{ + canvas->save(); + + if (m_haveClip) + setClip(canvas); + + paintMe(scrollX, scrollY, width, height, scale, canvas, opacity); + canvas->translate(m_position.x() + m_translation.x(), + m_position.y() + m_translation.y()); + + for (unsigned int i = 0; i < m_children.size(); i++) { + LayerAndroid* layer = m_children[i].get(); + if (layer) { + gDebugChildLevel++; + layer->paintChildren(scrollX, scrollY, width, height, scale, + canvas, opacity * m_opacity); + gDebugChildLevel--; + } + } + + canvas->restore(); +} + +void LayerAndroid::paintMe(int scrollX, + int scrollY, + int viewWidth, + int viewHeight, + float scale, + SkCanvas* canvas, + float opacity) +{ + if (!prepareContext()) + return; + + if (!m_haveImage && !m_drawsContent && !m_isRootLayer) + return; + + SkAutoCanvasRestore restore(canvas, true); + + int canvasOpacity = opacity * m_opacity * 255; + if (canvasOpacity != 255) + canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity)); + + SkPaint paintMode; + if (m_backgroundColorSet) { + paintMode.setARGB(m_backgroundColor.alpha(), + m_backgroundColor.red(), + m_backgroundColor.green(), + m_backgroundColor.blue()); + } else + paintMode.setARGB(0, 0, 0, 0); + + paintMode.setXfermodeMode(SkXfermode::kSrc_Mode); + + float x = 0; + float y = 0; + if (m_isFixed) { + float w = viewWidth / scale; + float h = viewHeight / scale; + float dx = scrollX / scale; + float dy = scrollY / scale; + + if (m_fixedLeft.type()) + x = dx + m_fixedLeft.calcFloatValue(w); + else if (m_fixedRight.type()) + x = dx + w - m_fixedRight.calcFloatValue(w) - m_size.width(); + + if (m_fixedTop.type()) + y = dy + m_fixedTop.calcFloatValue(h); + else if (m_fixedBottom.type()) + y = dy + h - m_fixedBottom.calcFloatValue(h) - m_size.height(); + + } else { + x = m_translation.x() + m_position.x(); + y = m_translation.y() + m_position.y(); + } + + canvas->translate(x, y); + + if (m_doRotation) { + float anchorX = m_anchorPoint.x() * m_size.width(); + float anchorY = m_anchorPoint.y() * m_size.height(); + canvas->translate(anchorX, anchorY); + canvas->rotate(m_angleTransform); + canvas->translate(-anchorX, -anchorY); + } + + float sx = m_scale.x(); + float sy = m_scale.y(); + if (sx > 1.0f || sy > 1.0f) { + float dx = (sx * m_size.width()) - m_size.width(); + float dy = (sy * m_size.height()) - m_size.height(); + canvas->translate(-dx / 2.0f, -dy / 2.0f); + canvas->scale(sx, sy); + } + + m_recordingPicture->draw(canvas); + +#ifdef LAYER_DEBUG + float w = m_size.width(); + float h = m_size.height(); + SkPaint paint; + paint.setARGB(128, 255, 0, 0); + canvas->drawLine(0, 0, w, h, paint); + canvas->drawLine(0, h, w, 0, paint); + paint.setARGB(128, 0, 255, 0); + canvas->drawLine(0, 0, 0, h, paint); + canvas->drawLine(0, h, w, h, paint); + canvas->drawLine(w, h, w, 0, paint); + canvas->drawLine(w, 0, 0, 0, paint); +#endif +} + +SkPicture* LayerAndroid::recordContext() +{ + if (prepareContext(true)) + return m_recordingPicture; + return 0; +} + +bool LayerAndroid::prepareContext(bool force) +{ + if (!m_haveContents) + return false; + + if (!m_isRootLayer) { + if (force || !m_recordingPicture + || (m_recordingPicture + && ((m_recordingPicture->width() != (int) m_size.width()) + || (m_recordingPicture->height() != (int) m_size.height())))) { + m_recordingPicture->safeUnref(); + m_recordingPicture = new SkPicture(); + } + } else if (m_recordingPicture) { + m_recordingPicture->safeUnref(); + m_recordingPicture = 0; + } + + return m_recordingPicture; +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h new file mode 100644 index 0000000..467c7dd --- /dev/null +++ b/WebCore/platform/graphics/android/LayerAndroid.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LayerAndroid_h +#define LayerAndroid_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "Color.h" +#include "FloatPoint.h" +#include "FloatPoint3D.h" +#include "FloatSize.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "Length.h" +#include "RefPtr.h" +#include "StringHash.h" +#include "Vector.h" +#include <wtf/HashSet.h> + +class SkCanvas; +class SkPicture; +class SkRect; + +namespace WebCore { + +class AndroidAnimation; +class AndroidAnimationValue; + +class LayerAndroid : public RefCounted<LayerAndroid> { + +public: + static PassRefPtr<LayerAndroid> create(bool isRootLayer); + LayerAndroid(bool isRootLayer); + LayerAndroid(LayerAndroid* layer); + ~LayerAndroid(); + + static int instancesCount(); + + void setSize(FloatSize size) { m_size = size; } + void setOpacity(float opacity) { m_opacity = opacity; } + void setTranslation(FloatPoint translation) { m_translation = translation; } + void setRotation(float a) { m_angleTransform = a; m_doRotation = true; } + void setScale(FloatPoint3D scale) { m_scale = scale; } + void setPosition(FloatPoint position) { m_position = position; } + void setAnchorPoint(FloatPoint3D point) { m_anchorPoint = point; } + void setHaveContents(bool haveContents) { m_haveContents = haveContents; } + void setHaveImage(bool haveImage) { m_haveImage = haveImage; } + void setDrawsContent(bool drawsContent); + void setMaskLayer(LayerAndroid*); + void setMasksToBounds(bool); + void setBackgroundColor(const Color& color); + void setIsRootLayer(bool isRootLayer) { m_isRootLayer = isRootLayer; } + + void paintOn(int scrollX, int scrollY, int width, int height, float scale, SkCanvas*); + GraphicsContext* paintContext(); + void removeAllChildren() { m_children.clear(); } + void addChildren(LayerAndroid* layer) { m_children.append(layer); } + bool prepareContext(bool force = false); + void startRecording(); + void stopRecording(); + SkPicture* recordContext(); + void setClip(SkCanvas* clip); + FloatPoint position() { return m_position; } + FloatPoint translation() { return m_translation; } + FloatSize size() { return m_size; } + + void setFixedPosition(Length left, Length top, Length right, Length bottom); + void addAnimation(PassRefPtr<AndroidAnimation> anim); + void removeAnimation(const String& name); + Vector<RefPtr<AndroidAnimationValue> >* evaluateAnimations() const; + bool evaluateAnimations(double time, + Vector<RefPtr<AndroidAnimationValue> >* result) const; + bool hasAnimations() const; + +private: + + void paintChildren(int scrollX, int scrollY, + int width, int height, + float scale, SkCanvas* canvas, + float opacity); + + void paintMe(int scrollX, int scrollY, + int width, int height, + float scale, SkCanvas* canvas, + float opacity); + + bool m_doRotation; + bool m_isRootLayer; + bool m_isFixed; + bool m_haveContents; + bool m_drawsContent; + bool m_haveImage; + bool m_haveClip; + bool m_backgroundColorSet; + + float m_angleTransform; + float m_opacity; + + FloatSize m_size; + FloatPoint m_position; + FloatPoint m_translation; + FloatPoint3D m_anchorPoint; + FloatPoint3D m_scale; + + Length m_fixedLeft; + Length m_fixedTop; + Length m_fixedRight; + Length m_fixedBottom; + + SkPicture* m_recordingPicture; + Color m_backgroundColor; + + Vector<RefPtr<LayerAndroid> > m_children; + typedef HashMap<String, RefPtr<AndroidAnimation> > KeyframesMap; + KeyframesMap m_animations; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // LayerAndroid_h diff --git a/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h b/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h index 812a337..19bfcd1 100644 --- a/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h +++ b/WebCore/platform/graphics/android/MediaPlayerPrivateAndroid.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,6 +48,7 @@ public: virtual IntSize naturalSize() const; + virtual bool hasAudio() const; virtual bool hasVideo() const; virtual void setVisible(bool); @@ -69,7 +70,7 @@ public: virtual MediaPlayer::ReadyState readyState() const; virtual float maxTimeSeekable() const; - virtual float maxTimeBuffered() const; + virtual PassRefPtr<TimeRanges> buffered() const; virtual int dataRate() const; @@ -88,6 +89,7 @@ public: void onPrepared(int duration, int width, int height); void onEnded(); void onPosterFetched(SkBitmap*); + void onTimeupdate(int position); private: // Android-specific methods and fields. static MediaPlayerPrivateInterface* create(MediaPlayer* player); @@ -106,6 +108,7 @@ private: float m_currentTime; bool m_paused; + bool m_hasVideo; MediaPlayer::ReadyState m_readyState; MediaPlayer::NetworkState m_networkState; diff --git a/WebCore/platform/graphics/android/PathAndroid.cpp b/WebCore/platform/graphics/android/PathAndroid.cpp index 90cd2db..4fdda23 100644 --- a/WebCore/platform/graphics/android/PathAndroid.cpp +++ b/WebCore/platform/graphics/android/PathAndroid.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebCore/platform/graphics/android/PatternAndroid.cpp b/WebCore/platform/graphics/android/PatternAndroid.cpp index a787113..58709fc 100644 --- a/WebCore/platform/graphics/android/PatternAndroid.cpp +++ b/WebCore/platform/graphics/android/PatternAndroid.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp index e0aecfa..fcdcce9 100644 --- a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp +++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/WebCore/platform/graphics/android/PlatformGraphicsContext.h index 4eeb4c1..8d0df36 100644 --- a/WebCore/platform/graphics/android/PlatformGraphicsContext.h +++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -162,4 +162,3 @@ private: } #endif - diff --git a/WebCore/platform/graphics/android/SharedBufferStream.cpp b/WebCore/platform/graphics/android/SharedBufferStream.cpp index fd63423..952495b 100644 --- a/WebCore/platform/graphics/android/SharedBufferStream.cpp +++ b/WebCore/platform/graphics/android/SharedBufferStream.cpp @@ -1,17 +1,26 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright 2009, The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -42,4 +51,3 @@ namespace WebCore { } } - diff --git a/WebCore/platform/graphics/android/SharedBufferStream.h b/WebCore/platform/graphics/android/SharedBufferStream.h index 929aa9b..da59b69 100644 --- a/WebCore/platform/graphics/android/SharedBufferStream.h +++ b/WebCore/platform/graphics/android/SharedBufferStream.h @@ -1,17 +1,26 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright 2009, The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WebCore_SharedBufferStream_DEFINED diff --git a/WebCore/platform/graphics/android/SkBitmapRef.h b/WebCore/platform/graphics/android/SkBitmapRef.h index 094102b..2a6e59e 100644 --- a/WebCore/platform/graphics/android/SkBitmapRef.h +++ b/WebCore/platform/graphics/android/SkBitmapRef.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp index cdd8afe..af88b8c 100644 --- a/WebCore/platform/graphics/android/android_graphics.cpp +++ b/WebCore/platform/graphics/android/android_graphics.cpp @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -88,5 +88,3 @@ void CursorRing::DrawRing(SkCanvas* canvas, paint.setColor(cursorInnerColors[flavor]); canvas->drawPath(path, paint); } - - diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h index 348daf1..a286e3a 100644 --- a/WebCore/platform/graphics/android/android_graphics.h +++ b/WebCore/platform/graphics/android/android_graphics.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index 0f7ae79..3bfa8f3 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -32,6 +32,7 @@ #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContext.h" +#include "ImageBuffer.h" #include "Pattern.h" #include "SimpleFontData.h" #include "TransformationMatrix.h" @@ -46,7 +47,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_t* cr = context->platformContext(); cairo_save(cr); - font->setFont(cr); + cairo_set_scaled_font(cr, font->platformData().scaledFont()); GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from); @@ -85,6 +86,34 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons shadowFillColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); +#if ENABLE(FILTERS) + cairo_text_extents_t extents; + cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); + + FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height)); + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0.f; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + GraphicsContext* shadowContext = shadowBuffer->context(); + cairo_t* shadowCr = shadowContext->platformContext(); + + cairo_translate(shadowCr, kernelSize, extents.height + kernelSize); + + cairo_set_scaled_font(shadowCr, font->platformData().scaledFont()); + cairo_show_glyphs(shadowCr, glyphs, numGlyphs); + if (font->syntheticBoldOffset()) { + cairo_save(shadowCr); + cairo_translate(shadowCr, font->syntheticBoldOffset(), 0); + cairo_show_glyphs(shadowCr, glyphs, numGlyphs); + cairo_restore(shadowCr); + } + cairo_translate(cr, 0.0, -extents.height); + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#else cairo_translate(cr, shadowSize.width(), shadowSize.height()); cairo_show_glyphs(cr, glyphs, numGlyphs); if (font->syntheticBoldOffset()) { @@ -93,6 +122,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_show_glyphs(cr, glyphs, numGlyphs); cairo_restore(cr); } +#endif cairo_restore(cr); } @@ -156,7 +186,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons // Re-enable the platform shadow we disabled earlier if (hasShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); cairo_restore(cr); } diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 5765546..14034fd 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -1,8 +1,9 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> - * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de> + * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) 2008 Nuanti Ltd. + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,16 +32,19 @@ #if PLATFORM(CAIRO) -#include "TransformationMatrix.h" #include "CairoPath.h" +#include "FEGaussianBlur.h" #include "FloatRect.h" #include "Font.h" #include "ImageBuffer.h" +#include "ImageBufferFilter.h" #include "IntRect.h" #include "NotImplemented.h" #include "Path.h" #include "Pattern.h" #include "SimpleFontData.h" +#include "SourceGraphic.h" +#include "TransformationMatrix.h" #include <cairo.h> #include <math.h> @@ -53,8 +57,8 @@ #elif PLATFORM(WIN) #include <cairo-win32.h> #endif -#include "GraphicsContextPrivate.h" #include "GraphicsContextPlatformPrivateCairo.h" +#include "GraphicsContextPrivate.h" #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -69,6 +73,42 @@ static inline void setColor(cairo_t* cr, const Color& col) cairo_set_source_rgba(cr, red, green, blue, alpha); } +static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) +{ + cairo_save(cr); + if (gcp->state.fillPattern) { + TransformationMatrix affine; + cairo_set_source(cr, gcp->state.fillPattern->createPlatformPattern(affine)); + } else if (gcp->state.fillGradient) + cairo_set_source(cr, gcp->state.fillGradient->platformGradient()); + else + setColor(cr, context->fillColor()); + cairo_clip_preserve(cr); + cairo_paint_with_alpha(cr, gcp->state.globalAlpha); + cairo_restore(cr); +} + +static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) +{ + cairo_save(cr); + if (gcp->state.strokePattern) { + TransformationMatrix affine; + cairo_set_source(cr, gcp->state.strokePattern->createPlatformPattern(affine)); + } else if (gcp->state.strokeGradient) + cairo_set_source(cr, gcp->state.strokeGradient->platformGradient()); + else { + Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * gcp->state.globalAlpha); + setColor(cr, strokeColor); + } + if (gcp->state.globalAlpha < 1.0f && (gcp->state.strokePattern || gcp->state.strokeGradient)) { + cairo_push_group(cr); + cairo_paint_with_alpha(cr, gcp->state.globalAlpha); + cairo_pop_group_to_source(cr); + } + cairo_stroke_preserve(cr); + cairo_restore(cr); +} + // A fillRect helper static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col) { @@ -78,6 +118,81 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const cairo_fill(cr); } +static inline void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr) +{ + cairo_set_antialias(dstCr, cairo_get_antialias(srcCr)); + + size_t dashCount = cairo_get_dash_count(srcCr); + Vector<double> dashes(dashCount); + + double offset; + cairo_get_dash(srcCr, dashes.data(), &offset); + cairo_set_dash(dstCr, dashes.data(), dashCount, offset); + cairo_set_line_cap(dstCr, cairo_get_line_cap(srcCr)); + cairo_set_line_join(dstCr, cairo_get_line_join(srcCr)); + cairo_set_line_width(dstCr, cairo_get_line_width(srcCr)); + cairo_set_miter_limit(dstCr, cairo_get_miter_limit(srcCr)); + cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr)); +} + +void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const IntSize& shadowSize, int shadowBlur) +{ +#if ENABLE(FILTERS) + // calculate the kernel size according to the HTML5 canvas shadow specification + kernelSize = (shadowBlur < 8 ? shadowBlur / 2.f : sqrt(shadowBlur * 2.f)); + int blurRadius = ceil(kernelSize); + + shadowBufferSize = IntSize(sourceRect.width() + blurRadius * 2, sourceRect.height() + blurRadius * 2); + + // determine dimensions of shadow rect + shadowRect = FloatRect(sourceRect.location(), shadowBufferSize); + shadowRect.move(shadowSize.width() - kernelSize, shadowSize.height() - kernelSize); +#endif +} + +static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* gcp, bool fillShadow, bool strokeShadow) +{ +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (!context->getShadow(shadowSize, shadowBlur, shadowColor)) + return; + + // Calculate filter values to create appropriate shadow. + cairo_t* cr = context->platformContext(); + cairo_path_t* path = cairo_copy_path(cr); + double x0, x1, y0, y1; + if (strokeShadow) + cairo_stroke_extents(cr, &x0, &y0, &x1, &y1); + else + cairo_fill_extents(cr, &x0, &y0, &x1, &y1); + FloatRect rect(x0, y0, x1 - x0, y1 - y0); + + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Create suitably-sized ImageBuffer to hold the shadow. + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + + // Draw shadow into a new ImageBuffer. + cairo_t* shadowContext = shadowBuffer->context()->platformContext(); + copyContextProperties(cr, shadowContext); + cairo_translate(shadowContext, -rect.x() + kernelSize, -rect.y() + kernelSize); + cairo_new_path(shadowContext); + cairo_append_path(shadowContext, path); + + if (fillShadow) + setPlatformFill(context, shadowContext, gcp); + if (strokeShadow) + setPlatformStroke(context, shadowContext, gcp); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#endif +} + GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate) @@ -142,38 +257,6 @@ void GraphicsContext::drawRect(const IntRect& rect) cairo_restore(cr); } -// FIXME: Now that this is refactored, it should be shared by all contexts. -static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle style) -{ - // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic - // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., - // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave - // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. - if (style == DottedStroke || style == DashedStroke) { - if (p1.x() == p2.x()) { - p1.setY(p1.y() + strokeWidth); - p2.setY(p2.y() - strokeWidth); - } - else { - p1.setX(p1.x() + strokeWidth); - p2.setX(p2.x() - strokeWidth); - } - } - - if (static_cast<int>(strokeWidth) % 2) { - if (p1.x() == p2.x()) { - // We're a vertical line. Adjust our x. - p1.setX(p1.x() + 0.5); - p2.setX(p2.x() + 0.5); - } - else { - // We're a horizontal line. Adjust our y. - p1.setY(p1.y() + 0.5); - p2.setY(p2.y() + 0.5); - } - } -} - // This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { @@ -239,20 +322,18 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth == 1) patternOffset = 1.0; else { - bool evenNumberOfSegments = numSegments%2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { if (remainder) { patternOffset += patWidth - remainder; - patternOffset += remainder/2; - } - else - patternOffset = patWidth/2; - } - else if (!evenNumberOfSegments) { + patternOffset += remainder / 2; + } else + patternOffset = patWidth / 2; + } else if (!evenNumberOfSegments) { if (remainder) - patternOffset = (patWidth - remainder)/2; + patternOffset = (patWidth - remainder) / 2; } } @@ -318,7 +399,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (w != h) cairo_scale(cr, 1., scaleFactor); - + cairo_arc_negative(cr, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, -fa * M_PI/180, -falen * M_PI/180); if (w != h) @@ -326,16 +407,16 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp float width = strokeThickness(); int patWidth = 0; - + switch (strokeStyle()) { - case DottedStroke: - patWidth = static_cast<int>(width / 2); - break; - case DashedStroke: - patWidth = 3 * static_cast<int>(width / 2); - break; - default: - break; + case DottedStroke: + patWidth = static_cast<int>(width / 2); + break; + case DashedStroke: + patWidth = 3 * static_cast<int>(width / 2); + break; + default: + break; } setColor(cr, strokeColor()); @@ -349,7 +430,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp distance = static_cast<int>((M_PI * hRadius) / 2.0); else // We are elliptical and will have to estimate the distance distance = static_cast<int>((M_PI * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0)) / 2.0); - + int remainder = distance % patWidth; int coverage = distance - remainder; int numSegments = coverage / patWidth; @@ -359,7 +440,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (patWidth == 1) patternOffset = 1.0; else { - bool evenNumberOfSegments = numSegments % 2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { @@ -421,30 +502,12 @@ void GraphicsContext::fillPath() return; cairo_t* cr = m_data->cr; - cairo_save(cr); cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - setColor(cr, fillColor()); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - case PatternColorSpace: { - TransformationMatrix affine; - cairo_set_source(cr, m_common->state.fillPattern->createPlatformPattern(affine)); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - } - case GradientColorSpace: - cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient(); - cairo_set_source(cr, pattern); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - } - cairo_restore(cr); + drawPathShadow(this, m_common, true, false); + + setPlatformFill(this, cr, m_common); + cairo_new_path(cr); } void GraphicsContext::strokePath() @@ -453,45 +516,26 @@ void GraphicsContext::strokePath() return; cairo_t* cr = m_data->cr; - cairo_save(cr); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - float red, green, blue, alpha; - strokeColor().getRGBA(red, green, blue, alpha); - if (m_common->state.globalAlpha < 1.0f) - alpha *= m_common->state.globalAlpha; - cairo_set_source_rgba(cr, red, green, blue, alpha); - cairo_stroke(cr); - break; - case PatternColorSpace: { - TransformationMatrix affine; - cairo_set_source(cr, m_common->state.strokePattern->createPlatformPattern(affine)); - if (m_common->state.globalAlpha < 1.0f) { - cairo_push_group(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - cairo_pop_group_to_source(cr); - } - cairo_stroke(cr); - break; - } - case GradientColorSpace: - cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient(); - cairo_set_source(cr, pattern); - if (m_common->state.globalAlpha < 1.0f) { - cairo_push_group(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - cairo_pop_group_to_source(cr); - } - cairo_stroke(cr); - break; - } - cairo_restore(cr); + drawPathShadow(this, m_common, false, true); + + setPlatformStroke(this, cr, m_common); + cairo_new_path(cr); + } void GraphicsContext::drawPath() { - fillPath(); - strokePath(); + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + + cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); + drawPathShadow(this, m_common, true, true); + + setPlatformFill(this, cr, m_common); + setPlatformStroke(this, cr, m_common); + cairo_new_path(cr); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -504,11 +548,36 @@ void GraphicsContext::fillRect(const FloatRect& rect) fillPath(); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +static void drawBorderlessRectShadow(GraphicsContext* context, const FloatRect& rect, const Color& rectColor) +{ +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + + if (!context->getShadow(shadowSize, shadowBlur, shadowColor)) + return; + + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + GraphicsContext* shadowContext = shadowBuffer->context(); + shadowContext->fillRect(FloatRect(FloatPoint(kernelSize, kernelSize), rect.size()), rectColor, DeviceColorSpace); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#endif +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; + drawBorderlessRectShadow(this, rect, color); if (color.alpha()) fillRectSourceOver(m_data->cr, rect, color); } @@ -668,13 +737,13 @@ IntPoint GraphicsContext::origin() return IntPoint(static_cast<int>(matrix.x0), static_cast<int>(matrix.y0)); } -void GraphicsContext::setPlatformFillColor(const Color& col) +void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) { // Cairo contexts can't hold separate fill and stroke colors // so we set them just before we actually fill or stroke } -void GraphicsContext::setPlatformStrokeColor(const Color& col) +void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) { // Cairo contexts can't hold separate fill and stroke colors // so we set them just before we actually fill or stroke @@ -760,9 +829,48 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer notImplemented(); } -void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&) +void GraphicsContext::setPlatformShadow(IntSize const& size, int, Color const&, ColorSpace) { - notImplemented(); + // Cairo doesn't support shadows natively, they are drawn manually in the draw* + // functions + + if (m_common->state.shadowsIgnoreTransforms) { + // Meaning that this graphics context is associated with a CanvasRenderingContext + // We flip the height since CG and HTML5 Canvas have opposite Y axis + m_common->state.shadowSize = IntSize(size.width(), -size.height()); + } +} + +void GraphicsContext::createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize) +{ +#if ENABLE(FILTERS) + cairo_t* cr = m_data->cr; + + // draw the shadow without blurring, if kernelSize is zero + if (!kernelSize) { + setColor(cr, shadowColor); + cairo_mask_surface(cr, buffer->image()->nativeImageForCurrentFrame(), shadowRect.x(), shadowRect.y()); + return; + } + + // limit kernel size to 1000, this is what CG is doing. + kernelSize = std::min(1000.f, kernelSize); + + // create filter + RefPtr<Filter> filter = ImageBufferFilter::create(); + filter->setSourceImage(buffer.release()); + RefPtr<FilterEffect> source = SourceGraphic::create(); + source->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size())); + source->setIsAlphaImage(true); + RefPtr<FilterEffect> blur = FEGaussianBlur::create(source.get(), kernelSize, kernelSize); + blur->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size())); + blur->apply(filter.get()); + + // Mask the filter with the shadow color and draw it to the context. + // Masking makes it possible to just blur the alpha channel. + setColor(cr, shadowColor); + cairo_mask_surface(cr, blur->resultImage()->image()->nativeImageForCurrentFrame(), shadowRect.x(), shadowRect.y()); +#endif } void GraphicsContext::clearPlatformShadow() @@ -828,15 +936,15 @@ void GraphicsContext::setLineCap(LineCap lineCap) cairo_line_cap_t cairoCap = CAIRO_LINE_CAP_BUTT; switch (lineCap) { - case ButtCap: - // no-op - break; - case RoundCap: - cairoCap = CAIRO_LINE_CAP_ROUND; - break; - case SquareCap: - cairoCap = CAIRO_LINE_CAP_SQUARE; - break; + case ButtCap: + // no-op + break; + case RoundCap: + cairoCap = CAIRO_LINE_CAP_ROUND; + break; + case SquareCap: + cairoCap = CAIRO_LINE_CAP_SQUARE; + break; } cairo_set_line_cap(m_data->cr, cairoCap); } @@ -853,15 +961,15 @@ void GraphicsContext::setLineJoin(LineJoin lineJoin) cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER; switch (lineJoin) { - case MiterJoin: - // no-op - break; - case RoundJoin: - cairoJoin = CAIRO_LINE_JOIN_ROUND; - break; - case BevelJoin: - cairoJoin = CAIRO_LINE_JOIN_BEVEL; - break; + case MiterJoin: + // no-op + break; + case RoundJoin: + cairoJoin = CAIRO_LINE_JOIN_ROUND; + break; + case BevelJoin: + cairoJoin = CAIRO_LINE_JOIN_BEVEL; + break; } cairo_set_line_join(m_data->cr, cairoJoin); } @@ -887,37 +995,37 @@ float GraphicsContext::getAlpha() static inline cairo_operator_t toCairoOperator(CompositeOperator op) { switch (op) { - case CompositeClear: - return CAIRO_OPERATOR_CLEAR; - case CompositeCopy: - return CAIRO_OPERATOR_SOURCE; - case CompositeSourceOver: - return CAIRO_OPERATOR_OVER; - case CompositeSourceIn: - return CAIRO_OPERATOR_IN; - case CompositeSourceOut: - return CAIRO_OPERATOR_OUT; - case CompositeSourceAtop: - return CAIRO_OPERATOR_ATOP; - case CompositeDestinationOver: - return CAIRO_OPERATOR_DEST_OVER; - case CompositeDestinationIn: - return CAIRO_OPERATOR_DEST_IN; - case CompositeDestinationOut: - return CAIRO_OPERATOR_DEST_OUT; - case CompositeDestinationAtop: - return CAIRO_OPERATOR_DEST_ATOP; - case CompositeXOR: - return CAIRO_OPERATOR_XOR; - case CompositePlusDarker: - return CAIRO_OPERATOR_SATURATE; - case CompositeHighlight: - // There is no Cairo equivalent for CompositeHighlight. - return CAIRO_OPERATOR_OVER; - case CompositePlusLighter: - return CAIRO_OPERATOR_ADD; - default: - return CAIRO_OPERATOR_SOURCE; + case CompositeClear: + return CAIRO_OPERATOR_CLEAR; + case CompositeCopy: + return CAIRO_OPERATOR_SOURCE; + case CompositeSourceOver: + return CAIRO_OPERATOR_OVER; + case CompositeSourceIn: + return CAIRO_OPERATOR_IN; + case CompositeSourceOut: + return CAIRO_OPERATOR_OUT; + case CompositeSourceAtop: + return CAIRO_OPERATOR_ATOP; + case CompositeDestinationOver: + return CAIRO_OPERATOR_DEST_OVER; + case CompositeDestinationIn: + return CAIRO_OPERATOR_DEST_IN; + case CompositeDestinationOut: + return CAIRO_OPERATOR_DEST_OUT; + case CompositeDestinationAtop: + return CAIRO_OPERATOR_DEST_ATOP; + case CompositeXOR: + return CAIRO_OPERATOR_XOR; + case CompositePlusDarker: + return CAIRO_OPERATOR_SATURATE; + case CompositeHighlight: + // There is no Cairo equivalent for CompositeHighlight. + return CAIRO_OPERATOR_OVER; + case CompositePlusLighter: + return CAIRO_OPERATOR_ADD; + default: + return CAIRO_OPERATOR_SOURCE; } } @@ -965,12 +1073,16 @@ void GraphicsContext::clip(const Path& path) m_data->clip(path); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) return; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) cairo_t* cr = m_data->cr; double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); @@ -981,9 +1093,6 @@ void GraphicsContext::clipOut(const Path& path) cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); -#else - notImplemented(); -#endif } void GraphicsContext::rotate(float radians) @@ -1009,19 +1118,15 @@ void GraphicsContext::clipOut(const IntRect& r) if (paintingDisabled()) return; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) cairo_t* cr = m_data->cr; double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - cairo_rectangle(cr, x1, x2, x2 - x1, y2 - y1); + cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); -#else - notImplemented(); -#endif } void GraphicsContext::clipOutEllipseInRect(const IntRect& r) @@ -1034,7 +1139,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& r) clipOut(p); } -void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1044,6 +1149,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, beginPath(); addPath(Path::createRoundedRectangle(r, topLeft, topRight, bottomLeft, bottomRight)); setColor(cr, color); + drawPathShadow(this, m_common, true, false); cairo_fill(cr); cairo_restore(cr); } diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index c905ee8..d991c80 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -136,18 +136,20 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) *pixel = premultipliedARGBFromColor(pixelColor); } } + cairo_surface_mark_dirty_rectangle (m_data.m_surface, 0, 0, m_size.width(), m_size.height()); } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +template <Multiply multiplied> +PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size) { - ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); + ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); - unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface); + unsigned char* dataSrc = cairo_image_surface_get_data(data.m_surface); unsigned char* dataDst = result->data()->data()->data(); - if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height()) - memset(dataSrc, 0, result->data()->length()); + if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) + memset(dataDst, 0, result->data()->length()); int originx = rect.x(); int destx = 0; @@ -156,8 +158,8 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originx = 0; } int endx = rect.x() + rect.width(); - if (endx > m_size.width()) - endx = m_size.width(); + if (endx > size.width()) + endx = size.width(); int numColumns = endx - originx; int originy = rect.y(); @@ -167,11 +169,11 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originy = 0; } int endy = rect.y() + rect.height(); - if (endy > m_size.height()) - endy = m_size.height(); + if (endy > size.height()) + endy = size.height(); int numRows = endy - originy; - int stride = cairo_image_surface_get_stride(m_data.m_surface); + int stride = cairo_image_surface_get_stride(data.m_surface); unsigned destBytesPerRow = 4 * rect.width(); unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4; @@ -180,7 +182,11 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const for (int x = 0; x < numColumns; x++) { int basex = x * 4; unsigned* pixel = row + x + originx; - Color pixelColor = colorFromPremultipliedARGB(*pixel); + Color pixelColor; + if (multiplied == Unmultiplied) + pixelColor = colorFromPremultipliedARGB(*pixel); + else + pixelColor = Color(*pixel); destRows[basex] = pixelColor.red(); destRows[basex + 1] = pixelColor.green(); destRows[basex + 2] = pixelColor.blue(); @@ -192,11 +198,22 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { - ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); + return getImageData<Unmultiplied>(rect, m_data, m_size); +} - unsigned char* dataDst = cairo_image_surface_get_data(m_data.m_surface); +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<Premultiplied>(rect, m_data, m_size); +} + +template <Multiply multiplied> +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size) +{ + ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); + + unsigned char* dataDst = cairo_image_surface_get_data(data.m_surface); ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -204,28 +221,28 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); - ASSERT(destx < m_size.width()); + ASSERT(destx < size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.right()); int endx = destPoint.x() + sourceRect.right(); - ASSERT(endx <= m_size.width()); + ASSERT(endx <= size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); - ASSERT(desty < m_size.height()); + ASSERT(desty < size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.bottom()); int endy = destPoint.y() + sourceRect.bottom(); - ASSERT(endy <= m_size.height()); + ASSERT(endy <= size.height()); int numRows = endy - desty; unsigned srcBytesPerRow = 4 * source->width(); - int stride = cairo_image_surface_get_stride(m_data.m_surface); + int stride = cairo_image_surface_get_stride(data.m_surface); unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; for (int y = 0; y < numRows; ++y) { @@ -237,10 +254,26 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con srcRows[basex + 1], srcRows[basex + 2], srcRows[basex + 3]); - *pixel = premultipliedARGBFromColor(pixelColor); + if (multiplied == Unmultiplied) + *pixel = premultipliedARGBFromColor(pixelColor); + else + *pixel = pixelColor.rgb(); } srcRows += srcBytesPerRow; } + cairo_surface_mark_dirty_rectangle (data.m_surface, + destx, desty, + numColumns, numRows); +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size); } static cairo_status_t writeFunction(void* closure, const unsigned char* data, unsigned int length) diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp index c8c992e..92e36fc 100644 --- a/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -89,7 +89,7 @@ BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer) checkForSolidColor(); } -void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { FloatRect srcRect(src); FloatRect dstRect(dst); @@ -105,7 +105,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo return; if (mayFillWithSolidColor()) { - fillWithSolidColor(context, dstRect, solidColor(), op); + fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op); return; } @@ -125,17 +125,37 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); - // To avoid the unwanted gradient effect (#14017) we use - // CAIRO_FILTER_NEAREST now, but the real fix will be to have - // CAIRO_EXTEND_PAD implemented for surfaces in Cairo allowing us to still - // use bilinear filtering - cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD); float scaleX = srcRect.width() / dstRect.width(); float scaleY = srcRect.height() / dstRect.height(); cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() }; cairo_pattern_set_matrix(pattern, &matrix); + // Draw the shadow +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize (0.0); + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, dstRect, shadowSize, shadowBlur); + shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() * context->getAlpha()) / 255.f); + + //draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + cairo_t* shadowContext = shadowBuffer->context()->platformContext(); + cairo_set_source(shadowContext, pattern); + cairo_translate(shadowContext, -dstRect.x(), -dstRect.y()); + cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height()); + cairo_fill(shadowContext); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); + } +#endif + // Draw the image. cairo_translate(cr, dstRect.x(), dstRect.y()); cairo_set_source(cr, pattern); @@ -151,7 +171,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo } void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect) { cairo_surface_t* image = nativeImageForCurrentFrame(); if (!image) // If it's too early we won't have an image yet. @@ -180,9 +200,6 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - // Workaround to avoid the unwanted gradient effect (#14017) - cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); - cairo_matrix_t pattern_matrix = cairo_matrix_t(patternTransform); cairo_matrix_t phase_matrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()}; cairo_matrix_t combined; diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index 75681bd..8bde57e 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -78,15 +78,7 @@ void Path::clear() bool Path::isEmpty() const { - cairo_t* cr = platformPath()->m_cr; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,5,10) - return !cairo_has_current_point(cr); -#else - cairo_path_t* p = cairo_copy_path(cr); - bool hasData = p->num_data; - cairo_path_destroy(p); - return !hasData; -#endif + return !cairo_has_current_point(platformPath()->m_cr); } bool Path::hasCurrentPoint() const @@ -256,11 +248,7 @@ FloatRect Path::boundingRect() const { cairo_t* cr = platformPath()->m_cr; double x0, x1, y0, y1; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0) cairo_path_extents(cr, &x0, &y0, &x1, &y1); -#else - cairo_stroke_extents(cr, &x0, &y0, &x1, &y1); -#endif return FloatRect(x0, y0, x1 - x0, y1 - y0); } diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp index 0465c0b..40aacc5 100644 --- a/WebCore/platform/graphics/cg/ColorCG.cpp +++ b/WebCore/platform/graphics/cg/ColorCG.cpp @@ -29,6 +29,7 @@ #if PLATFORM(CG) #include <wtf/Assertions.h> +#include <wtf/RetainPtr.h> #include <ApplicationServices/ApplicationServices.h> namespace WebCore { @@ -75,13 +76,12 @@ CGColorRef createCGColor(const Color& c) CMProfileRef prof = NULL; CMGetSystemProfile(&prof); - CGColorSpaceRef rgbSpace = CGColorSpaceCreateWithPlatformColorSpace(prof); + RetainPtr<CGColorSpaceRef> rgbSpace(AdoptCF, CGColorSpaceCreateWithPlatformColorSpace(prof)); - if (rgbSpace != NULL) - { - float components[4] = {c.red() / 255.0f, c.green() / 255.0f, c.blue() / 255.0f, c.alpha() / 255.0f}; - color = CGColorCreate(rgbSpace, components); - CGColorSpaceRelease(rgbSpace); + if (rgbSpace) { + CGFloat components[4] = { static_cast<CGFloat>(c.red()) / 255, static_cast<CGFloat>(c.green()) / 255, + static_cast<CGFloat>(c.blue()) / 255, static_cast<CGFloat>(c.alpha()) / 255 }; + color = CGColorCreate(rgbSpace.get(), components); } CMCloseProfile(prof); diff --git a/WebCore/platform/graphics/cg/GradientCG.cpp b/WebCore/platform/graphics/cg/GradientCG.cpp index c189fd5..05a0aad 100644 --- a/WebCore/platform/graphics/cg/GradientCG.cpp +++ b/WebCore/platform/graphics/cg/GradientCG.cpp @@ -58,17 +58,14 @@ CGShadingRef Gradient::platformGradient() const CGFloat intervalRanges[2] = { 0, 1 }; const CGFloat colorComponentRanges[4 * 2] = { 0, 1, 0, 1, 0, 1, 0, 1 }; const CGFunctionCallbacks gradientCallbacks = { 0, gradientCallback, 0 }; - CGFunctionRef colorFunction = CGFunctionCreate(this, 1, intervalRanges, 4, colorComponentRanges, &gradientCallbacks); + RetainPtr<CGFunctionRef> colorFunction(AdoptCF, CGFunctionCreate(this, 1, intervalRanges, 4, colorComponentRanges, &gradientCallbacks)); - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); if (m_radial) - m_gradient = CGShadingCreateRadial(colorSpace, m_p0, m_r0, m_p1, m_r1, colorFunction, true, true); + m_gradient = CGShadingCreateRadial(colorSpace, m_p0, m_r0, m_p1, m_r1, colorFunction.get(), true, true); else - m_gradient = CGShadingCreateAxial(colorSpace, m_p0, m_p1, colorFunction, true, true); - - CGColorSpaceRelease(colorSpace); - CGFunctionRelease(colorFunction); + m_gradient = CGShadingCreateAxial(colorSpace, m_p0, m_p1, colorFunction.get(), true, true); return m_gradient; } diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index ab8eb3c..39f06a6 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -28,40 +28,93 @@ #include "config.h" #include "GraphicsContext.h" -#include "TransformationMatrix.h" #include "FloatConversion.h" -#include "GraphicsContextPrivate.h" #include "GraphicsContextPlatformPrivateCG.h" +#include "GraphicsContextPrivate.h" #include "ImageBuffer.h" #include "KURL.h" #include "Path.h" #include "Pattern.h" +#include "TransformationMatrix.h" + #include <CoreGraphics/CGBitmapContext.h> #include <CoreGraphics/CGPDFContext.h> #include <wtf/MathExtras.h> #include <wtf/OwnArrayPtr.h> #include <wtf/RetainPtr.h> -#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +// Building on 10.6 or later: kCGInterpolationMedium is defined in the CGInterpolationQuality enum. #define HAVE_CG_INTERPOLATION_MEDIUM 1 #endif +#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD) +// Targeting 10.6 or later: use kCGInterpolationMedium. +#define WTF_USE_CG_INTERPOLATION_MEDIUM 1 +#endif + +#endif + using namespace std; namespace WebCore { -static void setCGFillColor(CGContextRef context, const Color& color) +static CGColorRef createCGColorWithColorSpace(const Color& color, ColorSpace colorSpace) { - CGFloat red, green, blue, alpha; - color.getRGBA(red, green, blue, alpha); - CGContextSetRGBFillColor(context, red, green, blue, alpha); + CGFloat components[4]; + color.getRGBA(components[0], components[1], components[2], components[3]); + + CGColorRef cgColor = 0; + if (colorSpace == sRGBColorSpace) + cgColor = CGColorCreate(sRGBColorSpaceRef(), components); + else + cgColor = CGColorCreate(deviceRGBColorSpaceRef(), components); + + return cgColor; +} + +static void setCGFillColor(CGContextRef context, const Color& color, ColorSpace colorSpace) +{ + CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace); + CGContextSetFillColorWithColor(context, cgColor); + CFRelease(cgColor); } -static void setCGStrokeColor(CGContextRef context, const Color& color) +static void setCGStrokeColor(CGContextRef context, const Color& color, ColorSpace colorSpace) { - CGFloat red, green, blue, alpha; - color.getRGBA(red, green, blue, alpha); - CGContextSetRGBStrokeColor(context, red, green, blue, alpha); + CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace); + CGContextSetStrokeColorWithColor(context, cgColor); + CFRelease(cgColor); +} + +static void setCGFillColorSpace(CGContextRef context, ColorSpace colorSpace) +{ + switch (colorSpace) { + case DeviceColorSpace: + break; + case sRGBColorSpace: + CGContextSetFillColorSpace(context, sRGBColorSpaceRef()); + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +static void setCGStrokeColorSpace(CGContextRef context, ColorSpace colorSpace) +{ + switch (colorSpace) { + case DeviceColorSpace: + break; + case sRGBColorSpace: + CGContextSetStrokeColorSpace(context, sRGBColorSpaceRef()); + break; + default: + ASSERT_NOT_REACHED(); + break; + } } GraphicsContext::GraphicsContext(CGContextRef cgContext) @@ -71,8 +124,8 @@ GraphicsContext::GraphicsContext(CGContextRef cgContext) setPaintingDisabled(!cgContext); if (cgContext) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), fillColorSpace()); + setPlatformStrokeColor(strokeColor(), strokeColorSpace()); } } @@ -86,7 +139,7 @@ CGContextRef GraphicsContext::platformContext() const { ASSERT(!paintingDisabled()); ASSERT(m_data->m_cgContext); - return m_data->m_cgContext; + return m_data->m_cgContext.get(); } void GraphicsContext::savePlatformState() @@ -122,7 +175,7 @@ void GraphicsContext::drawRect(const IntRect& rect) // We do a fill of four rects to simulate the stroke of a border. Color oldFillColor = fillColor(); if (oldFillColor != strokeColor()) - setCGFillColor(context, strokeColor()); + setCGFillColor(context, strokeColor(), strokeColorSpace()); CGRect rects[4] = { FloatRect(rect.x(), rect.y(), rect.width(), 1), FloatRect(rect.x(), rect.bottom() - 1, rect.width(), 1), @@ -131,7 +184,7 @@ void GraphicsContext::drawRect(const IntRect& rect) }; CGContextFillRects(context, rects, 4); if (oldFillColor != strokeColor()) - setCGFillColor(context, oldFillColor); + setCGFillColor(context, oldFillColor, fillColorSpace()); } } @@ -178,19 +231,19 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) int patWidth = 0; switch (strokeStyle()) { - case NoStroke: - case SolidStroke: - break; - case DottedStroke: - patWidth = (int)width; - break; - case DashedStroke: - patWidth = 3 * (int)width; - break; + case NoStroke: + case SolidStroke: + break; + case DottedStroke: + patWidth = (int)width; + break; + case DashedStroke: + patWidth = 3 * (int)width; + break; } CGContextRef context = platformContext(); - + if (shouldAntialias()) CGContextSetShouldAntialias(context, false); @@ -199,7 +252,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. - setCGFillColor(context, strokeColor()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color. + setCGFillColor(context, strokeColor(), strokeColorSpace()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color. if (isVerticalLine) { CGContextFillRect(context, FloatRect(p1.x() - width / 2, p1.y() - width, width, width)); CGContextFillRect(context, FloatRect(p2.x() - width / 2, p2.y(), width, width)); @@ -221,7 +274,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth == 1) patternOffset = 1.0f; else { - bool evenNumberOfSegments = numSegments % 2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { @@ -235,7 +288,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) patternOffset = (patWidth - remainder)/2; } } - + const CGFloat dottedLine[2] = { patWidth, patWidth }; CGContextSetLineDash(context, patternOffset, dottedLine, 2); } @@ -248,7 +301,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth) CGContextRestoreGState(context); - + if (shouldAntialias()) CGContextSetShouldAntialias(context, true); } @@ -263,7 +316,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect) if (paintingDisabled()) return; - + CGContextRef context = platformContext(); CGContextBeginPath(context); float r = (float)rect.width() / 2; @@ -275,25 +328,25 @@ void GraphicsContext::drawEllipse(const IntRect& rect) void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) -{ +{ if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f) return; - + CGContextRef context = platformContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextSetShouldAntialias(context, false); - + int x = rect.x(); int y = rect.y(); float w = (float)rect.width(); float h = (float)rect.height(); float scaleFactor = h / w; float reverseScaleFactor = w / h; - + if (w != h) scale(FloatSize(1, scaleFactor)); - + float hRadius = w / 2; float vRadius = h / 2; float fa = startAngle; @@ -304,22 +357,21 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (w != h) scale(FloatSize(1, reverseScaleFactor)); - - + float width = strokeThickness(); int patWidth = 0; - + switch (strokeStyle()) { - case DottedStroke: - patWidth = (int)(width / 2); - break; - case DashedStroke: - patWidth = 3 * (int)(width / 2); - break; - default: - break; + case DottedStroke: + patWidth = (int)(width / 2); + break; + case DashedStroke: + patWidth = 3 * (int)(width / 2); + break; + default: + break; } - + if (patWidth) { // Example: 80 pixels with a width of 30 pixels. // Remainder is 20. The maximum pixels of line we could paint @@ -329,7 +381,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp distance = static_cast<int>((piFloat * hRadius) / 2.0f); else // We are elliptical and will have to estimate the distance distance = static_cast<int>((piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0f)) / 2.0f); - + int remainder = distance % patWidth; int coverage = distance - remainder; int numSegments = coverage / patWidth; @@ -339,7 +391,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (patWidth == 1) patternOffset = 1.0f; else { - bool evenNumberOfSegments = numSegments % 2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { @@ -353,13 +405,13 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp patternOffset = (patWidth - remainder) / 2.0f; } } - + const CGFloat dottedLine[2] = { patWidth, patWidth }; CGContextSetLineDash(context, patternOffset, dottedLine, 2); } CGContextStrokePath(context); - + CGContextRestoreGState(context); } @@ -375,7 +427,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points if (antialiased != shouldAntialias()) CGContextSetShouldAntialias(context, antialiased); - + CGContextBeginPath(context); CGContextMoveToPoint(context, points[0].x(), points[0].y()); for (size_t i = 1; i < npoints; i++) @@ -383,7 +435,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points CGContextClosePath(context); drawPath(); - + if (antialiased != shouldAntialias()) CGContextSetShouldAntialias(context, shouldAntialias()); } @@ -391,41 +443,37 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points void GraphicsContext::applyStrokePattern() { CGContextRef cgContext = platformContext(); - - CGPatternRef platformPattern = m_common->state.strokePattern.get()->createPlatformPattern(getCTM()); + + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.strokePattern->createPlatformPattern(getCTM())); if (!platformPattern) return; - CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0); - CGContextSetStrokeColorSpace(cgContext, patternSpace); - CGColorSpaceRelease(patternSpace); + RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0)); + CGContextSetStrokeColorSpace(cgContext, patternSpace.get()); const CGFloat patternAlpha = 1; - CGContextSetStrokePattern(cgContext, platformPattern, &patternAlpha); - CGPatternRelease(platformPattern); + CGContextSetStrokePattern(cgContext, platformPattern.get(), &patternAlpha); } void GraphicsContext::applyFillPattern() { CGContextRef cgContext = platformContext(); - CGPatternRef platformPattern = m_common->state.fillPattern.get()->createPlatformPattern(getCTM()); + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.fillPattern->createPlatformPattern(getCTM())); if (!platformPattern) return; - CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0); - CGContextSetFillColorSpace(cgContext, patternSpace); - CGColorSpaceRelease(patternSpace); + RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0)); + CGContextSetFillColorSpace(cgContext, patternSpace.get()); const CGFloat patternAlpha = 1; - CGContextSetFillPattern(cgContext, platformPattern, &patternAlpha); - CGPatternRelease(platformPattern); + CGContextSetFillPattern(cgContext, platformPattern.get(), &patternAlpha); } static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPathDrawingMode& mode) { - bool shouldFill = state.fillColorSpace == PatternColorSpace || state.fillColor.alpha(); - bool shouldStroke = state.strokeColorSpace == PatternColorSpace || (state.strokeStyle != NoStroke && state.strokeColor.alpha()); + bool shouldFill = state.fillPattern || state.fillColor.alpha(); + bool shouldStroke = state.strokePattern || (state.strokeStyle != NoStroke && state.strokeColor.alpha()); bool useEOFill = state.fillRule == RULE_EVENODD; if (shouldFill) { @@ -457,16 +505,16 @@ void GraphicsContext::drawPath() CGContextRef context = platformContext(); const GraphicsContextState& state = m_common->state; - if (state.fillColorSpace == GradientColorSpace || state.strokeColorSpace == GradientColorSpace) { + if (state.fillGradient || state.strokeGradient) { // We don't have any optimized way to fill & stroke a path using gradients fillPath(); strokePath(); return; } - - if (state.fillColorSpace == PatternColorSpace) + + if (state.fillPattern) applyFillPattern(); - if (state.strokeColorSpace == PatternColorSpace) + if (state.strokePattern) applyStrokePattern(); CGPathDrawingMode drawingMode; @@ -488,15 +536,11 @@ void GraphicsContext::fillPath() return; CGContextRef context = platformContext(); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - fillPathWithFillRule(context, fillRule()); - break; - case PatternColorSpace: - applyFillPattern(); - fillPathWithFillRule(context, fillRule()); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the fillPattern and fillGradient cases? + setCGFillColorSpace(context, m_common->state.fillColorSpace); + + if (m_common->state.fillGradient) { CGContextSaveGState(context); if (fillRule() == RULE_EVENODD) CGContextEOClip(context); @@ -505,8 +549,12 @@ void GraphicsContext::fillPath() CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.fillGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.fillPattern) + applyFillPattern(); + fillPathWithFillRule(context, fillRule()); } void GraphicsContext::strokePath() @@ -515,76 +563,83 @@ void GraphicsContext::strokePath() return; CGContextRef context = platformContext(); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - CGContextStrokePath(context); - break; - case PatternColorSpace: - applyStrokePattern(); - CGContextStrokePath(context); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the strokePattern and strokeGradient cases? + setCGStrokeColorSpace(context, m_common->state.strokeColorSpace); + + if (m_common->state.strokeGradient) { CGContextSaveGState(context); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); CGContextConcatCTM(context, m_common->state.strokeGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.strokePattern) + applyStrokePattern(); + CGContextStrokePath(context); } void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) return; + CGContextRef context = platformContext(); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - CGContextFillRect(context, rect); - break; - case PatternColorSpace: - applyFillPattern(); - CGContextFillRect(context, rect); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the fillPattern and fillGradient cases? + setCGFillColorSpace(context, m_common->state.fillColorSpace); + + if (m_common->state.fillGradient) { CGContextSaveGState(context); CGContextClipToRect(context, rect); CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.fillGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.fillPattern) + applyFillPattern(); + CGContextFillRect(context, rect); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; CGContextRef context = platformContext(); Color oldFillColor = fillColor(); - if (oldFillColor != color) - setCGFillColor(context, color); + ColorSpace oldColorSpace = fillColorSpace(); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, color, colorSpace); + CGContextFillRect(context, rect); - if (oldFillColor != color) - setCGFillColor(context, oldFillColor); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, oldFillColor, oldColorSpace); } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; CGContextRef context = platformContext(); Color oldFillColor = fillColor(); - if (oldFillColor != color) - setCGFillColor(context, color); + ColorSpace oldColorSpace = fillColorSpace(); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, color, colorSpace); addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); fillPath(); - if (oldFillColor != color) - setCGFillColor(context, oldFillColor); + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, oldFillColor, oldColorSpace); } void GraphicsContext::clip(const FloatRect& rect) @@ -599,7 +654,7 @@ void GraphicsContext::clipOut(const IntRect& rect) { if (paintingDisabled()) return; - + CGRect rects[2] = { CGContextGetClipBoundingBox(platformContext()), rect }; CGContextBeginPath(platformContext()); CGContextAddRects(platformContext(), rects, 2); @@ -610,7 +665,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) { if (paintingDisabled()) return; - + CGContextBeginPath(platformContext()); CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); CGContextAddEllipseInRect(platformContext(), rect); @@ -639,13 +694,13 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness clip(rect); CGContextRef context = platformContext(); - + // Add outer ellipse CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height())); // Add inner ellipse. CGContextAddEllipseInRect(context, CGRectMake(rect.x() + thickness, rect.y() + thickness, rect.width() - (thickness * 2), rect.height() - (thickness * 2))); - + CGContextEOClip(context); } @@ -653,7 +708,7 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer { if (paintingDisabled()) return; - + CGContextTranslateCTM(platformContext(), rect.x(), rect.y() + rect.height()); CGContextScaleCTM(platformContext(), 1, -1); CGContextClipToMask(platformContext(), FloatRect(FloatPoint(), rect.size()), imageBuffer->image()->getCGImageRef()); @@ -684,7 +739,7 @@ void GraphicsContext::endTransparencyLayer() m_data->m_userToDeviceTransformKnownToBeIdentity = false; } -void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color) +void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -731,12 +786,11 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Col if (!color.isValid()) CGContextSetShadow(context, CGSizeMake(width, height), blurRadius); else { - CGColorRef colorCG = createCGColor(color); + RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColorWithColorSpace(color, colorSpace)); CGContextSetShadowWithColor(context, CGSizeMake(width, height), - blurRadius, - colorCG); - CGColorRelease(colorCG); + blurRadius, + colorCG.get()); } } @@ -774,15 +828,11 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) return; CGContextRef context = platformContext(); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - CGContextStrokeRectWithWidth(context, r, lineWidth); - break; - case PatternColorSpace: - applyStrokePattern(); - CGContextStrokeRectWithWidth(context, r, lineWidth); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the strokePattern and strokeGradient cases? + setCGStrokeColorSpace(context, m_common->state.strokeColorSpace); + + if (m_common->state.strokeGradient) { CGContextSaveGState(context); setStrokeThickness(lineWidth); CGContextAddRect(context, r); @@ -790,8 +840,12 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) CGContextClip(context); CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.strokePattern) + applyStrokePattern(); + CGContextStrokeRectWithWidth(context, r, lineWidth); } void GraphicsContext::setLineCap(LineCap cap) @@ -799,15 +853,15 @@ void GraphicsContext::setLineCap(LineCap cap) if (paintingDisabled()) return; switch (cap) { - case ButtCap: - CGContextSetLineCap(platformContext(), kCGLineCapButt); - break; - case RoundCap: - CGContextSetLineCap(platformContext(), kCGLineCapRound); - break; - case SquareCap: - CGContextSetLineCap(platformContext(), kCGLineCapSquare); - break; + case ButtCap: + CGContextSetLineCap(platformContext(), kCGLineCapButt); + break; + case RoundCap: + CGContextSetLineCap(platformContext(), kCGLineCapRound); + break; + case SquareCap: + CGContextSetLineCap(platformContext(), kCGLineCapSquare); + break; } } @@ -821,15 +875,15 @@ void GraphicsContext::setLineJoin(LineJoin join) if (paintingDisabled()) return; switch (join) { - case MiterJoin: - CGContextSetLineJoin(platformContext(), kCGLineJoinMiter); - break; - case RoundJoin: - CGContextSetLineJoin(platformContext(), kCGLineJoinRound); - break; - case BevelJoin: - CGContextSetLineJoin(platformContext(), kCGLineJoinBevel); - break; + case MiterJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinMiter); + break; + case RoundJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinRound); + break; + case BevelJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinBevel); + break; } } @@ -854,11 +908,16 @@ void GraphicsContext::clip(const Path& path) m_data->clip(path); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) return; - + CGContextBeginPath(platformContext()); CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); CGContextAddPath(platformContext(), path.platformPath()); @@ -909,9 +968,9 @@ TransformationMatrix GraphicsContext::getCTM() const FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) { - // It is not enough just to round to pixels in device space. The rotation part of the + // 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 + // rotating image like the hands of the world clock widget. We just need the scale, so // we get the affine transform matrix and extract the scale. if (m_data->m_userToDeviceTransformKnownToBeIdentity) @@ -934,11 +993,11 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) deviceOrigin.y = roundf(deviceOrigin.y); deviceLowerRight.x = roundf(deviceLowerRight.x); deviceLowerRight.y = roundf(deviceLowerRight.y); - + // Don't let the height or width round to 0 unless either was originally 0 - if (deviceOrigin.y == deviceLowerRight.y && rect.height() != 0) + if (deviceOrigin.y == deviceLowerRight.y && rect.height()) deviceLowerRight.y += 1; - if (deviceOrigin.x == deviceLowerRight.x && rect.width() != 0) + if (deviceOrigin.x == deviceLowerRight.x && rect.width()) deviceLowerRight.x += 1; FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x / deviceScaleX, deviceOrigin.y / deviceScaleY); @@ -984,13 +1043,13 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri } } } - + if (fillColor() != strokeColor()) - setCGFillColor(platformContext(), strokeColor()); + setCGFillColor(platformContext(), strokeColor(), strokeColorSpace()); CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness)); if (fillColor() != strokeColor()) - setCGFillColor(platformContext(), fillColor()); - + setCGFillColor(platformContext(), fillColor(), fillColorSpace()); + if (restoreAntialiasMode) CGContextSetShouldAntialias(platformContext(), true); } @@ -999,51 +1058,50 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) { if (paintingDisabled()) return; - - CFURLRef urlRef = link.createCFURL(); - if (urlRef) { - CGContextRef context = platformContext(); - - // Get the bounding box to handle clipping. - CGRect box = CGContextGetClipBoundingBox(context); - - IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height); - IntRect rect = destRect; - rect.intersect(intBox); - - CGPDFContextSetURLForRect(context, urlRef, - CGRectApplyAffineTransform(rect, CGContextGetCTM(context))); - - CFRelease(urlRef); - } + + RetainPtr<CFURLRef> urlRef(AdoptCF, link.createCFURL()); + if (!urlRef) + return; + + CGContextRef context = platformContext(); + + // Get the bounding box to handle clipping. + CGRect box = CGContextGetClipBoundingBox(context); + + IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height); + IntRect rect = destRect; + rect.intersect(intBox); + + CGPDFContextSetURLForRect(context, urlRef.get(), + CGRectApplyAffineTransform(rect, CGContextGetCTM(context))); } void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode) { if (paintingDisabled()) return; - + CGInterpolationQuality quality = kCGInterpolationDefault; switch (mode) { - case InterpolationDefault: - quality = kCGInterpolationDefault; - break; - case InterpolationNone: - quality = kCGInterpolationNone; - break; - case InterpolationLow: - quality = kCGInterpolationLow; - break; - - // Fall through to InterpolationHigh if kCGInterpolationMedium is not available - case InterpolationMedium: -#if HAVE(CG_INTERPOLATION_MEDIUM) - quality = kCGInterpolationMedium; - break; + case InterpolationDefault: + quality = kCGInterpolationDefault; + break; + case InterpolationNone: + quality = kCGInterpolationNone; + break; + case InterpolationLow: + quality = kCGInterpolationLow; + break; + + // Fall through to InterpolationHigh if kCGInterpolationMedium is not usable. + case InterpolationMedium: +#if USE(CG_INTERPOLATION_MEDIUM) + quality = kCGInterpolationMedium; + break; #endif - case InterpolationHigh: - quality = kCGInterpolationHigh; - break; + case InterpolationHigh: + quality = kCGInterpolationHigh; + break; } CGContextSetInterpolationQuality(platformContext(), quality); } @@ -1055,18 +1113,24 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const CGInterpolationQuality quality = CGContextGetInterpolationQuality(platformContext()); switch (quality) { - case kCGInterpolationDefault: - return InterpolationDefault; - case kCGInterpolationNone: - return InterpolationNone; - case kCGInterpolationLow: - return InterpolationLow; + case kCGInterpolationDefault: + return InterpolationDefault; + case kCGInterpolationNone: + return InterpolationNone; + case kCGInterpolationLow: + return InterpolationLow; #if HAVE(CG_INTERPOLATION_MEDIUM) - case kCGInterpolationMedium: - return InterpolationMedium; -#endif - case kCGInterpolationHigh: - return InterpolationHigh; + // kCGInterpolationMedium is known to be present in the CGInterpolationQuality enum. + case kCGInterpolationMedium: +#if USE(CG_INTERPOLATION_MEDIUM) + // Only map to InterpolationMedium if targeting a system that understands it. + return InterpolationMedium; +#else + return InterpolationDefault; +#endif // USE(CG_INTERPOLATION_MEDIUM) +#endif // HAVE(CG_INTERPOLATION_MEDIUM) + case kCGInterpolationHigh: + return InterpolationHigh; } return InterpolationDefault; } @@ -1079,40 +1143,40 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode) // Wow, wish CG had used bits here. CGContextRef context = platformContext(); switch (mode) { - case cTextInvisible: // Invisible - CGContextSetTextDrawingMode(context, kCGTextInvisible); - break; - case cTextFill: // Fill - CGContextSetTextDrawingMode(context, kCGTextFill); - break; - case cTextStroke: // Stroke - CGContextSetTextDrawingMode(context, kCGTextStroke); - break; - case 3: // Fill | Stroke - CGContextSetTextDrawingMode(context, kCGTextFillStroke); - break; - case cTextClip: // Clip - CGContextSetTextDrawingMode(context, kCGTextClip); - break; - case 5: // Fill | Clip - CGContextSetTextDrawingMode(context, kCGTextFillClip); - break; - case 6: // Stroke | Clip - CGContextSetTextDrawingMode(context, kCGTextStrokeClip); - break; - case 7: // Fill | Stroke | Clip - CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip); - break; - default: - break; + case cTextInvisible: // Invisible + CGContextSetTextDrawingMode(context, kCGTextInvisible); + break; + case cTextFill: // Fill + CGContextSetTextDrawingMode(context, kCGTextFill); + break; + case cTextStroke: // Stroke + CGContextSetTextDrawingMode(context, kCGTextStroke); + break; + case 3: // Fill | Stroke + CGContextSetTextDrawingMode(context, kCGTextFillStroke); + break; + case cTextClip: // Clip + CGContextSetTextDrawingMode(context, kCGTextClip); + break; + case 5: // Fill | Clip + CGContextSetTextDrawingMode(context, kCGTextFillClip); + break; + case 6: // Stroke | Clip + CGContextSetTextDrawingMode(context, kCGTextStrokeClip); + break; + case 7: // Fill | Stroke | Clip + CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip); + break; + default: + break; } } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; - setCGStrokeColor(platformContext(), color); + setCGStrokeColor(platformContext(), color, colorSpace); } void GraphicsContext::setPlatformStrokeThickness(float thickness) @@ -1122,11 +1186,11 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) CGContextSetLineWidth(platformContext(), thickness); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; - setCGFillColor(platformContext(), color); + setCGFillColor(platformContext(), color, colorSpace); } void GraphicsContext::setPlatformShouldAntialias(bool enable) @@ -1138,54 +1202,54 @@ void GraphicsContext::setPlatformShouldAntialias(bool enable) #ifndef BUILDING_ON_TIGER // Tiger's setCompositeOperation() is defined in GraphicsContextMac.mm. void GraphicsContext::setCompositeOperation(CompositeOperator mode) -{ +{ if (paintingDisabled()) return; - CGBlendMode target = kCGBlendModeNormal; + CGBlendMode target = kCGBlendModeNormal; switch (mode) { - case CompositeClear: - target = kCGBlendModeClear; - break; - case CompositeCopy: - target = kCGBlendModeCopy; - break; - case CompositeSourceOver: - //kCGBlendModeNormal - break; - case CompositeSourceIn: - target = kCGBlendModeSourceIn; - break; - case CompositeSourceOut: - target = kCGBlendModeSourceOut; - break; - case CompositeSourceAtop: - target = kCGBlendModeSourceAtop; - break; - case CompositeDestinationOver: - target = kCGBlendModeDestinationOver; - break; - case CompositeDestinationIn: - target = kCGBlendModeDestinationIn; - break; - case CompositeDestinationOut: - target = kCGBlendModeDestinationOut; - break; - case CompositeDestinationAtop: - target = kCGBlendModeDestinationAtop; - break; - case CompositeXOR: - target = kCGBlendModeXOR; - break; - case CompositePlusDarker: - target = kCGBlendModePlusDarker; - break; - case CompositeHighlight: - // currently unsupported - break; - case CompositePlusLighter: - target = kCGBlendModePlusLighter; - break; + case CompositeClear: + target = kCGBlendModeClear; + break; + case CompositeCopy: + target = kCGBlendModeCopy; + break; + case CompositeSourceOver: + //kCGBlendModeNormal + break; + case CompositeSourceIn: + target = kCGBlendModeSourceIn; + break; + case CompositeSourceOut: + target = kCGBlendModeSourceOut; + break; + case CompositeSourceAtop: + target = kCGBlendModeSourceAtop; + break; + case CompositeDestinationOver: + target = kCGBlendModeDestinationOver; + break; + case CompositeDestinationIn: + target = kCGBlendModeDestinationIn; + break; + case CompositeDestinationOut: + target = kCGBlendModeDestinationOut; + break; + case CompositeDestinationAtop: + target = kCGBlendModeDestinationAtop; + break; + case CompositeXOR: + target = kCGBlendModeXOR; + break; + case CompositePlusDarker: + target = kCGBlendModePlusDarker; + break; + case CompositeHighlight: + // currently unsupported + break; + case CompositePlusLighter: + target = kCGBlendModePlusLighter; + break; } CGContextSetBlendMode(platformContext(), target); } diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index f63a8dd..ff1816f 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -27,6 +27,25 @@ namespace WebCore { +// FIXME: This would be in GraphicsContextCG.h if that existed. +inline CGColorSpaceRef deviceRGBColorSpaceRef() +{ + static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB(); + return deviceSpace; +} + +// FIXME: This would be in GraphicsContextCG.h if that existed. +inline CGColorSpaceRef sRGBColorSpaceRef() +{ + // FIXME: Windows should be able to use kCGColorSpaceSRGB, this is tracked by http://webkit.org/b/31363. +#if PLATFORM(WIN) || defined(BUILDING_ON_TIGER) + return deviceRGBColorSpaceRef(); +#else + static CGColorSpaceRef sRGBSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); + return sRGBSpace; +#endif +} + class GraphicsContextPlatformPrivate { public: GraphicsContextPlatformPrivate(CGContextRef cgContext) @@ -38,12 +57,10 @@ public: #endif , m_userToDeviceTransformKnownToBeIdentity(false) { - CGContextRetain(m_cgContext); } ~GraphicsContextPlatformPrivate() { - CGContextRelease(m_cgContext); } #if PLATFORM(MAC) || PLATFORM(CHROMIUM) @@ -80,7 +97,7 @@ public: bool m_shouldIncludeChildWindows; #endif - CGContextRef m_cgContext; + RetainPtr<CGContextRef> m_cgContext; bool m_userToDeviceTransformKnownToBeIdentity; }; diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 6db7e88..b1896f8 100644 --- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -65,37 +65,37 @@ ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, b bytesPerRow *= 4; } - m_data.m_data = tryFastCalloc(size.height(), bytesPerRow); + if (!tryFastCalloc(size.height(), bytesPerRow).getValue(m_data.m_data)) + return; + ASSERT((reinterpret_cast<size_t>(m_data.m_data) & 2) == 0); - CGColorSpaceRef colorSpace; + RetainPtr<CGColorSpaceRef> colorSpace; switch(imageColorSpace) { case DeviceRGB: - colorSpace = CGColorSpaceCreateDeviceRGB(); + colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); break; case GrayScale: - colorSpace = CGColorSpaceCreateDeviceGray(); + colorSpace.adoptCF(CGColorSpaceCreateDeviceGray()); break; #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) case LinearRGB: - colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear); + colorSpace.adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear)); break; #endif default: - colorSpace = CGColorSpaceCreateDeviceRGB(); + colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); break; } - CGContextRef cgContext = CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, - colorSpace, (imageColorSpace == GrayScale) ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(colorSpace); + RetainPtr<CGContextRef> cgContext(AdoptCF, CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, + colorSpace.get(), (imageColorSpace == GrayScale) ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast)); if (!cgContext) return; - m_context.set(new GraphicsContext(cgContext)); + m_context.set(new GraphicsContext(cgContext.get())); m_context->scale(FloatSize(1, -1)); m_context->translate(0, -size.height()); - CGContextRelease(cgContext); success = true; } @@ -122,12 +122,13 @@ Image* ImageBuffer::image() const return m_image.get(); } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +template <Multiply multiplied> +PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size) { PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* data = result->data()->data()->data(); - if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height()) + if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) memset(data, 0, result->data()->length()); int originx = rect.x(); @@ -137,8 +138,8 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originx = 0; } int endx = rect.x() + rect.width(); - if (endx > m_size.width()) - endx = m_size.width(); + if (endx > size.width()) + endx = size.width(); int numColumns = endx - originx; int originy = rect.y(); @@ -148,20 +149,21 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originy = 0; } int endy = rect.y() + rect.height(); - if (endy > m_size.height()) - endy = m_size.height(); + if (endy > size.height()) + endy = size.height(); int numRows = endy - originy; - unsigned srcBytesPerRow = 4 * m_size.width(); + unsigned srcBytesPerRow = 4 * size.width(); unsigned destBytesPerRow = 4 * rect.width(); // ::create ensures that all ImageBuffers have valid data, so we don't need to check it here. - unsigned char* srcRows = reinterpret_cast<unsigned char*>(m_data.m_data) + originy * srcBytesPerRow + originx * 4; + unsigned char* srcRows = reinterpret_cast<unsigned char*>(imageData.m_data) + originy * srcBytesPerRow + originx * 4; unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; for (int y = 0; y < numRows; ++y) { for (int x = 0; x < numColumns; x++) { int basex = x * 4; - if (unsigned char alpha = srcRows[basex + 3]) { + 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; @@ -175,7 +177,18 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData<Unmultiplied>(rect, m_data, m_size); +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<Premultiplied>(rect, m_data, m_size); +} + +template <Multiply multiplied> +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -183,36 +196,36 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); - ASSERT(destx < m_size.width()); + ASSERT(destx < size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.right()); int endx = destPoint.x() + sourceRect.right(); - ASSERT(endx <= m_size.width()); + ASSERT(endx <= size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); - ASSERT(desty < m_size.height()); + ASSERT(desty < size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.bottom()); int endy = destPoint.y() + sourceRect.bottom(); - ASSERT(endy <= m_size.height()); + ASSERT(endy <= size.height()); int numRows = endy - desty; unsigned srcBytesPerRow = 4 * source->width(); - unsigned destBytesPerRow = 4 * m_size.width(); + unsigned destBytesPerRow = 4 * size.width(); unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; - unsigned char* destRows = reinterpret_cast<unsigned char*>(m_data.m_data) + desty * destBytesPerRow + destx * 4; + unsigned char* 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 (alpha != 255) { + 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; @@ -225,6 +238,16 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con } } +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + static RetainPtr<CFStringRef> utiFromMIMEType(const String& mimeType) { #if PLATFORM(MAC) diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp index a5620e8..2e372e2 100644 --- a/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/WebCore/platform/graphics/cg/ImageCG.cpp @@ -32,6 +32,7 @@ #include "FloatConversion.h" #include "FloatRect.h" #include "GraphicsContext.h" +#include "GraphicsContextPlatformPrivateCG.h" #include "ImageObserver.h" #include "PDFDocumentImage.h" #include "PlatformString.h" @@ -101,52 +102,72 @@ BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer) void BitmapImage::checkForSolidColor() { m_checkedForSolidColor = true; - if (frameCount() > 1) + if (frameCount() > 1) { m_isSolidColor = false; - else { - CGImageRef image = frameAtIndex(0); - - // Currently we only check for solid color in the important special case of a 1x1 image. - if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) { - unsigned char pixel[4]; // RGBA - CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); - CGContextRef bmap = CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), space, - kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); - if (bmap) { - GraphicsContext(bmap).setCompositeOperation(CompositeCopy); - CGRect dst = { {0, 0}, {1, 1} }; - CGContextDrawImage(bmap, dst, image); - if (pixel[3] == 0) - m_solidColor = Color(0, 0, 0, 0); - else - m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]); - m_isSolidColor = true; - CFRelease(bmap); - } - CFRelease(space); - } + return; + } + + CGImageRef image = frameAtIndex(0); + + // Currently we only check for solid color in the important special case of a 1x1 image. + if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) { + unsigned char pixel[4]; // RGBA + static CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + RetainPtr<CGContextRef> bmap(AdoptCF, CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), space, + kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big)); + if (!bmap) + return; + GraphicsContext(bmap.get()).setCompositeOperation(CompositeCopy); + CGRect dst = { {0, 0}, {1, 1} }; + CGContextDrawImage(bmap.get(), dst, image); + if (pixel[3] == 0) + m_solidColor = Color(0, 0, 0, 0); + else + m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]); + m_isSolidColor = true; } } +static RetainPtr<CGImageRef> imageWithColorSpace(CGImageRef originalImage, ColorSpace colorSpace) +{ + CGColorSpaceRef originalColorSpace = CGImageGetColorSpace(originalImage); + + // If the image already has a (non-device) color space, we don't want to + // override it, so return. + if (!originalColorSpace || !CFEqual(originalColorSpace, deviceRGBColorSpaceRef())) + return originalImage; + + switch (colorSpace) { + case DeviceColorSpace: + return originalImage; + case sRGBColorSpace: + return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, + sRGBColorSpaceRef())); + } + + ASSERT_NOT_REACHED(); + return originalImage; +} + CGImageRef BitmapImage::getCGImageRef() { return frameAtIndex(0); } -void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp) +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); - CGImageRef image = frameAtIndex(m_currentFrame); + RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, destRect, solidColor(), compositeOp); + fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } - float currHeight = CGImageGetHeight(image); + float currHeight = CGImageGetHeight(image.get()); if (currHeight <= srcRect.y()) return; @@ -182,10 +203,10 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F subimageRect.setHeight(ceilf(subimageRect.height() + topPadding)); adjustedDestRect.setHeight(subimageRect.height() / yScale); - image = CGImageCreateWithImageInRect(image, subimageRect); + image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); if (currHeight < srcRect.bottom()) { - ASSERT(CGImageGetHeight(image) == currHeight - CGRectIntegral(srcRect).origin.y); - adjustedDestRect.setHeight(CGImageGetHeight(image) / yScale); + ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); + adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } } else { adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale)); @@ -205,11 +226,11 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F CGContextScaleCTM(context, 1, -1); adjustedDestRect.setY(-adjustedDestRect.bottom()); - // Draw the image. - CGContextDrawImage(context, adjustedDestRect, image); + // Adjust the color space. + image = imageWithColorSpace(image.get(), styleColorSpace); - if (shouldUseSubimage) - CGImageRelease(image); + // Draw the image. + CGContextDrawImage(context, adjustedDestRect, image.get()); ctxt->restore(); @@ -224,7 +245,7 @@ static void drawPatternCallback(void* info, CGContextRef context) } void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) { if (!nativeImageForCurrentFrame()) return; @@ -252,15 +273,18 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const CGImageRef tileImage = nativeImageForCurrentFrame(); float h = CGImageGetHeight(tileImage); - CGImageRef subImage; + RetainPtr<CGImageRef> subImage; if (tileRect.size() == size()) subImage = tileImage; else { // Copying a sub-image out of a partially-decoded image stops the decoding of the original image. It should never happen // because sub-images are only used for border-image, which only renders when the image is fully decoded. ASSERT(h == height()); - subImage = CGImageCreateWithImageInRect(tileImage, tileRect); + subImage.adoptCF(CGImageCreateWithImageInRect(tileImage, tileRect)); } + + // Adjust the color space. + subImage = imageWithColorSpace(subImage.get(), styleColorSpace); #ifndef BUILDING_ON_TIGER // Leopard has an optimized call for the tiling of image patterns, but we can only use it if the image has been decoded enough that @@ -275,7 +299,7 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const #else if (w == size().width() && h == size().height()) #endif - CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage); + CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage.get()); else { #endif @@ -288,39 +312,31 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const matrix = CGAffineTransformConcat(matrix, CGContextGetCTM(context)); // The top of a partially-decoded image is drawn at the bottom of the tile. Map it to the top. matrix = CGAffineTransformTranslate(matrix, 0, size().height() - h); - CGPatternRef pattern = CGPatternCreate(subImage, CGRectMake(0, 0, tileRect.width(), tileRect.height()), - matrix, tileRect.width(), tileRect.height(), - kCGPatternTilingConstantSpacing, true, &patternCallbacks); - if (pattern == NULL) { - if (subImage != tileImage) - CGImageRelease(subImage); + RetainPtr<CGPatternRef> pattern(AdoptCF, CGPatternCreate(subImage.get(), CGRectMake(0, 0, tileRect.width(), tileRect.height()), + matrix, tileRect.width(), tileRect.height(), + kCGPatternTilingConstantSpacing, true, &patternCallbacks)); + if (!pattern) { ctxt->restore(); return; } - CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); + RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0)); CGFloat alpha = 1; - CGColorRef color = CGColorCreateWithPattern(patternSpace, pattern, &alpha); - CGContextSetFillColorSpace(context, patternSpace); - CGColorSpaceRelease(patternSpace); - CGPatternRelease(pattern); + RetainPtr<CGColorRef> color(AdoptCF, CGColorCreateWithPattern(patternSpace.get(), pattern.get(), &alpha)); + CGContextSetFillColorSpace(context, patternSpace.get()); // FIXME: Really want a public API for this. It is just CGContextSetBaseCTM(context, CGAffineTransformIdentiy). wkSetPatternBaseCTM(context, CGAffineTransformIdentity); CGContextSetPatternPhase(context, CGSizeZero); - CGContextSetFillColorWithColor(context, color); + CGContextSetFillColorWithColor(context, color.get()); CGContextFillRect(context, CGContextGetClipBoundingBox(context)); - - CGColorRelease(color); - + #ifndef BUILDING_ON_TIGER } #endif - if (subImage != tileImage) - CGImageRelease(subImage); ctxt->restore(); if (imageObserver()) diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index b716060..2b2c6b0 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -35,12 +35,27 @@ #include <ApplicationServices/ApplicationServices.h> #include <wtf/UnusedParam.h> +using namespace std; + namespace WebCore { static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); #if !PLATFORM(MAC) -static void sharedBufferDerefCallback(void*, void* info) +size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count) +{ + SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); + size_t sourceSize = sharedBuffer->size(); + if (position >= sourceSize) + return 0; + + const char* source = sharedBuffer->data() + position; + size_t amount = min<size_t>(count, sourceSize - position); + memcpy(buffer, source, amount); + return amount; +} + +void sharedBufferRelease(void* info) { SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); sharedBuffer->deref(); @@ -109,18 +124,18 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) #if PLATFORM(MAC) // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer. - CFDataRef cfData = data->createCFData(); + RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData()); + CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived); #else - // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the - // scenes. We use CFDataCreateWithBytesNoCopy in that case. Ensure that the SharedBuffer lives as long as the CFDataRef. + // Create a CGDataProvider to wrap the SharedBuffer. data->ref(); - CFAllocatorContext context = {0, data, 0, 0, 0, 0, 0, &sharedBufferDerefCallback, 0}; - CFAllocatorRef derefAllocator = CFAllocatorCreate(kCFAllocatorDefault, &context); - CFDataRef cfData = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), derefAllocator); - CFRelease(derefAllocator); + // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer + // does not provide a way to lock down the byte pointer and guarantee that it won't move, which + // is a requirement for using the GetBytePointer callback. + CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease }; + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirect(data, data->size(), &providerCallbacks)); + CGImageSourceUpdateDataProvider(m_decoder, dataProvider.get(), allDataReceived); #endif - CGImageSourceUpdateData(m_decoder, cfData, allDataReceived); - CFRelease(cfData); } String ImageSource::filenameExtension() const @@ -138,12 +153,11 @@ bool ImageSource::isSizeAvailable() // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus! if (imageSourceStatus >= kCGImageStatusIncomplete) { - CFDictionaryRef image0Properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()); + RetainPtr<CFDictionaryRef> image0Properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions())); if (image0Properties) { - CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelWidth); - CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelHeight); + CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelWidth); + CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelHeight); result = widthNumber && heightNumber; - CFRelease(image0Properties); } } @@ -153,17 +167,16 @@ bool ImageSource::isSizeAvailable() IntSize ImageSource::frameSizeAtIndex(size_t index) const { IntSize result; - CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()); + RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions())); if (properties) { int w = 0, h = 0; - CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); + CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); if (num) CFNumberGetValue(num, kCFNumberIntType, &w); - num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); + num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); if (num) CFNumberGetValue(num, kCFNumberIntType, &h); result = IntSize(w, h); - CFRelease(properties); } return result; } @@ -180,17 +193,15 @@ int ImageSource::repetitionCount() return result; // A property with value 0 means loop forever. - CFDictionaryRef properties = CGImageSourceCopyProperties(m_decoder, imageSourceOptions()); + RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyProperties(m_decoder, imageSourceOptions())); if (properties) { - CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); + CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (gifProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount); if (num) CFNumberGetValue(num, kCFNumberIntType, &result); } else result = cAnimationNone; // Turns out we're not a GIF after all, so we don't animate. - - CFRelease(properties); } return result; @@ -206,20 +217,19 @@ CGImageRef ImageSource::createFrameAtIndex(size_t index) if (!initialized()) return 0; - CGImageRef image = CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions()); + RetainPtr<CGImageRef> image(AdoptCF, CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions())); CFStringRef imageUTI = CGImageSourceGetType(m_decoder); static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); if (!imageUTI || !CFEqual(imageUTI, xbmUTI)) - return image; + return image.releaseRef(); // If it is an xbm image, mask out all the white areas to render them transparent. const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255}; - CGImageRef maskedImage = CGImageCreateWithMaskingColors(image, maskingColors); + RetainPtr<CGImageRef> maskedImage(AdoptCF, CGImageCreateWithMaskingColors(image.get(), maskingColors)); if (!maskedImage) - return image; - - CGImageRelease(image); - return maskedImage; + return image.releaseRef(); + + return maskedImage.releaseRef(); } bool ImageSource::frameIsCompleteAtIndex(size_t index) @@ -233,15 +243,14 @@ float ImageSource::frameDurationAtIndex(size_t index) return 0; float duration = 0; - CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()); + RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions())); if (properties) { - CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); + CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (typeProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime); if (num) CFNumberGetValue(num, kCFNumberFloatType, &duration); } - CFRelease(properties); } // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.h b/WebCore/platform/graphics/cg/ImageSourceCG.h index d5b4b5a..76b4160 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.h +++ b/WebCore/platform/graphics/cg/ImageSourceCG.h @@ -36,6 +36,10 @@ String preferredExtensionForImageSourceType(const String& type); String MIMETypeForImageSourceType(const String& type); +#if !PLATFORM(MAC) +size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count); +#endif + } #endif // ImageSourceCG_h diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp index 858b18e..67333ae 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -33,6 +33,10 @@ #include "ImageObserver.h" #include <wtf/MathExtras.h> +#if !PLATFORM(MAC) +#include "ImageSourceCG.h" +#endif + using namespace std; namespace WebCore { @@ -68,16 +72,17 @@ bool PDFDocumentImage::dataChanged(bool allDataReceived) #if PLATFORM(MAC) // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer. - CFDataRef data = this->data()->createCFData(); + RetainPtr<CFDataRef> data(AdoptCF, this->data()->createCFData()); + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); #else - // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the - // scenes. We use CFDataCreateWithBytesNoCopy in that case. - CFDataRef data = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(this->data()->data()), this->data()->size(), kCFAllocatorNull); + // Create a CGDataProvider to wrap the SharedBuffer. + // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer + // does not provide a way to lock down the byte pointer and guarantee that it won't move, which + // is a requirement for using the GetBytePointer callback. + CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, 0 }; + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirect(this->data(), this->data()->size(), &providerCallbacks)); #endif - CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); - CFRelease(data); - m_document = CGPDFDocumentCreateWithProvider(dataProvider); - CGDataProviderRelease(dataProvider); + m_document = CGPDFDocumentCreateWithProvider(dataProvider.get()); setCurrentPage(0); } return m_document; // return true if size is available @@ -141,7 +146,7 @@ int PDFDocumentImage::pageCount() const return m_document ? CGPDFDocumentGetNumberOfPages(m_document) : 0; } -void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator op) +void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator op) { if (!m_document || m_currentPage == -1) return; diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h index 130c12c..12ab46c 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.h +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h @@ -58,7 +58,7 @@ namespace WebCore { virtual IntSize size() const; PDFDocumentImage(); - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); void setCurrentPage(int); int pageCount() const; diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp index 5812cea..3b05641 100644 --- a/WebCore/platform/graphics/cg/PathCG.cpp +++ b/WebCore/platform/graphics/cg/PathCG.cpp @@ -49,9 +49,8 @@ static size_t putBytesNowhere(void*, const void*, size_t count) static CGContextRef createScratchContext() { CGDataConsumerCallbacks callbacks = { putBytesNowhere, 0 }; - CGDataConsumerRef consumer = CGDataConsumerCreate(0, &callbacks); - CGContextRef context = CGPDFContextCreate(consumer, 0, 0); - CGDataConsumerRelease(consumer); + RetainPtr<CGDataConsumerRef> consumer(AdoptCF, CGDataConsumerCreate(0, &callbacks)); + CGContextRef context = CGPDFContextCreate(consumer.get(), 0, 0); CGFloat black[4] = { 0, 0, 0, 1 }; CGContextSetFillColor(context, black); @@ -129,9 +128,8 @@ bool Path::contains(const FloatPoint &point, WindRule rule) const return false; // CGPathContainsPoint returns false for non-closed paths, as a work-around, we copy and close the path first. Radar 4758998 asks for a better CG API to use - CGMutablePathRef path = copyCGPathClosingSubpaths(m_path); - bool ret = CGPathContainsPoint(path, 0, point, rule == RULE_EVENODD ? true : false); - CGPathRelease(path); + RetainPtr<CGMutablePathRef> path(AdoptCF, copyCGPathClosingSubpaths(m_path)); + bool ret = CGPathContainsPoint(path.get(), 0, point, rule == RULE_EVENODD ? true : false); return ret; } diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp index 9252ae0..e8fa860 100644 --- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -261,7 +261,7 @@ static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winf // characters. Because it's family names rather than font faces we use // as keys, there might be edge cases where one face of a font family // has a different repertoire from another face of the same family. -typedef HashMap<const wchar_t*, UnicodeSet*> FontCmapCache; +typedef HashMap<const wchar_t*, icu::UnicodeSet*> FontCmapCache; static bool fontContainsCharacter(const FontPlatformData* fontData, const wchar_t* family, UChar32 character) @@ -277,7 +277,7 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, if (!fontCmapCache) fontCmapCache = new FontCmapCache; - HashMap<const wchar_t*, UnicodeSet*>::iterator it = fontCmapCache->find(family); + HashMap<const wchar_t*, icu::UnicodeSet*>::iterator it = fontCmapCache->find(family); if (it != fontCmapCache->end()) return it->second->contains(character); @@ -308,7 +308,7 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, // 1) port back ICU 4.0's faster look-up code for UnicodeSet // 2) port Mozilla's CompressedCharMap or gfxSparseBitset unsigned i = 0; - UnicodeSet* cmap = new UnicodeSet; + icu::UnicodeSet* cmap = new icu::UnicodeSet; while (i < glyphset->cRanges) { WCHAR start = glyphset->ranges[i].wcLow; cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1); diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 3d67992..9f8f354 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -112,12 +112,16 @@ void TransparencyAwareFontPainter::init() void TransparencyAwareFontPainter::initializeForGDI() { + m_graphicsContext->save(); SkColor color = m_platformContext->effectiveFillColor(); + // Used only when m_createdTransparencyLayer is true. + float layerAlpha = 0.0f; if (SkColorGetA(color) != 0xFF) { // When the font has some transparency, apply it by creating a new - // transparency layer with that opacity applied. + // transparency layer with that opacity applied. We'll actually create + // a new transparency layer after we calculate the bounding box. m_createdTransparencyLayer = true; - m_graphicsContext->beginTransparencyLayer(SkColorGetA(color) / 255.0f); + layerAlpha = SkColorGetA(color) / 255.0f; // The color should be opaque now. color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); } @@ -131,16 +135,22 @@ void TransparencyAwareFontPainter::initializeForGDI() // and we could do ClearType in that case. layerMode = TransparencyWin::TextComposite; layerRect = estimateTextBounds(); + m_graphicsContext->clip(layerRect); + if (m_createdTransparencyLayer) + m_graphicsContext->beginTransparencyLayer(layerAlpha); // The transparency helper requires that we draw text in black in // this mode and it will apply the color. m_transparency.setTextCompositeColor(color); color = SkColorSetRGB(0, 0, 0); - } else if (canvasHasMultipleLayers(m_platformContext->canvas())) { + } else if (m_createdTransparencyLayer || canvasHasMultipleLayers(m_platformContext->canvas())) { // When we're drawing a web page, we know the background is opaque, // but if we're drawing to a layer, we still need extra work. layerMode = TransparencyWin::OpaqueCompositeLayer; layerRect = estimateTextBounds(); + m_graphicsContext->clip(layerRect); + if (m_createdTransparencyLayer) + m_graphicsContext->beginTransparencyLayer(layerAlpha); } else { // Common case of drawing onto the bottom layer of a web page: we // know everything is opaque so don't need to do anything special. @@ -167,6 +177,7 @@ TransparencyAwareFontPainter::~TransparencyAwareFontPainter() m_transparency.composite(); if (m_createdTransparencyLayer) m_graphicsContext->endTransparencyLayer(); + m_graphicsContext->restore(); m_platformContext->canvas()->endPlatformPaint(); } @@ -459,14 +470,16 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point); HDC hdc = painter.hdc(); - if (!hdc) + if (windowsCanHandleTextDrawing(graphicsContext) && !hdc) return; // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency. // Enforce non-transparent color. color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); - SetTextColor(hdc, skia::SkColorToCOLORREF(color)); - SetBkMode(hdc, TRANSPARENT); + if (hdc) { + SetTextColor(hdc, skia::SkColorToCOLORREF(color)); + SetBkMode(hdc, TRANSPARENT); + } // If there is a non-blur shadow and both the fill color and shadow color // are opaque, handle without skia. diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp index 88035d5..6bd7d7c 100644 --- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp @@ -42,12 +42,11 @@ #include "FontPlatformData.h" #include "NotImplemented.h" +#include "OpenTypeSanitizer.h" #include "SharedBuffer.h" #if PLATFORM(WIN_OS) #include <objbase.h> -#include <t2embapi.h> -#pragma comment(lib, "t2embed") #elif PLATFORM(LINUX) #include <cstring> #endif @@ -57,13 +56,8 @@ namespace WebCore { FontCustomPlatformData::~FontCustomPlatformData() { #if PLATFORM(WIN_OS) - if (m_fontReference) { - if (m_name.isNull()) { - ULONG status; - TTDeleteEmbeddedFont(m_fontReference, 0, &status); - } else - RemoveFontMemResourceEx(m_fontReference); - } + if (m_fontReference) + RemoveFontMemResourceEx(m_fontReference); #elif PLATFORM(LINUX) if (m_fontReference) m_fontReference->unref(); @@ -76,19 +70,15 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b ASSERT(m_fontReference); LOGFONT logFont; - if (m_name.isNull()) - TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0); - else { - // m_name comes from createUniqueFontName, which, in turn, gets - // it from base64-encoded uuid (128-bit). So, m_name - // can never be longer than LF_FACESIZE (32). - if (m_name.length() + 1 >= LF_FACESIZE) { - ASSERT_NOT_REACHED(); - return FontPlatformData(); - } - memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), - sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); + // m_name comes from createUniqueFontName, which, in turn, gets + // it from base64-encoded uuid (128-bit). So, m_name + // can never be longer than LF_FACESIZE (32). + if (m_name.length() + 1 >= LF_FACESIZE) { + ASSERT_NOT_REACHED(); + return FontPlatformData(); } + memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), + sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); // FIXME: almost identical to FillLogFont in FontCacheWin.cpp. // Need to refactor. @@ -119,69 +109,6 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b } #if PLATFORM(WIN_OS) -// FIXME: EOTStream class and static functions in this #if block are -// duplicated from platform/graphics/win/FontCustomPlatformData.cpp -// and need to be shared. - -// Streams the concatenation of a header and font data. -class EOTStream { -public: - EOTStream(const EOTHeader& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) - : m_eotHeader(eotHeader) - , m_fontData(fontData) - , m_overlayDst(overlayDst) - , m_overlaySrc(overlaySrc) - , m_overlayLength(overlayLength) - , m_offset(0) - , m_inHeader(true) - { - } - - size_t read(void* buffer, size_t count); - -private: - const EOTHeader& m_eotHeader; - const SharedBuffer* m_fontData; - size_t m_overlayDst; - size_t m_overlaySrc; - size_t m_overlayLength; - size_t m_offset; - bool m_inHeader; -}; - -size_t EOTStream::read(void* buffer, size_t count) -{ - size_t bytesToRead = count; - if (m_inHeader) { - size_t bytesFromHeader = std::min(m_eotHeader.size() - m_offset, count); - memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader); - m_offset += bytesFromHeader; - bytesToRead -= bytesFromHeader; - if (m_offset == m_eotHeader.size()) { - m_inHeader = false; - m_offset = 0; - } - } - if (bytesToRead && !m_inHeader) { - size_t bytesFromData = std::min(m_fontData->size() - m_offset, bytesToRead); - memcpy(buffer, m_fontData->data() + m_offset, bytesFromData); - if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) { - size_t dstOffset = std::max<int>(m_overlayDst - m_offset, 0); - size_t srcOffset = std::max<int>(0, m_offset - m_overlayDst); - size_t bytesToCopy = std::min(bytesFromData - dstOffset, m_overlayLength - srcOffset); - memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy); - } - m_offset += bytesFromData; - bytesToRead -= bytesFromData; - } - return count - bytesToRead; -} - -static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length) -{ - return static_cast<EOTStream*>(stream)->read(buffer, length); -} - // Creates a unique and unpredictable font name, in order to avoid collisions and to // not allow access from CSS. static String createUniqueFontName() @@ -245,38 +172,22 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); +#if ENABLE(OPENTYPE_SANITIZER) + OpenTypeSanitizer sanitizer(buffer); + RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize(); + if (!transcodeBuffer) + return 0; // validation failed. + buffer = transcodeBuffer.get(); +#endif + #if PLATFORM(WIN_OS) - // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's + // Introduce the font to GDI. AddFontMemResourceEx should be used with care, because it will pollute the process's // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the - // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name - // we avoid namespace collisions. - + // entire process first). String fontName = createUniqueFontName(); - - // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, - // so we need to create an EOT header and prepend it to the font data. - EOTHeader eotHeader; - size_t overlayDst; - size_t overlaySrc; - size_t overlayLength; - - if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength)) + HANDLE fontReference = renameAndActivateFont(buffer, fontName); + if (!fontReference) return 0; - - HANDLE fontReference; - ULONG privStatus; - ULONG status; - EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength); - - LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0); - if (loadEmbeddedFontResult == E_NONE) - fontName = String(); - else { - fontReference = renameAndActivateFont(buffer, fontName); - if (!fontReference) - return 0; - } - return new FontCustomPlatformData(fontReference, fontName); #elif PLATFORM(LINUX) RemoteFontStream stream(buffer); diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index d4e45fb..a4526a8 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -45,6 +45,11 @@ #include "SkTypeface.h" #include "SkUtils.h" +#include <unicode/normlzr.h> +#include <unicode/uchar.h> +#include <wtf/OwnArrayPtr.h> +#include <wtf/OwnPtr.h> + namespace WebCore { bool Font::canReturnFallbackFontsForComplexText() @@ -52,6 +57,23 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } +static bool isCanvasMultiLayered(SkCanvas* canvas) +{ + SkCanvas::LayerIter layerIterator(canvas, false); + layerIterator.next(); + return !layerIterator.done(); +} + +static bool adjustTextRenderMode(SkPaint* paint, bool isCanvasMultiLayered) +{ + // Our layers only have a single alpha channel. This means that subpixel + // rendered text cannot be compositied correctly when the layer is + // collapsed. Therefore, subpixel text is disabled when we are drawing + // onto a layer. + if (isCanvasMultiLayered) + paint->setLCDRenderText(false); +} + void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { @@ -79,12 +101,14 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, SkCanvas* canvas = gc->platformContext()->canvas(); int textMode = gc->platformContext()->getTextDrawingMode(); + bool haveMultipleLayers = isCanvasMultiLayered(canvas); // We draw text up to two times (once for fill, once for stroke). if (textMode & cTextFill) { SkPaint paint; gc->platformContext()->setupPaintForFilling(&paint); font->platformData().setupPaint(&paint); + adjustTextRenderMode(&paint, haveMultipleLayers); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->fillColor().rgb()); canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); @@ -97,6 +121,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, SkPaint paint; gc->platformContext()->setupPaintForStroking(&paint, 0, 0); font->platformData().setupPaint(&paint); + adjustTextRenderMode(&paint, haveMultipleLayers); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->strokeColor().rgb()); @@ -136,27 +161,29 @@ class TextRunWalker { public: TextRunWalker(const TextRun& run, unsigned startingX, const Font* font) : m_font(font) - , m_run(run) , m_startingX(startingX) , m_offsetX(m_startingX) - , m_iterateBackwards(run.rtl()) + , m_run(getTextRun(run)) + , m_iterateBackwards(m_run.rtl()) { + // Do not use |run| inside this constructor. Use |m_run| instead. + memset(&m_item, 0, sizeof(m_item)); // We cannot know, ahead of time, how many glyphs a given script run // will produce. We take a guess that script runs will not produce more // than twice as many glyphs as there are code points and fallback if // we find that we are wrong. - m_maxGlyphs = run.length() * 2; + m_maxGlyphs = m_run.length() * 2; createGlyphArrays(); - m_item.log_clusters = new unsigned short[run.length()]; + m_item.log_clusters = new unsigned short[m_run.length()]; m_item.face = 0; m_item.font = allocHarfbuzzFont(); - m_item.string = run.characters(); - m_item.stringLength = run.length(); - m_item.item.bidiLevel = run.rtl(); + m_item.string = m_run.characters(); + m_item.stringLength = m_run.length(); + m_item.item.bidiLevel = m_run.rtl(); reset(); } @@ -283,6 +310,43 @@ public: } private: + const TextRun& getTextRun(const TextRun& originalRun) + { + // Convert the |originalRun| to NFC normalized form if combining diacritical marks + // (U+0300..) are used in the run. This conversion is necessary since most OpenType + // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in + // their GSUB tables. + // + // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since + // the API returns FALSE (= not normalized) for complex runs that don't require NFC + // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, + // Harfbuzz will do the same thing for us using the GSUB table. + for (unsigned i = 0; i < originalRun.length(); ++i) { + UBlockCode block = ::ublock_getCode(originalRun[i]); + if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS) { + return getNormalizedTextRun(originalRun); + } + } + return originalRun; + } + + const TextRun& getNormalizedTextRun(const TextRun& originalRun) + { + icu::UnicodeString normalizedString; + UErrorCode error = U_ZERO_ERROR; + icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error); + if (U_FAILURE(error)) + return originalRun; + + m_normalizedBuffer.set(new UChar[normalizedString.length() + 1]); + normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error); + ASSERT(U_SUCCESS(error)); + + m_normalizedRun.set(new TextRun(originalRun)); + m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length()); + return *m_normalizedRun; + } + void setupFontForScriptRun() { const FontData* fontData = m_font->fontDataAt(0); @@ -379,7 +443,6 @@ private: } const Font* const m_font; - const TextRun& m_run; HB_ShaperItem m_item; uint16_t* m_glyphs16; // A vector of 16-bit glyph ids. SkScalar* m_xPositions; // A vector of x positions for each glyph. @@ -389,6 +452,10 @@ private: unsigned m_pixelWidth; // Width (in px) of the current script run. unsigned m_numCodePoints; // Code points in current script run. unsigned m_maxGlyphs; // Current size of all the Harfbuzz arrays. + + OwnPtr<TextRun> m_normalizedRun; + OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run. + const TextRun& m_run; bool m_iterateBackwards; }; @@ -425,15 +492,18 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, } TextRunWalker walker(run, point.x(), this); + bool haveMultipleLayers = isCanvasMultiLayered(canvas); while (walker.nextScriptRun()) { if (fill) { walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint); + adjustTextRenderMode(&fillPaint, haveMultipleLayers); canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), fillPaint); } if (stroke) { walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint); + adjustTextRenderMode(&strokePaint, haveMultipleLayers); canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), strokePaint); } } @@ -598,8 +668,6 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, if (toX == -1 && !to) toX = rightEdge; - else if (!walker.rtl()) - toX += truncateFixedPointToInteger(toAdvance); ASSERT(fromX != -1 && toX != -1); diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp index 9596a4c..4e2a226 100644 --- a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -100,11 +100,11 @@ void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) // Initialize the locale-dependent mapping. // Since Chrome synchronizes the ICU default locale with its UI locale, // this ICU locale tells the current UI locale of Chrome. - Locale locale = Locale::getDefault(); + icu::Locale locale = icu::Locale::getDefault(); const UChar* localeFamily = 0; - if (locale == Locale::getJapanese()) + if (locale == icu::Locale::getJapanese()) localeFamily = scriptFontMap[USCRIPT_HIRAGANA]; - else if (locale == Locale::getKorean()) + else if (locale == icu::Locale::getKorean()) localeFamily = scriptFontMap[USCRIPT_HANGUL]; else { // Use Simplified Chinese font for all other locales including diff --git a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp index a5a6e1f..1386163 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp @@ -46,12 +46,6 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String&) -{ - notImplemented(); - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) { notImplemented(); diff --git a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp index 93e36ba..23ca698 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp @@ -39,11 +39,6 @@ namespace WebCore { -PassRefPtr<Icon> Icon::createIconForFile(const String&) -{ - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) { return 0; diff --git a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp index b419e6f..b0145f8 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp @@ -52,26 +52,11 @@ Icon::~Icon() DestroyIcon(m_icon); } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) -{ - SHFILEINFO sfi; - memset(&sfi, 0, sizeof(sfi)); - - String tmpFilename = filename; - if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) - return 0; - - return adoptRef(new Icon(sfi.hIcon)); -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - // FIXME: support multiple files. + // FIXME: We can't access icons directly from renderer processes. // http://code.google.com/p/chromium/issues/detail?id=4092 - if (!filenames.size()) - return 0; - - return createIconForFile(filenames[0]); + return 0; } void Icon::paint(GraphicsContext* context, const IntRect& rect) diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp index 7957d5a..6dcd595 100644 --- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp +++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp @@ -275,7 +275,7 @@ void TransparencyWin::setupLayerForWhiteLayer() if (!m_validLayer) return; - m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white); + m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white, DeviceColorSpace); // Layer rect represents the part of the original layer. } diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp index 39b0847..10fcdf6 100644 --- a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp +++ b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp @@ -375,11 +375,13 @@ void UniscribeHelper::draw(GraphicsContext* graphicsContext, // Pass 0 in when there is no justification. const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph]; - if (firstRun) { - oldFont = SelectObject(dc, shaping.m_hfont); - firstRun = false; - } else - SelectObject(dc, shaping.m_hfont); + if (useWindowsDrawing) { + if (firstRun) { + oldFont = SelectObject(dc, shaping.m_hfont); + firstRun = false; + } else + SelectObject(dc, shaping.m_hfont); + } // Fonts with different ascents can be used to render different // runs. 'Across-runs' y-coordinate correction needs to be @@ -401,7 +403,7 @@ void UniscribeHelper::draw(GraphicsContext* graphicsContext, } else { SkPoint origin; origin.fX = curX + + innerOffset; - origin.fY = y + m_ascent - shaping.m_ascentOffset; + origin.fY = y + m_ascent; textOutOk = paintSkiaText(graphicsContext, shaping.m_hfont, glyphCount, diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index 86b702f..f362148 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005 Rob Buis <buis@kde.org> 2005 Eric Seidel <eric@webkit.org> + 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -24,7 +25,13 @@ #if ENABLE(FILTERS) #include "FEBlend.h" +#include "CanvasPixelArray.h" #include "Filter.h" +#include "FloatPoint.h" +#include "GraphicsContext.h" +#include "ImageData.h" + +typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB); namespace WebCore { @@ -61,8 +68,77 @@ void FEBlend::setBlendMode(BlendModeType mode) m_mode = mode; } -void FEBlend::apply(Filter*) +static unsigned char unknown(unsigned char, unsigned char, unsigned char, unsigned char) +{ + return 0; +} + +static unsigned char normal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char) +{ + return (((255 - alphaA) * colorB + colorA * 255) / 255); +} + +static unsigned char multiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) +{ + return (((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA) / 255); +} + +static unsigned char screen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char) +{ + return (((colorB + colorA) * 255 - colorA * colorB) / 255); +} + +static unsigned char darken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) +{ + return ((std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255); +} + +static unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) { + return ((std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255); +} + +void FEBlend::apply(Filter* filter) +{ + m_in->apply(filter); + m_in2->apply(filter); + if (!m_in->resultImage() || !m_in2->resultImage()) + return; + + if (m_mode == FEBLEND_MODE_UNKNOWN) + return; + + if (!getEffectContext()) + return; + + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); + RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); + + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->scaledSubRegion()); + RefPtr<CanvasPixelArray> srcPixelArrayB(m_in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)->data()); + + IntRect imageRect(IntPoint(), resultImage()->size()); + RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); + + // Keep synchronized with BlendModeType + static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten}; + + ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); + for (unsigned pixelOffset = 0; pixelOffset < srcPixelArrayA->length(); pixelOffset += 4) { + unsigned char alphaA = srcPixelArrayA->get(pixelOffset + 3); + unsigned char alphaB = srcPixelArrayB->get(pixelOffset + 3); + for (unsigned channel = 0; channel < 3; ++channel) { + unsigned char colorA = srcPixelArrayA->get(pixelOffset + channel); + unsigned char colorB = srcPixelArrayB->get(pixelOffset + channel); + + unsigned char result = (*callEffect[m_mode])(colorA, colorB, alphaA, alphaB); + imageData->data()->set(pixelOffset + channel, result); + } + unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255; + imageData->data()->set(pixelOffset + 3, alphaR); + } + + resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEBlend::dump() diff --git a/WebCore/platform/graphics/filters/FEBlend.h b/WebCore/platform/graphics/filters/FEBlend.h index b09cd72..31c625f 100644 --- a/WebCore/platform/graphics/filters/FEBlend.h +++ b/WebCore/platform/graphics/filters/FEBlend.h @@ -41,7 +41,7 @@ namespace WebCore { class FEBlend : public FilterEffect { public: static PassRefPtr<FEBlend> create(FilterEffect*, FilterEffect*, BlendModeType); - + FilterEffect* in2() const; void setIn2(FilterEffect*); diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index fb0a194..f422157 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -30,6 +30,7 @@ #include "GraphicsContext.h" #include "ImageData.h" #include <math.h> +#include <wtf/MathExtras.h> namespace WebCore { @@ -92,8 +93,8 @@ inline void saturate(double& red, double& green, double& blue, const float& s) inline void huerotate(double& red, double& green, double& blue, const float& hue) { - double cosHue = cos(hue * M_PI / 180); - double sinHue = sin(hue * M_PI / 180); + double cosHue = cos(hue * piDouble / 180); + double sinHue = sin(hue * piDouble / 180); double r = red * (0.213 + cosHue * 0.787 - sinHue * 0.213) + green * (0.715 - cosHue * 0.715 - sinHue * 0.715) + blue * (0.072 - cosHue * 0.072 + sinHue * 0.928); @@ -163,10 +164,10 @@ void FEColorMatrix::apply(Filter* filter) if (!filterContext) return; - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); IntRect imageRect(IntPoint(), resultImage()->size()); - PassRefPtr<ImageData> imageData(resultImage()->getImageData(imageRect)); + PassRefPtr<ImageData> imageData(resultImage()->getUnmultipliedImageData(imageRect)); PassRefPtr<CanvasPixelArray> srcPixelArray(imageData->data()); switch (m_type) { @@ -186,7 +187,7 @@ void FEColorMatrix::apply(Filter* filter) break; } - resultImage()->putImageData(imageData.get(), imageRect, IntPoint()); + resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEColorMatrix::dump() diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index 54ac123..1d9cfff 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005 Rob Buis <buis@kde.org> 2005 Eric Seidel <eric@webkit.org> + 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -24,10 +25,16 @@ #if ENABLE(FILTERS) #include "FEComponentTransfer.h" +#include "CanvasPixelArray.h" #include "Filter.h" +#include "GraphicsContext.h" +#include "ImageData.h" +#include <math.h> namespace WebCore { +typedef void (*TransferType)(unsigned char*, const ComponentTransferFunction&); + FEComponentTransfer::FEComponentTransfer(FilterEffect* in, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc) : FilterEffect() @@ -85,8 +92,91 @@ void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func m_alphaFunc = func; } -void FEComponentTransfer::apply(Filter*) +static void identity(unsigned char*, const ComponentTransferFunction&) +{ +} + +static void table(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + const Vector<float>& tableValues = transferFunction.tableValues; + unsigned n = tableValues.size(); + if (n < 1) + return; + for (unsigned i = 0; i < 256; ++i) { + double c = i / 255.0; + unsigned k = static_cast<unsigned>(c * (n - 1)); + double v1 = tableValues[k]; + double v2 = tableValues[std::min((k + 1), (n - 1))]; + double val = 255.0 * (v1 + (c * (n - 1) - k) * (v2 - v1)); + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +static void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + const Vector<float>& tableValues = transferFunction.tableValues; + unsigned n = tableValues.size(); + if (n < 1) + return; + for (unsigned i = 0; i < 256; ++i) { + unsigned k = static_cast<unsigned>((i * n) / 255.0); + k = std::min(k, n - 1); + double val = 255 * tableValues[k]; + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +static void linear(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + for (unsigned i = 0; i < 256; ++i) { + double val = transferFunction.slope * i + 255 * transferFunction.intercept; + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +static void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + for (unsigned i = 0; i < 256; ++i) { + double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), transferFunction.exponent) + transferFunction.offset); + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +void FEComponentTransfer::apply(Filter* filter) { + m_in->apply(filter); + if (!m_in->resultImage()) + return; + + if (!getEffectContext()) + return; + + unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; + for (unsigned i = 0; i < 256; ++i) + rValues[i] = gValues[i] = bValues[i] = aValues[i] = i; + unsigned char* tables[] = { rValues, gValues, bValues, aValues }; + ComponentTransferFunction transferFunction[] = {m_redFunc, m_greenFunc, m_blueFunc, m_alphaFunc}; + TransferType callEffect[] = {identity, identity, table, discrete, linear, gamma}; + + for (unsigned channel = 0; channel < 4; channel++) + (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); + + IntRect drawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); + RefPtr<ImageData> imageData(m_in->resultImage()->getUnmultipliedImageData(drawingRect)); + CanvasPixelArray* srcPixelArray(imageData->data()); + + for (unsigned pixelOffset = 0; pixelOffset < srcPixelArray->length(); pixelOffset += 4) { + for (unsigned channel = 0; channel < 4; ++channel) { + unsigned char c = srcPixelArray->get(pixelOffset + channel); + imageData->data()->set(pixelOffset + channel, tables[channel][c]); + } + } + + resultImage()->putUnmultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); } void FEComponentTransfer::dump() diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index 0706358..c540cb7 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005 Rob Buis <buis@kde.org> 2005 Eric Seidel <eric@webkit.org> + 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -24,7 +25,10 @@ #if ENABLE(FILTERS) #include "FEComposite.h" +#include "CanvasPixelArray.h" #include "Filter.h" +#include "GraphicsContext.h" +#include "ImageData.h" namespace WebCore { @@ -97,8 +101,74 @@ void FEComposite::setK4(float k4) m_k4 = k4; } -void FEComposite::apply(Filter*) +inline void arithmetic(const RefPtr<CanvasPixelArray>& srcPixelArrayA, CanvasPixelArray*& srcPixelArrayB, + float k1, float k2, float k3, float k4) { + float scaledK1 = k1 / 255.f; + float scaledK4 = k4 * 255.f; + for (unsigned pixelOffset = 0; pixelOffset < srcPixelArrayA->length(); pixelOffset += 4) { + for (unsigned channel = 0; channel < 4; ++channel) { + unsigned char i1 = srcPixelArrayA->get(pixelOffset + channel); + unsigned char i2 = srcPixelArrayB->get(pixelOffset + channel); + + unsigned char result = scaledK1 * i1 * i2 + k2 * i1 + k3 * i2 + scaledK4; + if (channel == 3 && i1 == 0 && i2 == 0) + result = 0; + srcPixelArrayB->set(pixelOffset + channel, result); + } + } +} + +void FEComposite::apply(Filter* filter) +{ + m_in->apply(filter); + m_in2->apply(filter); + if (!m_in->resultImage() || !m_in2->resultImage()) + return; + + GraphicsContext* filterContext = getEffectContext(); + if (!filterContext) + return; + + FloatRect srcRect = FloatRect(0.f, 0.f, -1.f, -1.f); + switch (m_type) { + case FECOMPOSITE_OPERATOR_OVER: + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); + break; + case FECOMPOSITE_OPERATOR_IN: + filterContext->save(); + filterContext->clipToImageBuffer(calculateDrawingRect(m_in2->scaledSubRegion()), m_in2->resultImage()); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); + filterContext->restore(); + break; + case FECOMPOSITE_OPERATOR_OUT: + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion()), srcRect, CompositeDestinationOut); + break; + case FECOMPOSITE_OPERATOR_ATOP: + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion()), srcRect, CompositeSourceAtop); + break; + case FECOMPOSITE_OPERATOR_XOR: + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion()), srcRect, CompositeXOR); + break; + case FECOMPOSITE_OPERATOR_ARITHMETIC: { + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); + RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); + + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->scaledSubRegion()); + RefPtr<ImageData> imageData(m_in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)); + CanvasPixelArray* srcPixelArrayB(imageData->data()); + + arithmetic(srcPixelArrayA, srcPixelArrayB, m_k1, m_k2, m_k3, m_k4); + resultImage()->putPremultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); + } + break; + default: + break; + } } void FEComposite::dump() diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp new file mode 100644 index 0000000..0b97e39 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -0,0 +1,144 @@ +/* + Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + 2004, 2005 Rob Buis <buis@kde.org> + 2005 Eric Seidel <eric@webkit.org> + 2009 Dirk Schulze <krit@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + 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. +*/ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FEGaussianBlur.h" + +#include "CanvasPixelArray.h" +#include "Filter.h" +#include "GraphicsContext.h" +#include "ImageData.h" +#include <math.h> +#include <wtf/MathExtras.h> + +using std::max; + +namespace WebCore { + +FEGaussianBlur::FEGaussianBlur(FilterEffect* in, const float& x, const float& y) + : FilterEffect() + , m_in(in) + , m_x(x) + , m_y(y) +{ +} + +PassRefPtr<FEGaussianBlur> FEGaussianBlur::create(FilterEffect* in, const float& x, const float& y) +{ + return adoptRef(new FEGaussianBlur(in, x, y)); +} + +float FEGaussianBlur::stdDeviationX() const +{ + return m_x; +} + +void FEGaussianBlur::setStdDeviationX(float x) +{ + m_x = x; +} + +float FEGaussianBlur::stdDeviationY() const +{ + return m_y; +} + +void FEGaussianBlur::setStdDeviationY(float y) +{ + m_y = y; +} + +static void boxBlur(CanvasPixelArray*& srcPixelArray, CanvasPixelArray*& dstPixelArray, + unsigned dx, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage) +{ + int dxLeft = dx / 2; + int dxRight = dx - dxLeft; + + for (int y = 0; y < effectHeight; ++y) { + int line = y * strideLine; + for (int channel = 3; channel >= 0; --channel) { + int sum = 0; + // Fill the kernel + int maxKernelSize = std::min(dxRight, effectWidth); + for (int i = 0; i < maxKernelSize; ++i) + sum += srcPixelArray->get(line + i * stride + channel); + + // Blurring + for (int x = 0; x < effectWidth; ++x) { + int pixelByteOffset = line + x * stride + channel; + dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx)); + if (x >= dxLeft) + sum -= srcPixelArray->get(pixelByteOffset - dxLeft * stride); + if (x + dxRight < effectWidth) + sum += srcPixelArray->get(pixelByteOffset + dxRight * stride); + } + if (alphaImage) // Source image is black, it just has different alpha values + break; + } + } +} + +void FEGaussianBlur::apply(Filter* filter) +{ + m_in->apply(filter); + if (!m_in->resultImage()) + return; + + if (!getEffectContext()) + return; + + setIsAlphaImage(m_in->isAlphaImage()); + + if (m_x == 0 || m_y == 0) + return; + + unsigned sdx = static_cast<unsigned>(floor(m_x * filter->filterResolution().width() * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + unsigned sdy = static_cast<unsigned>(floor(m_y * filter->filterResolution().height() * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + sdx = max(sdx, static_cast<unsigned>(1)); + sdy = max(sdy, static_cast<unsigned>(1)); + + IntRect effectDrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); + RefPtr<ImageData> srcImageData(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect)); + CanvasPixelArray* srcPixelArray(srcImageData->data()); + + IntRect imageRect(IntPoint(), resultImage()->size()); + RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height()); + CanvasPixelArray* tmpPixelArray(tmpImageData->data()); + + int stride = 4 * imageRect.width(); + for (int i = 0; i < 3; ++i) { + boxBlur(srcPixelArray, tmpPixelArray, sdx, 4, stride, imageRect.width(), imageRect.height(), isAlphaImage()); + boxBlur(tmpPixelArray, srcPixelArray, sdy, stride, 4, imageRect.height(), imageRect.width(), isAlphaImage()); + } + + resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint()); +} + +void FEGaussianBlur::dump() +{ +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.h b/WebCore/platform/graphics/filters/FEGaussianBlur.h new file mode 100644 index 0000000..ecdb9e3 --- /dev/null +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> + 2004, 2005 Rob Buis <buis@kde.org> + 2005 Eric Seidel <eric@webkit.org> + + 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 FEGaussianBlur_h +#define FEGaussianBlur_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" +#include "Filter.h" + +namespace WebCore { + + class FEGaussianBlur : public FilterEffect { + public: + static PassRefPtr<FEGaussianBlur> create(FilterEffect*, const float&, const float&); + + float stdDeviationX() const; + void setStdDeviationX(float); + + float stdDeviationY() const; + void setStdDeviationY(float); + + virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); } + void apply(Filter*); + void dump(); + + private: + FEGaussianBlur(FilterEffect*, const float&, const float&); + + RefPtr<FilterEffect> m_in; + float m_x; + float m_y; + }; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FEGaussianBlur_h diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h index ee97afc..8924b94 100644 --- a/WebCore/platform/graphics/filters/Filter.h +++ b/WebCore/platform/graphics/filters/Filter.h @@ -22,6 +22,7 @@ #if ENABLE(FILTERS) #include "FloatRect.h" +#include "FloatSize.h" #include "ImageBuffer.h" #include "StringHash.h" @@ -40,15 +41,21 @@ namespace WebCore { void setSourceImage(PassOwnPtr<ImageBuffer> sourceImage) { m_sourceImage = sourceImage; } ImageBuffer* sourceImage() { return m_sourceImage.get(); } - virtual FloatRect sourceImageRect() = 0; - virtual FloatRect filterRegion() = 0; + FloatSize filterResolution() const { return m_filterResolution; } + void setFilterResolution(const FloatSize& filterResolution) { m_filterResolution = filterResolution; } + + virtual FloatRect sourceImageRect() const = 0; + virtual FloatRect filterRegion() const = 0; // SVG specific - virtual void calculateEffectSubRegion(FilterEffect*) = 0; - virtual bool effectBoundingBoxMode() = 0; + virtual void calculateEffectSubRegion(FilterEffect*) { } + + virtual FloatSize maxImageSize() const = 0; + virtual bool effectBoundingBoxMode() const = 0; private: OwnPtr<ImageBuffer> m_sourceImage; + FloatSize m_filterResolution; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index 41e8a39..5583813 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -25,14 +25,11 @@ namespace WebCore { FilterEffect::FilterEffect() - : m_xBBoxMode(false) - , m_yBBoxMode(false) - , m_widthBBoxMode(false) - , m_heightBBoxMode(false) - , m_hasX(false) + : m_hasX(false) , m_hasY(false) , m_hasWidth(false) , m_hasHeight(false) + , m_alphaImage(false) { } @@ -59,16 +56,23 @@ FloatRect FilterEffect::calculateEffectRect(Filter* filter) return subRegion(); } +IntRect FilterEffect::calculateDrawingIntRect(const FloatRect& effectRect) +{ + IntPoint location = roundedIntPoint(FloatPoint(scaledSubRegion().x() - effectRect.x(), + scaledSubRegion().y() - effectRect.y())); + return IntRect(location, resultImage()->size()); +} + FloatRect FilterEffect::calculateDrawingRect(const FloatRect& srcRect) { - FloatPoint startPoint = FloatPoint(srcRect.x() - subRegion().x(), srcRect.y() - subRegion().y()); + FloatPoint startPoint = FloatPoint(srcRect.x() - scaledSubRegion().x(), srcRect.y() - scaledSubRegion().y()); FloatRect drawingRect = FloatRect(startPoint, srcRect.size()); return drawingRect; } GraphicsContext* FilterEffect::getEffectContext() { - IntRect bufferRect = enclosingIntRect(subRegion()); + IntRect bufferRect = enclosingIntRect(scaledSubRegion()); m_effectBuffer = ImageBuffer::create(bufferRect.size(), LinearRGB); return m_effectBuffer->context(); } diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index 8dc6233..a46d795 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -38,24 +38,18 @@ namespace WebCore { public: virtual ~FilterEffect(); - bool xBoundingBoxMode() const { return m_xBBoxMode; } - void setXBoundingBoxMode(bool bboxMode) { m_xBBoxMode = bboxMode; } - - bool yBoundingBoxMode() const { return m_yBBoxMode; } - void setYBoundingBoxMode(bool bboxMode) { m_yBBoxMode = bboxMode; } - - bool widthBoundingBoxMode() const { return m_widthBBoxMode; } - void setWidthBoundingBoxMode(bool bboxMode) { m_widthBBoxMode = bboxMode; } - - bool heightBoundingBoxMode() const { return m_heightBBoxMode; } - void setHeightBoundingBoxMode(bool bboxMode) { m_heightBBoxMode = bboxMode; } - void setUnionOfChildEffectSubregions(const FloatRect& uniteRect) { m_unionOfChildEffectSubregions = uniteRect; } FloatRect unionOfChildEffectSubregions() const { return m_unionOfChildEffectSubregions; } FloatRect subRegion() const { return m_subRegion; } void setSubRegion(const FloatRect& subRegion) { m_subRegion = subRegion; } + FloatRect scaledSubRegion() const { return m_scaledSubRegion; } + void setScaledSubRegion(const FloatRect& scaledSubRegion) { m_scaledSubRegion = scaledSubRegion; } + + FloatRect effectBoundaries() const { return m_effectBoundaries; } + void setEffectBoundaries(const FloatRect& effectBoundaries) { m_effectBoundaries = effectBoundaries; } + bool hasX() { return m_hasX; } void setHasX(bool value) { m_hasX = value; } @@ -77,6 +71,11 @@ namespace WebCore { GraphicsContext* getEffectContext(); FloatRect calculateDrawingRect(const FloatRect&); + IntRect calculateDrawingIntRect(const FloatRect&); + + // black image with different alpha values + bool isAlphaImage() { return m_alphaImage; } + void setIsAlphaImage(bool alphaImage) { m_alphaImage = alphaImage; } virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return filter->filterRegion(); } virtual FloatRect calculateEffectRect(Filter*); @@ -101,7 +100,11 @@ namespace WebCore { bool m_hasWidth : 1; bool m_hasHeight : 1; + bool m_alphaImage; + + FloatRect m_effectBoundaries; FloatRect m_subRegion; + FloatRect m_scaledSubRegion; FloatRect m_unionOfChildEffectSubregions; mutable OwnPtr<ImageBuffer> m_effectBuffer; diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp new file mode 100644 index 0000000..33953d6 --- /dev/null +++ b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * + * 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. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "ImageBufferFilter.h" + +#include "FloatSize.h" + +namespace WebCore { + +ImageBufferFilter::ImageBufferFilter() + : Filter() +{ + setFilterResolution(FloatSize(1.f, 1.f)); +} + +PassRefPtr<ImageBufferFilter> ImageBufferFilter::create() +{ + return adoptRef(new ImageBufferFilter()); +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.h b/WebCore/platform/graphics/filters/ImageBufferFilter.h new file mode 100644 index 0000000..a2775ea --- /dev/null +++ b/WebCore/platform/graphics/filters/ImageBufferFilter.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * + * 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 ImageBufferFilter_h +#define ImageBufferFilter_h + +#if ENABLE(FILTERS) +#include "Filter.h" +#include "FilterEffect.h" +#include "FloatRect.h" +#include "FloatSize.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class ImageBufferFilter : public Filter { +public: + static PassRefPtr<ImageBufferFilter> create(); + + virtual FloatRect filterRegion() const { return FloatRect(); } + virtual FloatRect sourceImageRect() const { return FloatRect(); } + + // SVG specific + virtual bool effectBoundingBoxMode() const { return false; } + + virtual FloatSize maxImageSize() const { return FloatSize(); } + virtual void calculateEffectSubRegion(FilterEffect*) { } + +private: + ImageBufferFilter(); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // ImageBufferFilter_h diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index 646a57b..539bb44 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -22,6 +22,7 @@ #if ENABLE(FILTERS) #include "SourceAlpha.h" +#include "Color.h" #include "GraphicsContext.h" #include "PlatformString.h" #include "Filter.h" @@ -41,8 +42,32 @@ const AtomicString& SourceAlpha::effectName() return s_effectName; } -void SourceAlpha::apply(Filter*) +FloatRect SourceAlpha::calculateEffectRect(Filter* filter) { + FloatRect clippedSourceRect = filter->sourceImageRect(); + if (filter->sourceImageRect().x() < filter->filterRegion().x()) + clippedSourceRect.setX(filter->filterRegion().x()); + if (filter->sourceImageRect().y() < filter->filterRegion().y()) + clippedSourceRect.setY(filter->filterRegion().y()); + setSubRegion(clippedSourceRect); + clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setScaledSubRegion(clippedSourceRect); + return filter->filterRegion(); +} + +void SourceAlpha::apply(Filter* filter) +{ + GraphicsContext* filterContext = getEffectContext(); + if (!filterContext) + return; + + setIsAlphaImage(true); + + FloatRect imageRect(FloatPoint(), filter->sourceImage()->image()->size()); + filterContext->save(); + filterContext->clipToImageBuffer(imageRect, filter->sourceImage()); + filterContext->fillRect(imageRect, Color::black, DeviceColorSpace); + filterContext->restore(); } void SourceAlpha::dump() diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h index 5341562..172d05a 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.h +++ b/WebCore/platform/graphics/filters/SourceAlpha.h @@ -35,7 +35,7 @@ namespace WebCore { static const AtomicString& effectName(); virtual bool isSourceInput() { return true; } - virtual FloatRect calculateEffectRect(Filter* filter) { return filter->sourceImageRect(); } + virtual FloatRect calculateEffectRect(Filter*); void apply(Filter*); void dump(); diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp index 023eeac..cc55618 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.cpp +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -49,6 +49,8 @@ FloatRect SourceGraphic::calculateEffectRect(Filter* filter) if (filter->sourceImageRect().y() < filter->filterRegion().y()) clippedSourceRect.setY(filter->filterRegion().y()); setSubRegion(clippedSourceRect); + clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setScaledSubRegion(clippedSourceRect); return filter->filterRegion(); } @@ -58,7 +60,7 @@ void SourceGraphic::apply(Filter* filter) if (!filterContext) return; - filterContext->drawImage(filter->sourceImage()->image(), IntPoint()); + filterContext->drawImage(filter->sourceImage()->image(), DeviceColorSpace, IntPoint()); } void SourceGraphic::dump() diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp new file mode 100644 index 0000000..567da74 --- /dev/null +++ b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2009 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 "DataSourceGStreamer.h" + +#include <gio/gio.h> +#include <glib.h> +#include <gst/gst.h> +#include <gst/pbutils/missing-plugins.h> + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GST_DEBUG_CATEGORY_STATIC(webkit_data_src_debug); +#define GST_CAT_DEFAULT webkit_data_src_debug + +static void webkit_data_src_uri_handler_init(gpointer g_iface, + gpointer iface_data); + +static void webkit_data_src_finalize(WebkitDataSrc* src); +static GstStateChangeReturn webkit_data_src_change_state(GstElement* element, + GstStateChange transition); + +static const GInterfaceInfo urihandler_info = { + webkit_data_src_uri_handler_init, + 0, 0 +}; + + +static void _do_init(GType datasrc_type) +{ + GST_DEBUG_CATEGORY_INIT(webkit_data_src_debug, "webkit_data_src", 0, "datasrc element"); + g_type_add_interface_static(datasrc_type, GST_TYPE_URI_HANDLER, + &urihandler_info); +} + +GST_BOILERPLATE_FULL(WebkitDataSrc, webkit_data_src, GstBin, GST_TYPE_BIN, _do_init); + +static void webkit_data_src_base_init(gpointer klass) +{ + GstElementClass* element_class = GST_ELEMENT_CLASS(klass); + + gst_element_class_add_pad_template(element_class, + gst_static_pad_template_get(&src_template)); + gst_element_class_set_details_simple(element_class, (gchar*) "WebKit data source element", + (gchar*) "Source", + (gchar*) "Handles data: uris", + (gchar*) "Philippe Normand <pnormand@igalia.com>"); + +} + +static void webkit_data_src_class_init(WebkitDataSrcClass* klass) +{ + GObjectClass* oklass = G_OBJECT_CLASS(klass); + GstElementClass* eklass = GST_ELEMENT_CLASS(klass); + + oklass->finalize = (GObjectFinalizeFunc) webkit_data_src_finalize; + eklass->change_state = webkit_data_src_change_state; +} + + +static gboolean webkit_data_src_reset(WebkitDataSrc* src) +{ + GstPad* targetpad; + + if (src->kid) { + gst_element_set_state(src->kid, GST_STATE_NULL); + gst_bin_remove(GST_BIN(src), src->kid); + } + + src->kid = gst_element_factory_make("giostreamsrc", "streamsrc"); + if (!src->kid) { + GST_ERROR_OBJECT(src, "Failed to create giostreamsrc"); + return FALSE; + } + + gst_bin_add(GST_BIN(src), src->kid); + + targetpad = gst_element_get_static_pad(src->kid, "src"); + gst_ghost_pad_set_target(GST_GHOST_PAD(src->pad), targetpad); + gst_object_unref(targetpad); + + return TRUE; +} + +static void webkit_data_src_init(WebkitDataSrc* src, + WebkitDataSrcClass* g_class) +{ + GstPadTemplate* pad_template = gst_static_pad_template_get(&src_template); + src->pad = gst_ghost_pad_new_no_target_from_template("src", + pad_template); + + gst_element_add_pad(GST_ELEMENT(src), src->pad); + + webkit_data_src_reset(src); +} + +static void webkit_data_src_finalize(WebkitDataSrc* src) +{ + g_free(src->uri); + + if (src->kid) { + GST_DEBUG_OBJECT(src, "Removing giostreamsrc element"); + gst_element_set_state(src->kid, GST_STATE_NULL); + gst_bin_remove(GST_BIN(src), src->kid); + src->kid = 0; + } + + GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src))); +} + +static GstStateChangeReturn webkit_data_src_change_state(GstElement* element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + WebkitDataSrc* src = WEBKIT_DATA_SRC(element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!src->kid) { + gst_element_post_message(element, + gst_missing_element_message_new(element, "giostreamsrc")); + GST_ELEMENT_ERROR(src, CORE, MISSING_PLUGIN, (0), ("no giostreamsrc")); + return GST_STATE_CHANGE_FAILURE; + } + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); + if (G_UNLIKELY(ret == GST_STATE_CHANGE_FAILURE)) + return ret; + + // Downwards state change code should be here, after chaining up + // to the parent class. + + return ret; +} + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static GstURIType webkit_data_src_uri_get_type(void) +{ + return GST_URI_SRC; +} + +static gchar** webkit_data_src_uri_get_protocols(void) +{ + static gchar* protocols[] = {(gchar*) "data", 0 }; + + return protocols; +} + +static const gchar* webkit_data_src_uri_get_uri(GstURIHandler* handler) +{ + WebkitDataSrc* src = WEBKIT_DATA_SRC(handler); + + return src->uri; +} + +static gboolean webkit_data_src_uri_set_uri(GstURIHandler* handler, const gchar* uri) +{ + WebkitDataSrc* src = WEBKIT_DATA_SRC(handler); + + // URI as defined in RFC2397: + // "data:" [ mediatype ] [ ";base64" ] "," data + // we parse URIs like this one: + // data:audio/3gpp;base64,AA... + + gchar** scheme_and_remains = g_strsplit(uri, ":", 2); + gchar** mime_type_and_options = g_strsplit(scheme_and_remains[1], ";", 0); + gint options_size = g_strv_length(mime_type_and_options); + gchar* data = 0; + gchar* mime_type = 0; + gint ret = FALSE; + + // we require uris with a specified mime-type and base64-encoded + // data. It doesn't make much sense anyway to play plain/text data + // with very few allowed characters (as per the RFC). + + if (GST_STATE(src) >= GST_STATE_PAUSED) { + GST_ERROR_OBJECT(src, "Element already configured. Reset it and retry"); + } else if (!options_size) + GST_ERROR_OBJECT(src, "A mime-type is needed in %s", uri); + else { + mime_type = mime_type_and_options[0]; + data = mime_type_and_options[options_size-1]; + + guchar* decoded_data = 0; + gsize decoded_size; + + if (!g_str_has_prefix(data, "base64")) + GST_ERROR_OBJECT(src, "Data has to be base64-encoded in %s", uri); + else { + decoded_data = g_base64_decode(data+7, &decoded_size); + GInputStream* stream = g_memory_input_stream_new_from_data(decoded_data, + decoded_size, + g_free); + g_object_set(src->kid, "stream", stream, NULL); + g_object_unref(stream); + + if (src->uri) { + g_free(src->uri); + src->uri = 0; + } + + src->uri = g_strdup(uri); + ret = TRUE; + } + } + + g_strfreev(scheme_and_remains); + g_strfreev(mime_type_and_options); + return ret; +} + +static void webkit_data_src_uri_handler_init(gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface* iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = webkit_data_src_uri_get_type; + iface->get_protocols = webkit_data_src_uri_get_protocols; + iface->get_uri = webkit_data_src_uri_get_uri; + iface->set_uri = webkit_data_src_uri_set_uri; +} diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.h b/WebCore/platform/graphics/gtk/DataSourceGStreamer.h new file mode 100644 index 0000000..3e88f63 --- /dev/null +++ b/WebCore/platform/graphics/gtk/DataSourceGStreamer.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 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 DATA_SOURCE_GSTREAMER_H +#define DATA_SOURCE_GSTREAMER_H + +#include <glib-object.h> +#include <gst/base/gstbasesrc.h> + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_DATA_SRC (webkit_data_src_get_type ()) +#define WEBKIT_DATA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_DATA_SRC, WebkitDataSrc)) +#define WEBKIT_DATA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_DATA_SRC, WebkitDataSrcClass)) +#define WEBKIT_IS_DATA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_DATA_SRC)) +#define WEBKIT_IS_DATA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_DATA_SRC)) + +typedef struct _WebkitDataSrc WebkitDataSrc; +typedef struct _WebkitDataSrcClass WebkitDataSrcClass; + + +struct _WebkitDataSrc { + GstBin parent; + + /* explicit pointers to stuff used */ + GstElement* kid; + GstPad* pad; + gchar* uri; +}; + +struct _WebkitDataSrcClass { + GstBinClass parent_class; +}; + +GType webkit_data_src_get_type(void); + +G_END_DECLS + +#endif diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp index ee86f96..5c320e0 100644 --- a/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -259,7 +259,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F // Re-enable the platform shadow we disabled earlier if (hasShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); // Pango sometimes leaves behind paths we don't want cairo_new_path(cr); diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h index 2a65f1e..d30b480 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformData.h +++ b/WebCore/platform/graphics/gtk/FontPlatformData.h @@ -87,7 +87,7 @@ public: bool syntheticBold() const { return m_syntheticBold; } bool syntheticOblique() const { return m_syntheticOblique; } - void setFont(cairo_t*) const; + cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } unsigned hash() const { diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp index f2c5f0c..0b1280e 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp @@ -224,10 +224,8 @@ FontPlatformData::~FontPlatformData() m_fallbacks = 0; } - if (m_scaledFont) { + if (m_scaledFont) cairo_scaled_font_destroy(m_scaledFont); - m_scaledFont = 0; - } } bool FontPlatformData::isFixedPitch() @@ -242,13 +240,6 @@ bool FontPlatformData::isFixedPitch() return false; } -void FontPlatformData::setFont(cairo_t* cr) const -{ - ASSERT(m_scaledFont); - - cairo_set_scaled_font(cr, m_scaledFont); -} - bool FontPlatformData::operator==(const FontPlatformData& other) const { if (m_pattern == other.m_pattern) diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp index 9ea6811..8a1a5f1 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp +++ b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp @@ -214,13 +214,6 @@ bool FontPlatformData::isFixedPitch() return pango_font_family_is_monospace(family); } -void FontPlatformData::setFont(cairo_t* cr) const -{ - ASSERT(m_scaledFont); - - cairo_set_scaled_font(cr, m_scaledFont); -} - FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) { // Check for self-assignment. diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp index e08c1ab..3563a59 100644 --- a/WebCore/platform/graphics/gtk/IconGtk.cpp +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -87,23 +87,25 @@ static String lookupIconName(String MIMEType) return GTK_STOCK_FILE; } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - if (!g_path_skip_root(filename.utf8().data())) + if (filenames.isEmpty()) return 0; - String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filename); - String iconName = lookupIconName(MIMEType); + if (filenames.size() == 1) { + if (!g_path_skip_root(filenames[0].utf8().data())) + return 0; - RefPtr<Icon> icon = adoptRef(new Icon); - icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); - if (!icon->m_icon) - return 0; - return icon.release(); -} + String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filenames[0]); + String iconName = lookupIconName(MIMEType); + + RefPtr<Icon> icon = adoptRef(new Icon); + icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, 0); + if (!icon->m_icon) + return 0; + return icon.release(); + } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) -{ //FIXME: Implement this return 0; } diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp index 0e92d6c..38da70d 100644 --- a/WebCore/platform/graphics/gtk/ImageGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -88,26 +88,67 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name) return img.release(); } +static inline unsigned char* getCairoSurfacePixel(unsigned char* data, uint x, uint y, uint rowStride) +{ + return data + (y * rowStride) + x * 4; +} + +static inline guchar* getGdkPixbufPixel(guchar* data, uint x, uint y, uint rowStride) +{ + return data + (y * rowStride) + x * 4; +} + GdkPixbuf* BitmapImage::getGdkPixbuf() { int width = cairo_image_surface_get_width(frameAtIndex(currentFrame())); int height = cairo_image_surface_get_height(frameAtIndex(currentFrame())); - - int bestDepth = gdk_visual_get_best_depth(); - GdkColormap* cmap = gdk_colormap_new(gdk_visual_get_best_with_depth(bestDepth), true); - - GdkPixmap* pixmap = gdk_pixmap_new(0, width, height, bestDepth); - gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), cmap); - cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(pixmap)); - cairo_set_source_surface(cr, frameAtIndex(currentFrame()), 0, 0); - cairo_paint(cr); - cairo_destroy(cr); - - GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(0, GDK_DRAWABLE(pixmap), 0, 0, 0, 0, 0, width, height); - g_object_unref(pixmap); - g_object_unref(cmap); - - return pixbuf; + unsigned char* surfaceData = cairo_image_surface_get_data(frameAtIndex(currentFrame())); + int surfaceRowStride = cairo_image_surface_get_stride(frameAtIndex(currentFrame())); + + GdkPixbuf* dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); + if (!dest) + return 0; + + guchar* pixbufData = gdk_pixbuf_get_pixels(dest); + int pixbufRowStride = gdk_pixbuf_get_rowstride(dest); + + /* From: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t + * "CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with alpha in + * the upper 8 bits, then red, then green, then blue. The 32-bit + * quantities are stored native-endian. Pre-multiplied alpha is used. + * (That is, 50% transparent red is 0x80800000, not 0x80ff0000.)" + * + * See http://developer.gimp.org/api/2.0/gdk-pixbuf/gdk-pixbuf-gdk-pixbuf.html#GdkPixbuf + * for information on the structure of GdkPixbufs stored with GDK_COLORSPACE_RGB. + * + * RGB color channels in CAIRO_FORMAT_ARGB32 are stored based on the + * endianness of the machine and are also multiplied by the alpha channel. + * To properly transfer the data from the Cairo surface we must divide each + * of the RGB channels by the alpha channel and then reorder all channels + * if this machine is little-endian. + */ + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + unsigned char* source = getCairoSurfacePixel(surfaceData, x, y, surfaceRowStride); + guchar* dest = getGdkPixbufPixel(pixbufData, x, y, pixbufRowStride); + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + guchar alpha = source[3]; + dest[0] = alpha ? ((source[2] * 255) / alpha) : 0; + dest[1] = alpha ? ((source[1] * 255) / alpha) : 0; + dest[2] = alpha ? ((source[0] * 255) / alpha) : 0; + dest[3] = alpha; +#else + guchar alpha = source[0]; + dest[0] = alpha ? ((source[1] * 255) / alpha) : 0; + dest[1] = alpha ? ((source[2] * 255) / alpha) : 0; + dest[2] = alpha ? ((source[3] * 255) / alpha) : 0; + dest[3] = alpha; +#endif + } + } + + return dest; } } diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp index 4e4bda9..a023dae 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Collabora Ltd. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,7 +26,9 @@ #include "MediaPlayerPrivateGStreamer.h" + #include "CString.h" +#include "DataSourceGStreamer.h" #include "GraphicsContext.h" #include "IntRect.h" #include "KURL.h" @@ -33,71 +36,100 @@ #include "MediaPlayer.h" #include "NotImplemented.h" #include "ScrollView.h" +#include "TimeRanges.h" #include "VideoSinkGStreamer.h" #include "Widget.h" -#include <gst/base/gstbasesrc.h> #include <gst/gst.h> #include <gst/interfaces/mixer.h> #include <gst/interfaces/xoverlay.h> #include <gst/video/video.h> #include <limits> #include <math.h> -#include <wtf/GOwnPtr.h> +#include <wtf/gtk/GOwnPtr.h> using namespace std; namespace WebCore { -gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data) +gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data) { - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) { - GOwnPtr<GError> err; - GOwnPtr<gchar> debug; + GOwnPtr<GError> err; + GOwnPtr<gchar> debug; + MediaPlayer::NetworkState error; + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + gint percent = 0; + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); - if (err->code == 3) { - LOG_VERBOSE(Media, "File not found"); - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); - if (mp) - mp->loadingFailed(); - } else - LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); - } - return true; -} - -gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data) -{ - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS) { + 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) + error = MediaPlayer::DecodeError; + else if (err->domain == GST_RESOURCE_ERROR) + error = MediaPlayer::NetworkError; + + if (mp) + mp->loadingFailed(error); + break; + case GST_MESSAGE_EOS: LOG_VERBOSE(Media, "End of Stream"); - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); mp->didEnd(); - } - return true; -} - -gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data) -{ - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED) { - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + break; + case GST_MESSAGE_STATE_CHANGED: mp->updateStates(); + break; + case GST_MESSAGE_BUFFERING: + gst_message_parse_buffering(message, &percent); + LOG_VERBOSE(Media, "Buffering %d", percent); + break; + default: + LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s", + GST_MESSAGE_TYPE_NAME(message)); + break; } return true; } -gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data) +static float playbackPosition(GstElement* playbin) { - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING) { - gint percent = 0; - gst_message_parse_buffering(message, &percent); - LOG_VERBOSE(Media, "Buffering %d", percent); + + float ret = 0.0; + + 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; } - return true; + + gint64 position; + gst_query_parse_position(query, 0, &position); + + // Position is available only if the pipeline is not in NULL or + // 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; } -static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, MediaPlayerPrivate* playerPrivate) +void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate) { + g_return_if_fail(GST_IS_BUFFER(buffer)); + gst_buffer_replace(&playerPrivate->m_buffer, buffer); playerPrivate->repaint(); } @@ -112,43 +144,74 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) registrar(create, getSupportedTypes, supportsType); } +static bool gstInitialized = false; + +static bool do_gst_init() +{ + // FIXME: We should pass the arguments from the command line + if (!gstInitialized) { + GOwnPtr<GError> error; + gstInitialized = gst_init_check(0, 0, &error.outPtr()); + if (!gstInitialized) + LOG_VERBOSE(Media, "Could not initialize GStreamer: %s", + error ? error->message : "unknown error occurred"); + else + gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, + WEBKIT_TYPE_DATA_SRC); + + } + return gstInitialized; +} + +bool MediaPlayerPrivate::isAvailable() +{ + if (!do_gst_init()) + return false; + + GstElementFactory* factory = gst_element_factory_find("playbin2"); + if (factory) { + gst_object_unref(GST_OBJECT(factory)); + return true; + } + return false; +} + MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player) , m_playBin(0) , m_videoSink(0) , m_source(0) - , m_rate(1.0f) + , m_seekTime(0) + , m_changingRate(false) , m_endTime(numeric_limits<float>::infinity()) - , m_isEndReached(false) - , m_volume(0.5f) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) , m_startedPlaying(false) , m_isStreaming(false) , m_size(IntSize()) - , m_visible(true) + , m_buffer(0) + , m_paused(true) + , m_seeking(false) + , m_errorOccured(false) { - - static bool gstInitialized = false; - // FIXME: We should pass the arguments from the command line - if (!gstInitialized) { - gst_init(0, 0); - gstInitialized = true; - } - - // FIXME: The size shouldn't be fixed here, this is just a quick hack. - m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480); + do_gst_init(); } MediaPlayerPrivate::~MediaPlayerPrivate() { - if (m_surface) - cairo_surface_destroy(m_surface); + if (m_buffer) + gst_buffer_unref(m_buffer); + m_buffer = 0; if (m_playBin) { gst_element_set_state(m_playBin, GST_STATE_NULL); gst_object_unref(GST_OBJECT(m_playBin)); } + + if (m_videoSink) { + g_object_unref(m_videoSink); + m_videoSink = 0; + } } void MediaPlayerPrivate::load(const String& url) @@ -169,21 +232,26 @@ void MediaPlayerPrivate::load(const String& url) void MediaPlayerPrivate::play() { - LOG_VERBOSE(Media, "Play"); - // When end reached, rewind for Test video-seek-past-end-playing - if (m_isEndReached) - seek(0); - m_isEndReached = false; + GstState state; + GstState pending; - gst_element_set_state(m_playBin, GST_STATE_PLAYING); - m_startedPlaying = true; + gst_element_get_state(m_playBin, &state, &pending, 0); + if (state != GST_STATE_PLAYING && pending != GST_STATE_PLAYING) { + LOG_VERBOSE(Media, "Play"); + gst_element_set_state(m_playBin, GST_STATE_PLAYING); + } } void MediaPlayerPrivate::pause() { - LOG_VERBOSE(Media, "Pause"); - gst_element_set_state(m_playBin, GST_STATE_PAUSED); - m_startedPlaying = false; + GstState state; + GstState pending; + + gst_element_get_state(m_playBin, &state, &pending, 0); + if (state != GST_STATE_PAUSED && pending != GST_STATE_PAUSED) { + LOG_VERBOSE(Media, "Pause"); + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + } } float MediaPlayerPrivate::duration() const @@ -191,23 +259,20 @@ float MediaPlayerPrivate::duration() const if (!m_playBin) return 0.0; + if (m_errorOccured) + return 0.0; + GstFormat timeFormat = GST_FORMAT_TIME; gint64 timeLength = 0; - // FIXME: We try to get the duration, but we do not trust the - // return value of the query function only; the problem we are - // trying to work-around here is that pipelines in stream mode may - // not be able to figure out the duration, but still return true! - // See https://bugs.webkit.org/show_bug.cgi?id=24639. - if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeLength <= 0) { + if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE) { LOG_VERBOSE(Media, "Time duration query failed."); - m_isStreaming = true; return numeric_limits<float>::infinity(); } LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength)); - return (float) (timeLength / 1000000000.0); + return (float) ((guint64) timeLength / 1000000000.0); // FIXME: handle 3.14.9.5 properly } @@ -215,25 +280,15 @@ float MediaPlayerPrivate::currentTime() const { if (!m_playBin) return 0; - // Necessary as sometimes, gstreamer return 0:00 at the EOS - if (m_isEndReached) - return m_endTime; - float ret; + if (m_errorOccured) + return 0; - GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); - if (gst_element_query(m_playBin, query)) { - gint64 position; - gst_query_parse_position(query, 0, &position); - ret = (float) (position / 1000000000.0); - LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); - } else { - LOG_VERBOSE(Media, "Position query failed..."); - ret = 0.0; - } - gst_query_unref(query); + if (m_seeking) + return m_seekTime; + + return playbackPosition(m_playBin); - return ret; } void MediaPlayerPrivate::seek(float time) @@ -246,35 +301,25 @@ void MediaPlayerPrivate::seek(float time) if (m_isStreaming) return; + if (m_errorOccured) + return; + LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec)); - // FIXME: What happens when the seeked position is not available? - if (!gst_element_seek( m_playBin, m_rate, + if (!gst_element_seek(m_playBin, m_player->rate(), GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, sec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) LOG_VERBOSE(Media, "Seek to %f failed", time); + else { + m_seeking = true; + m_seekTime = sec; + } } void MediaPlayerPrivate::setEndTime(float time) { - if (!m_playBin) - return; - if (m_isStreaming) - return; - if (m_endTime != time) { - m_endTime = time; - GstClockTime start = (GstClockTime)(currentTime() * GST_SECOND); - GstClockTime end = (GstClockTime)(time * GST_SECOND); - LOG_VERBOSE(Media, "setEndTime: %" GST_TIME_FORMAT, GST_TIME_ARGS(end)); - // FIXME: What happens when the seeked position is not available? - if (!gst_element_seek(m_playBin, m_rate, - GST_FORMAT_TIME, - (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), - GST_SEEK_TYPE_SET, start, - GST_SEEK_TYPE_SET, end)) - LOG_VERBOSE(Media, "Seek to %f failed", time); - } + notImplemented(); } void MediaPlayerPrivate::startEndPointTimerIfNeeded() @@ -294,12 +339,12 @@ void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*) bool MediaPlayerPrivate::paused() const { - return !m_startedPlaying; + return m_paused; } bool MediaPlayerPrivate::seeking() const { - return false; + return m_seeking; } // Returns the size of the video @@ -308,13 +353,31 @@ IntSize MediaPlayerPrivate::naturalSize() const if (!hasVideo()) return IntSize(); - int x = 0, y = 0; + // TODO: handle possible clean aperture data. See + // https://bugzilla.gnome.org/show_bug.cgi?id=596571 + // TODO: handle possible transformation matrix. See + // https://bugzilla.gnome.org/show_bug.cgi?id=596326 + int width = 0, height = 0; if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) { - gst_video_get_size(GST_PAD(pad), &x, &y); + GstCaps* caps = GST_PAD_CAPS(pad); + gfloat pixelAspectRatio; + gint pixelAspectRatioNumerator, pixelAspectRatioDenominator; + + if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) + || !gst_video_format_parse_caps(caps, 0, &width, &height) + || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, + &pixelAspectRatioDenominator)) { + gst_object_unref(GST_OBJECT(pad)); + return IntSize(); + } + + pixelAspectRatio = (gfloat) pixelAspectRatioNumerator / (gfloat) pixelAspectRatioDenominator; + width *= pixelAspectRatio; + height /= pixelAspectRatio; gst_object_unref(GST_OBJECT(pad)); } - return IntSize(x, y); + return IntSize(width, height); } bool MediaPlayerPrivate::hasVideo() const @@ -325,43 +388,68 @@ bool MediaPlayerPrivate::hasVideo() const return currentVideo > -1; } -void MediaPlayerPrivate::setVolume(float volume) +bool MediaPlayerPrivate::hasAudio() const { - m_volume = volume; - LOG_VERBOSE(Media, "Volume to %f", volume); - setMuted(false); + gint currentAudio = -1; + if (m_playBin) + g_object_get(G_OBJECT(m_playBin), "current-audio", ¤tAudio, NULL); + return currentAudio > -1; } -void MediaPlayerPrivate::setMuted(bool b) +void MediaPlayerPrivate::setVolume(float volume) { if (!m_playBin) return; - if (b) { - g_object_get(G_OBJECT(m_playBin), "volume", &m_volume, NULL); - g_object_set(G_OBJECT(m_playBin), "volume", (double)0.0, NULL); - } else - g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL); - + g_object_set(G_OBJECT(m_playBin), "volume", static_cast<double>(volume), NULL); } void MediaPlayerPrivate::setRate(float rate) { - if (rate == 0.0) { - gst_element_set_state(m_playBin, GST_STATE_PAUSED); + GstState state; + GstState pending; + + gst_element_get_state(m_playBin, &state, &pending, 0); + if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED) + || (pending == GST_STATE_PAUSED)) return; - } + if (m_isStreaming) return; - m_rate = rate; + m_changingRate = true; + float currentPosition = playbackPosition(m_playBin) * GST_SECOND; + GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH); + gint64 start, end; + bool mute = false; + LOG_VERBOSE(Media, "Set Rate to %f", rate); - if (!gst_element_seek(m_playBin, rate, - GST_FORMAT_TIME, - (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), - GST_SEEK_TYPE_SET, (GstClockTime) (currentTime() * GST_SECOND), - GST_SEEK_TYPE_SET, (GstClockTime) (m_endTime * GST_SECOND))) - LOG_VERBOSE(Media, "Set Rate to %f failed", rate); + 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); + start = currentPosition; + end = GST_CLOCK_TIME_NONE; + } else { + start = 0; + mute = true; + + // If we are at beginning of media, start from the end to + // avoid immediate EOS. + if (currentPosition <= 0) + end = duration() * GST_SECOND; + else + end = currentPosition; + } + + LOG_VERBOSE(Media, "Need to mute audio: %d", (int) mute); + + if (!gst_element_seek(m_playBin, rate, GST_FORMAT_TIME, flags, + GST_SEEK_TYPE_SET, start, + GST_SEEK_TYPE_SET, end)) + LOG_VERBOSE(Media, "Set rate to %f failed", rate); + else + g_object_set(m_playBin, "mute", mute, NULL); } int MediaPlayerPrivate::dataRate() const @@ -380,16 +468,20 @@ MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const return m_readyState; } -float MediaPlayerPrivate::maxTimeBuffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { - notImplemented(); - LOG_VERBOSE(Media, "maxTimeBuffered"); - // rtsp streams are not buffered - return m_isStreaming ? 0 : maxTimeLoaded(); + RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + float loaded = maxTimeLoaded(); + if (!m_errorOccured && !m_isStreaming && loaded > 0) + timeRanges->add(0, loaded); + return timeRanges.release(); } float MediaPlayerPrivate::maxTimeSeekable() const { + if (m_errorOccured) + return 0.0; + // TODO LOG_VERBOSE(Media, "maxTimeSeekable"); if (m_isStreaming) @@ -400,6 +492,9 @@ float MediaPlayerPrivate::maxTimeSeekable() const float MediaPlayerPrivate::maxTimeLoaded() const { + if (m_errorOccured) + return 0.0; + // TODO LOG_VERBOSE(Media, "maxTimeLoaded"); notImplemented(); @@ -416,34 +511,39 @@ unsigned MediaPlayerPrivate::bytesLoaded() const float maxTime = maxTimeLoaded(); if (!dur) return 0;*/ + return 1;//totalBytes() * maxTime / dur; } bool MediaPlayerPrivate::totalBytesKnown() const { - notImplemented(); LOG_VERBOSE(Media, "totalBytesKnown"); return totalBytes() > 0; } unsigned MediaPlayerPrivate::totalBytes() const { - notImplemented(); LOG_VERBOSE(Media, "totalBytes"); - if (!m_playBin) + if (!m_source) return 0; - if (!m_source) + if (m_errorOccured) return 0; - // Do something with m_source to get the total bytes of the media + GstFormat fmt = GST_FORMAT_BYTES; + gint64 length = 0; + gst_element_query_duration(m_source, &fmt, &length); - return 100; + return length; } void MediaPlayerPrivate::cancelLoad() { - notImplemented(); + if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) + return; + + if (m_playBin) + gst_element_set_state(m_playBin, GST_STATE_NULL); } void MediaPlayerPrivate::updateStates() @@ -452,27 +552,47 @@ void MediaPlayerPrivate::updateStates() // the state of GStreamer, therefore, when in PAUSED state, // we are sure we can display the first frame and go to play + if (!m_playBin) + return; + + if (m_errorOccured) + return; + MediaPlayer::NetworkState oldNetworkState = m_networkState; MediaPlayer::ReadyState oldReadyState = m_readyState; GstState state; GstState pending; - if (!m_playBin) - return; - GstStateChangeReturn ret = gst_element_get_state(m_playBin, &state, &pending, 250 * GST_NSECOND); + bool shouldUpdateAfterSeek = false; switch (ret) { case GST_STATE_CHANGE_SUCCESS: LOG_VERBOSE(Media, "State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending)); - if (state == GST_STATE_READY) { + if (state == GST_STATE_READY) + m_readyState = MediaPlayer::HaveNothing; + else if (state == GST_STATE_PAUSED) m_readyState = MediaPlayer::HaveEnoughData; - } else if (state == GST_STATE_PAUSED) + + if (state == GST_STATE_PLAYING) { m_readyState = MediaPlayer::HaveEnoughData; + m_paused = false; + } else + m_paused = true; + + if (m_changingRate) { + m_player->rateChanged(); + m_changingRate = false; + } + + if (m_seeking) { + shouldUpdateAfterSeek = true; + m_seeking = false; + } m_networkState = MediaPlayer::Loaded; @@ -486,14 +606,20 @@ void MediaPlayerPrivate::updateStates() gst_element_state_get_name(pending)); // Change in progress return; - break; + case GST_STATE_CHANGE_FAILURE: + LOG_VERBOSE(Media, "Failure: State: %s, pending: %s", + gst_element_state_get_name(state), + gst_element_state_get_name(pending)); + // Change failed + return; case GST_STATE_CHANGE_NO_PREROLL: LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending)); - if (state == GST_STATE_READY) { - m_readyState = MediaPlayer::HaveFutureData; - } else if (state == GST_STATE_PAUSED) + + if (state == GST_STATE_READY) + m_readyState = MediaPlayer::HaveNothing; + else if (state == GST_STATE_PAUSED) m_readyState = MediaPlayer::HaveCurrentData; m_networkState = MediaPlayer::Loading; @@ -506,6 +632,9 @@ void MediaPlayerPrivate::updateStates() if (seeking()) m_readyState = MediaPlayer::HaveNothing; + if (shouldUpdateAfterSeek) + timeChanged(); + if (m_networkState != oldNetworkState) { LOG_VERBOSE(Media, "Network State Changed from %u to %u", oldNetworkState, m_networkState); @@ -523,11 +652,6 @@ void MediaPlayerPrivate::loadStateChanged() updateStates(); } -void MediaPlayerPrivate::rateChanged() -{ - updateStates(); -} - void MediaPlayerPrivate::sizeChanged() { notImplemented(); @@ -546,15 +670,14 @@ void MediaPlayerPrivate::volumeChanged() void MediaPlayerPrivate::didEnd() { - m_isEndReached = true; - pause(); timeChanged(); } -void MediaPlayerPrivate::loadingFailed() +void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error) { - if (m_networkState != MediaPlayer::NetworkError) { - m_networkState = MediaPlayer::NetworkError; + m_errorOccured = true; + if (m_networkState != error) { + m_networkState = error; m_player->networkStateChanged(); } if (m_readyState != MediaPlayer::HaveNothing) { @@ -570,7 +693,6 @@ void MediaPlayerPrivate::setSize(const IntSize& size) void MediaPlayerPrivate::setVisible(bool visible) { - m_visible = visible; } void MediaPlayerPrivate::repaint() @@ -583,62 +705,199 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) if (context->paintingDisabled()) return; - if (!m_visible) + if (!m_player->visible()) + return; + if (!m_buffer) return; - //TODO: m_size vs rect? + int width = 0, height = 0; + GstCaps *caps = gst_buffer_get_caps(m_buffer); + GstVideoFormat format; + + if (!gst_video_format_parse_caps(caps, &format, &width, &height)) { + gst_caps_unref(caps); + return; + } + + cairo_format_t cairoFormat; + if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) + cairoFormat = CAIRO_FORMAT_ARGB32; + else + cairoFormat = CAIRO_FORMAT_RGB24; + cairo_t* cr = context->platformContext(); + cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(m_buffer), + cairoFormat, + width, height, + 4 * width); cairo_save(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + + // translate and scale the context to correct size cairo_translate(cr, rect.x(), rect.y()); - cairo_rectangle(cr, 0, 0, rect.width(), rect.height()); - cairo_set_source_surface(cr, m_surface, 0, 0); + cairo_scale(cr, static_cast<double>(rect.width()) / width, static_cast<double>(rect.height()) / height); + + // And paint it. + cairo_set_source_surface(cr, src, 0, 0); + cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD); + cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); cairo_restore(cr); + + cairo_surface_destroy(src); + gst_caps_unref(caps); +} + +static HashSet<String> mimeTypeCache() +{ + + do_gst_init(); + + static HashSet<String> cache; + static bool typeListInitialized = false; + + if (!typeListInitialized) { + // Build a whitelist of mime-types known to be supported by + // GStreamer. + HashSet<String> handledApplicationSubtypes; + handledApplicationSubtypes.add(String("ogg")); + handledApplicationSubtypes.add(String("x-3gp")); + handledApplicationSubtypes.add(String("vnd.rn-realmedia")); + handledApplicationSubtypes.add(String("x-pn-realaudio")); + + GList* factories = gst_type_find_factory_get_list(); + for (GList* iterator = factories; iterator; iterator = iterator->next) { + GstTypeFindFactory* factory = GST_TYPE_FIND_FACTORY(iterator->data); + GstCaps* caps = gst_type_find_factory_get_caps(factory); + + if (!caps) + continue; + + for (guint structureIndex = 0; structureIndex < gst_caps_get_size(caps); structureIndex++) { + GstStructure* structure = gst_caps_get_structure(caps, structureIndex); + const gchar* name = gst_structure_get_name(structure); + bool cached = false; + + // These formats are supported by GStreamer, but not + // correctly advertised. + if (g_str_equal(name, "video/x-h264") + || g_str_equal(name, "audio/x-m4a")) { + cache.add(String("video/mp4")); + cache.add(String("audio/aac")); + cached = true; + } + + if (g_str_equal(name, "video/x-theora")) { + cache.add(String("video/ogg")); + cached = true; + } + + if (g_str_equal(name, "audio/x-vorbis")) { + cache.add(String("audio/ogg")); + cached = true; + } + + if (g_str_equal(name, "audio/x-wav")) { + cache.add(String("audio/wav")); + cached = true; + } + + if (g_str_equal(name, "audio/mpeg")) { + cache.add(String(name)); + cached = true; + + // This is what we are handling: + // mpegversion=(int)1, layer=(int)[ 1, 3 ] + gint mpegVersion = 0; + if (gst_structure_get_int(structure, "mpegversion", &mpegVersion) && (mpegVersion == 1)) { + const GValue* layer = gst_structure_get_value(structure, "layer"); + if (G_VALUE_TYPE(layer) == GST_TYPE_INT_RANGE) { + gint minLayer = gst_value_get_int_range_min(layer); + gint maxLayer = gst_value_get_int_range_max(layer); + if (minLayer <= 1 <= maxLayer) + cache.add(String("audio/mp1")); + if (minLayer <= 2 <= maxLayer) + cache.add(String("audio/mp2")); + if (minLayer <= 3 <= maxLayer) + cache.add(String("audio/mp3")); + } + } + } + + if (!cached) { + // GStreamer plugins can be capable of supporting + // types which WebKit supports by default. In that + // case, we should not consider these types + // supportable by GStreamer. Examples of what + // GStreamer can support but should not be added: + // text/plain, text/html, image/jpeg, + // application/xml + gchar** mimetype = g_strsplit(name, "/", 2); + if (g_str_equal(mimetype[0], "audio") + || g_str_equal(mimetype[0], "video") + || (g_str_equal(mimetype[0], "application") + && handledApplicationSubtypes.contains(String(mimetype[1])))) + cache.add(String(name)); + + g_strfreev(mimetype); + } + } + } + + gst_plugin_feature_list_free(factories); + typeListInitialized = true; + } + + return cache; } void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) { - // FIXME: query the engine to see what types are supported - notImplemented(); - types.add(String("video/x-theora+ogg")); + types = mimeTypeCache(); } MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) { - // FIXME: query the engine to see what types are supported - notImplemented(); - return type == "video/x-theora+ogg" ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported; + if (type.isNull() || type.isEmpty()) + return MediaPlayer::IsNotSupported; + + // spec says we should not return "probably" if the codecs string is empty + if (mimeTypeCache().contains(type)) + return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported; + return MediaPlayer::IsNotSupported; +} + +bool MediaPlayerPrivate::hasSingleSecurityOrigin() const +{ + return true; +} + +bool MediaPlayerPrivate::supportsFullscreen() const +{ + return true; } void MediaPlayerPrivate::createGSTPlayBin(String url) { ASSERT(!m_playBin); - m_playBin = gst_element_factory_make("playbin", "play"); + m_playBin = gst_element_factory_make("playbin2", "play"); GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin)); gst_bus_add_signal_watch(bus); - g_signal_connect(bus, "message::error", G_CALLBACK(mediaPlayerPrivateErrorCallback), this); - g_signal_connect(bus, "message::eos", G_CALLBACK(mediaPlayerPrivateEOSCallback), this); - g_signal_connect(bus, "message::state-changed", G_CALLBACK(mediaPlayerPrivateStateCallback), this); - g_signal_connect(bus, "message::buffering", G_CALLBACK(mediaPlayerPrivateBufferingCallback), this); + g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this); gst_object_unref(bus); - g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL); + g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), + "volume", static_cast<double>(m_player->volume()), NULL); - GstElement* audioSink = gst_element_factory_make("gconfaudiosink", 0); - m_videoSink = webkit_video_sink_new(m_surface); + m_videoSink = webkit_video_sink_new(); - g_object_set(m_playBin, "audio-sink", audioSink, NULL); + g_object_ref_sink(m_videoSink); g_object_set(m_playBin, "video-sink", m_videoSink, NULL); g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this); - - setVolume(m_volume); } } #endif - diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h index 8842f84..6ab8edb 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h @@ -29,9 +29,12 @@ #include <cairo.h> #include <glib.h> +#include <gst/gst.h> -typedef struct _GstElement GstElement; +typedef struct _WebKitVideoSink WebKitVideoSink; +typedef struct _GstBuffer GstBuffer; typedef struct _GstMessage GstMessage; +typedef struct _GstElement GstElement; typedef struct _GstBus GstBus; namespace WebCore { @@ -41,14 +44,11 @@ namespace WebCore { class IntRect; class String; - gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data); - gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data); - gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data); + gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); class MediaPlayerPrivate : public MediaPlayerPrivateInterface { - friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data); - friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data); - friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data); + friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); + friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate); public: static void registerMediaEngine(MediaEngineRegistrar); @@ -56,6 +56,7 @@ namespace WebCore { IntSize naturalSize() const; bool hasVideo() const; + bool hasAudio() const; void load(const String &url); void cancelLoad(); @@ -73,14 +74,13 @@ namespace WebCore { void setRate(float); void setVolume(float); - void setMuted(bool); int dataRate() const; MediaPlayer::NetworkState networkState() const; MediaPlayer::ReadyState readyState() const; - float maxTimeBuffered() const; + PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; bool totalBytesKnown() const; @@ -90,23 +90,26 @@ namespace WebCore { void setSize(const IntSize&); void loadStateChanged(); - void rateChanged(); void sizeChanged(); void timeChanged(); void volumeChanged(); void didEnd(); - void loadingFailed(); + void loadingFailed(MediaPlayer::NetworkState); void repaint(); void paint(GraphicsContext*, const IntRect&); + bool hasSingleSecurityOrigin() const; + + bool supportsFullscreen() const; + private: MediaPlayerPrivate(MediaPlayer*); static MediaPlayerPrivateInterface* create(MediaPlayer* player); static void getSupportedTypes(HashSet<String>&); static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); - static bool isAvailable() { return true; } + static bool isAvailable(); void updateStates(); void cancelSeek(); @@ -121,17 +124,20 @@ namespace WebCore { GstElement* m_playBin; GstElement* m_videoSink; GstElement* m_source; - float m_rate; + GstClockTime m_seekTime; + bool m_changingRate; float m_endTime; bool m_isEndReached; - double m_volume; MediaPlayer::NetworkState m_networkState; MediaPlayer::ReadyState m_readyState; bool m_startedPlaying; mutable bool m_isStreaming; IntSize m_size; - bool m_visible; - cairo_surface_t* m_surface; + GstBuffer* m_buffer; + + bool m_paused; + bool m_seeking; + bool m_errorOccured; }; } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp index a77c1cf..df25393 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -39,8 +39,6 @@ #include "FontDescription.h" #include "GlyphBuffer.h" #include <cairo.h> -#include <unicode/uchar.h> -#include <unicode/unorm.h> #include <wtf/MathExtras.h> namespace WebCore { @@ -50,9 +48,9 @@ void SimpleFontData::platformInit() cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); - m_ascent = static_cast<int>(font_extents.ascent); - m_descent = static_cast<int>(font_extents.descent); - m_lineSpacing = static_cast<int>(font_extents.height); + m_ascent = static_cast<int>(lroundf(font_extents.ascent)); + m_descent = static_cast<int>(lroundf(font_extents.descent)); + m_lineSpacing = static_cast<int>(lroundf(font_extents.height)); // There seems to be some rounding error in cairo (or in how we // use cairo) with some fonts, like DejaVu Sans Mono, which makes // cairo report a height smaller than ascent + descent, which is @@ -63,7 +61,7 @@ void SimpleFontData::platformInit() cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); m_xHeight = text_extents.height; cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); - m_spaceWidth = static_cast<int>(text_extents.x_advance); + m_spaceWidth = static_cast<float>(text_extents.x_advance); m_lineGap = m_lineSpacing - m_ascent - m_descent; m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; } @@ -130,10 +128,4 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const return w; } -void SimpleFontData::setFont(cairo_t* cr) const -{ - ASSERT(cr); - m_platformData.setFont(cr); -} - } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp index e57d9e6..975143e 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp @@ -49,9 +49,9 @@ void SimpleFontData::platformInit() cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); - m_ascent = static_cast<int>(font_extents.ascent); - m_descent = static_cast<int>(font_extents.descent); - m_lineSpacing = static_cast<int>(font_extents.height); + m_ascent = static_cast<int>(lroundf(font_extents.ascent)); + m_descent = static_cast<int>(lroundf(font_extents.descent)); + m_lineSpacing = static_cast<int>(lroundf(font_extents.height)); // There seems to be some rounding error in cairo (or in how we // use cairo) with some fonts, like DejaVu Sans Mono, which makes // cairo report a height smaller than ascent + descent, which is @@ -62,7 +62,7 @@ void SimpleFontData::platformInit() cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); m_xHeight = text_extents.height; cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); - m_spaceWidth = static_cast<int>(text_extents.x_advance); + m_spaceWidth = static_cast<float>(text_extents.x_advance); m_lineGap = m_lineSpacing - m_ascent - m_descent; m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; } @@ -133,10 +133,4 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const return w; } -void SimpleFontData::setFont(cairo_t* cr) const -{ - ASSERT(cr); - m_platformData.setFont(cr); -} - } diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp index f049998..5e0f8e2 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -21,8 +21,9 @@ * SECTION:webkit-video-sink * @short_description: GStreamer video sink * - * #WebKitVideoSink is a GStreamer sink element that sends - * data to a #cairo_surface_t. + * #WebKitVideoSink is a GStreamer sink element that triggers + * repaints in the WebKit GStreamer media player for the + * current video buffer. */ #include "config.h" @@ -33,40 +34,44 @@ #include <gst/video/video.h> static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink", - GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS(GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx)); + GST_PAD_SINK, GST_PAD_ALWAYS, +// CAIRO_FORMAT_RGB24 used to render the video buffers is little/big endian dependant. +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + GST_STATIC_CAPS(GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_BGRA) +#else + GST_STATIC_CAPS(GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_ARGB) +#endif +); GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug); #define GST_CAT_DEFAULT webkit_video_sink_debug -static GstElementDetails webkit_video_sink_details = - GST_ELEMENT_DETAILS((gchar*) "WebKit video sink", - (gchar*) "Sink/Video", - (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface", - (gchar*) "Alp Toker <alp@atoker.com>"); - enum { REPAINT_REQUESTED, LAST_SIGNAL }; enum { - PROP_0, - PROP_SURFACE + PROP_0 }; static guint webkit_video_sink_signals[LAST_SIGNAL] = { 0, }; struct _WebKitVideoSinkPrivate { - cairo_surface_t* surface; - GAsyncQueue* async_queue; - gboolean rgb_ordering; - int width; - int height; - int fps_n; - int fps_d; - int par_n; - int par_d; + GstBuffer* buffer; + guint timeout_id; + GMutex* buffer_mutex; + GCond* data_cond; + + // If this is TRUE all processing should finish ASAP + // This is necessary because there could be a race between + // unlock() and render(), where unlock() wins, signals the + // GCond, then render() tries to render a frame although + // everything else isn't running anymore. This will lead + // to deadlocks because render() holds the stream lock. + // + // Protected by the buffer mutex + gboolean unlocked; }; #define _do_init(bla) \ @@ -77,8 +82,8 @@ struct _WebKitVideoSinkPrivate { GST_BOILERPLATE_FULL(WebKitVideoSink, webkit_video_sink, - GstBaseSink, - GST_TYPE_BASE_SINK, + GstVideoSink, + GST_TYPE_VIDEO_SINK, _do_init); static void @@ -87,7 +92,9 @@ webkit_video_sink_base_init(gpointer g_class) GstElementClass* element_class = GST_ELEMENT_CLASS(g_class); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinktemplate)); - gst_element_class_set_details(element_class, &webkit_video_sink_details); + gst_element_class_set_details_simple(element_class, "WebKit video sink", + "Sink/Video", "Sends video data from a GStreamer pipeline to a Cairo surface", + "Alp Toker <alp@atoker.com>"); } static void @@ -96,38 +103,32 @@ webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass) WebKitVideoSinkPrivate* priv; sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate); - priv->async_queue = g_async_queue_new(); + priv->data_cond = g_cond_new(); + priv->buffer_mutex = g_mutex_new(); } static gboolean -webkit_video_sink_idle_func(gpointer data) +webkit_video_sink_timeout_func(gpointer data) { - WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(data); + WebKitVideoSink* sink = reinterpret_cast<WebKitVideoSink*>(data); WebKitVideoSinkPrivate* priv = sink->priv; GstBuffer* buffer; - if (!priv->async_queue) - return FALSE; + g_mutex_lock(priv->buffer_mutex); + buffer = priv->buffer; + priv->buffer = 0; + priv->timeout_id = 0; - buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue); - if (!buffer || G_UNLIKELY(!GST_IS_BUFFER(buffer))) + if (!buffer || priv->unlocked || G_UNLIKELY(!GST_IS_BUFFER(buffer))) { + g_cond_signal(priv->data_cond); + g_mutex_unlock(priv->buffer_mutex); return FALSE; + } - // TODO: consider priv->rgb_ordering? - cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), CAIRO_FORMAT_RGB24, priv->width, priv->height, (4 * priv->width + 3) & ~3); - - // TODO: We copy the data twice right now. This could be easily improved. - cairo_t* cr = cairo_create(priv->surface); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_surface(cr, src, 0, 0); - cairo_surface_destroy(src); - cairo_rectangle(cr, 0, 0, priv->width, priv->height); - cairo_fill(cr); - cairo_destroy(cr); - + g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0, buffer); gst_buffer_unref(buffer); - - g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0); + g_cond_signal(priv->data_cond); + g_mutex_unlock(priv->buffer_mutex); return FALSE; } @@ -138,60 +139,89 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); WebKitVideoSinkPrivate* priv = sink->priv; - g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer)); - g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, 0); - - return GST_FLOW_OK; -} - -static gboolean -webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps) -{ - WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); - WebKitVideoSinkPrivate* priv = sink->priv; - GstStructure* structure; - gboolean ret; - const GValue* fps; - const GValue* par; - gint width, height; - int red_mask; - - GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps); + g_mutex_lock(priv->buffer_mutex); - if (gst_caps_is_empty(intersection)) - return FALSE; - - gst_caps_unref(intersection); - - structure = gst_caps_get_structure(caps, 0); - - ret = gst_structure_get_int(structure, "width", &width); - ret &= gst_structure_get_int(structure, "height", &height); - fps = gst_structure_get_value(structure, "framerate"); - ret &= (fps != 0); - - par = gst_structure_get_value(structure, "pixel-aspect-ratio"); + if (priv->unlocked) { + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_OK; + } - if (!ret) - return FALSE; + priv->buffer = gst_buffer_ref(buffer); - priv->width = width; - priv->height = height; + // For the unlikely case where the buffer has no caps, the caps + // are implicitely the caps of the pad. This shouldn't happen. + if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) { + buffer = priv->buffer = gst_buffer_make_metadata_writable(priv->buffer); + gst_buffer_set_caps(priv->buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(bsink))); + } - /* We dont yet use fps or pixel aspect into but handy to have */ - priv->fps_n = gst_value_get_fraction_numerator(fps); - priv->fps_d = gst_value_get_fraction_denominator(fps); + GstCaps *caps = GST_BUFFER_CAPS(buffer); + GstVideoFormat format; + int width, height; + if (G_UNLIKELY(!gst_video_format_parse_caps(caps, &format, &width, &height))) { + gst_buffer_unref(buffer); + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_ERROR; + } - if (par) { - priv->par_n = gst_value_get_fraction_numerator(par); - priv->par_d = gst_value_get_fraction_denominator(par); - } else - priv->par_n = priv->par_d = 1; + // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't. + // Here we convert to Cairo's ARGB. + if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) { + // Because GstBaseSink::render() only owns the buffer reference in the + // method scope we can't use gst_buffer_make_writable() here. Also + // The buffer content should not be changed here because the same buffer + // could be passed multiple times to this method (in theory) + GstBuffer *newBuffer = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buffer)); + + // Check if allocation failed + if (G_UNLIKELY(!newBuffer)) { + gst_buffer_unref(buffer); + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_ERROR; + } + + gst_buffer_copy_metadata(newBuffer, buffer, (GstBufferCopyFlags) GST_BUFFER_COPY_ALL); + + // We don't use Color::premultipliedARGBFromColor() here because + // one function call per video pixel is just too expensive: + // For 720p/PAL for example this means 1280*720*25=23040000 + // function calls per second! + unsigned short alpha; + const guint8 *source = GST_BUFFER_DATA(buffer); + guint8 *destination = GST_BUFFER_DATA(newBuffer); + + for (int x = 0; x < height; x++) { + for (int y = 0; y < width; y++) { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + alpha = source[3]; + destination[0] = (source[0] * alpha + 128) / 255; + destination[1] = (source[1] * alpha + 128) / 255; + destination[2] = (source[2] * alpha + 128) / 255; + destination[3] = alpha; +#else + alpha = source[0]; + destination[0] = alpha; + destination[1] = (source[1] * alpha + 128) / 255; + destination[2] = (source[2] * alpha + 128) / 255; + destination[3] = (source[3] * alpha + 128) / 255; +#endif + source += 4; + destination += 4; + } + } + gst_buffer_unref(buffer); + buffer = priv->buffer = newBuffer; + } - gst_structure_get_int(structure, "red_mask", &red_mask); - priv->rgb_ordering = (red_mask == static_cast<int>(0xff000000)); + // Use HIGH_IDLE+20 priority, like Gtk+ for redrawing operations. + priv->timeout_id = g_timeout_add_full(G_PRIORITY_HIGH_IDLE + 20, 0, + webkit_video_sink_timeout_func, + gst_object_ref(sink), + (GDestroyNotify)gst_object_unref); - return TRUE; + g_cond_wait(priv->data_cond, priv->buffer_mutex); + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_OK; } static void @@ -200,56 +230,58 @@ webkit_video_sink_dispose(GObject* object) WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); WebKitVideoSinkPrivate* priv = sink->priv; - if (priv->surface) { - cairo_surface_destroy(priv->surface); - priv->surface = 0; + if (priv->data_cond) { + g_cond_free(priv->data_cond); + priv->data_cond = 0; } - if (priv->async_queue) { - g_async_queue_unref(priv->async_queue); - priv->async_queue = 0; + if (priv->buffer_mutex) { + g_mutex_free(priv->buffer_mutex); + priv->buffer_mutex = 0; } G_OBJECT_CLASS(parent_class)->dispose(object); } static void -webkit_video_sink_finalize(GObject* object) +unlock_buffer_mutex(WebKitVideoSinkPrivate* priv) { - G_OBJECT_CLASS(parent_class)->finalize(object); + g_mutex_lock(priv->buffer_mutex); + + if (priv->buffer) { + gst_buffer_unref(priv->buffer); + priv->buffer = 0; + } + + priv->unlocked = TRUE; + + g_cond_signal(priv->data_cond); + g_mutex_unlock(priv->buffer_mutex); } -static void -webkit_video_sink_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +static gboolean +webkit_video_sink_unlock(GstBaseSink* object) { WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); - WebKitVideoSinkPrivate* priv = sink->priv; - switch (prop_id) { - case PROP_SURFACE: - if (priv->surface) - cairo_surface_destroy(priv->surface); - priv->surface = cairo_surface_reference((cairo_surface_t*)g_value_get_pointer(value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } + unlock_buffer_mutex(sink->priv); + + return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock, + (object), TRUE); } -static void -webkit_video_sink_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) +static gboolean +webkit_video_sink_unlock_stop(GstBaseSink* object) { WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + WebKitVideoSinkPrivate* priv = sink->priv; - switch (prop_id) { - case PROP_SURFACE: - g_value_set_pointer(value, sink->priv->surface); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } + g_mutex_lock(priv->buffer_mutex); + priv->unlocked = FALSE; + g_mutex_unlock(priv->buffer_mutex); + + return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop, + (object), TRUE); } static gboolean @@ -257,18 +289,46 @@ webkit_video_sink_stop(GstBaseSink* base_sink) { WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv; - g_async_queue_lock(priv->async_queue); - - /* Remove all remaining objects from the queue */ - while (GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue)) - gst_buffer_unref(buffer); + unlock_buffer_mutex(priv); + return TRUE; +} - g_async_queue_unlock(priv->async_queue); +static gboolean +webkit_video_sink_start(GstBaseSink* base_sink) +{ + WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv; + g_mutex_lock(priv->buffer_mutex); + priv->unlocked = FALSE; + g_mutex_unlock(priv->buffer_mutex); return TRUE; } static void +marshal_VOID__MINIOBJECT(GClosure * closure, GValue * return_value, + guint n_param_values, const GValue * param_values, + gpointer invocation_hint, gpointer marshal_data) +{ + typedef void (*marshalfunc_VOID__MINIOBJECT) (gpointer obj, gpointer arg1, gpointer data2); + marshalfunc_VOID__MINIOBJECT callback; + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + + g_return_if_fail(n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA(closure)) { + data1 = closure->data; + data2 = g_value_peek_pointer(param_values + 0); + } else { + data1 = g_value_peek_pointer(param_values + 0); + data2 = closure->data; + } + callback = (marshalfunc_VOID__MINIOBJECT) (marshal_data ? marshal_data : cc->callback); + + callback(data1, gst_value_get_mini_object(param_values + 1), data2); +} + +static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass) { GObjectClass* gobject_class = G_OBJECT_CLASS(klass); @@ -276,16 +336,14 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass) g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate)); - gobject_class->set_property = webkit_video_sink_set_property; - gobject_class->get_property = webkit_video_sink_get_property; - gobject_class->dispose = webkit_video_sink_dispose; - gobject_class->finalize = webkit_video_sink_finalize; + gstbase_sink_class->unlock = webkit_video_sink_unlock; + gstbase_sink_class->unlock_stop = webkit_video_sink_unlock_stop; gstbase_sink_class->render = webkit_video_sink_render; gstbase_sink_class->preroll = webkit_video_sink_render; gstbase_sink_class->stop = webkit_video_sink_stop; - gstbase_sink_class->set_caps = webkit_video_sink_set_caps; + gstbase_sink_class->start = webkit_video_sink_start; webkit_video_sink_signals[REPAINT_REQUESTED] = g_signal_new("repaint-requested", G_TYPE_FROM_CLASS(klass), @@ -293,37 +351,20 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass) 0, 0, 0, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_object_class_install_property( - gobject_class, PROP_SURFACE, - g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*", - (GParamFlags)(G_PARAM_READWRITE))); + marshal_VOID__MINIOBJECT, + G_TYPE_NONE, 1, GST_TYPE_BUFFER); } /** * webkit_video_sink_new: - * @surface: a #cairo_surface_t * - * Creates a new GStreamer video sink which uses @surface as the target - * for sinking a video stream from GStreamer. + * Creates a new GStreamer video sink. * * Return value: a #GstElement for the newly created video sink */ GstElement* -webkit_video_sink_new(cairo_surface_t* surface) +webkit_video_sink_new(void) { - return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, 0); + return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, 0); } -void -webkit_video_sink_set_surface(WebKitVideoSink* sink, cairo_surface_t* surface) -{ - WebKitVideoSinkPrivate* priv; - - sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate); - if (priv->surface) - cairo_surface_destroy(priv->surface); - priv->surface = cairo_surface_reference(surface); -} diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h index be2c94c..7ea7d91 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h @@ -22,7 +22,7 @@ #include <cairo.h> #include <glib-object.h> -#include <gst/base/gstbasesink.h> +#include <gst/video/gstvideosink.h> G_BEGIN_DECLS @@ -54,13 +54,13 @@ typedef struct _WebKitVideoSinkPrivate WebKitVideoSinkPrivate; struct _WebKitVideoSink { /*< private >*/ - GstBaseSink parent; + GstVideoSink parent; WebKitVideoSinkPrivate *priv; }; struct _WebKitVideoSinkClass { /*< private >*/ - GstBaseSinkClass parent_class; + GstVideoSinkClass parent_class; /* Future padding */ void (* _webkit_reserved1)(void); @@ -72,9 +72,7 @@ struct _WebKitVideoSinkClass { }; GType webkit_video_sink_get_type(void) G_GNUC_CONST; -GstElement *webkit_video_sink_new(cairo_surface_t *surface); - -void webkit_video_sink_set_surface(WebKitVideoSink *sink, cairo_surface_t *surface); +GstElement *webkit_video_sink_new(void); G_END_DECLS diff --git a/WebCore/platform/graphics/haiku/ColorHaiku.cpp b/WebCore/platform/graphics/haiku/ColorHaiku.cpp new file mode 100644 index 0000000..a9ac186 --- /dev/null +++ b/WebCore/platform/graphics/haiku/ColorHaiku.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Color.h" + +#include <InterfaceDefs.h> + + +namespace WebCore { + +Color::Color(const rgb_color& color) + : m_color(makeRGBA(color.red, color.green, color.blue, color.alpha)) + , m_valid(true) +{ +} + +Color::operator rgb_color() const +{ + return make_color(red(), green(), blue(), alpha()); +} + + +Color focusRingColor() +{ + return Color(keyboard_navigation_color()); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp b/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp new file mode 100644 index 0000000..0f50898 --- /dev/null +++ b/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * 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 "FloatPoint.h" + +#include <Point.h> + + +namespace WebCore { + +FloatPoint::FloatPoint(const BPoint& point) + : m_x(point.x) + , m_y(point.y) +{ +} + +FloatPoint::operator BPoint() const +{ + return BPoint(m_x, m_y); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp b/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp new file mode 100644 index 0000000..67af3af --- /dev/null +++ b/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * 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 "FloatRect.h" + +#include <Rect.h> + + +namespace WebCore { + +FloatRect::FloatRect(const BRect& rect) + : m_location(rect.LeftTop()) + , m_size(rect.Width(), rect.Height()) +{ +} + +FloatRect::operator BRect() const +{ + return BRect(BPoint(x(), y()), BSize(width(), height())); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp b/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp new file mode 100644 index 0000000..b99bf42 --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontCache.h" + +#include "Font.h" +#include "FontData.h" +#include "FontPlatformData.h" +#include "NotImplemented.h" +#include <String.h> + + +namespace WebCore { + +void FontCache::platformInit() +{ +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + FontPlatformData data(font.fontDescription(), font.family().family()); + return getCachedFontData(&data); +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + notImplemented(); + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) +{ + // FIXME: Would be even better to somehow get the user's default font here. + // For now we'll pick the default that the user would get without changing any prefs. + static AtomicString defaultString("DejaVu Serif"); + return getCachedFontPlatformData(fontDescription, defaultString); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + return new FontPlatformData(fontDescription, family); +} + +void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp b/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp new file mode 100644 index 0000000..6008bb1 --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#include "SharedBuffer.h" +#include "FontPlatformData.h" + + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode) +{ + return FontPlatformData(size, bold, italic); +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + // FIXME: We need support in Haiku to read fonts from memory to implement this. + return 0; +} + +} diff --git a/WebCore/platform/graphics/haiku/FontCustomPlatformData.h b/WebCore/platform/graphics/haiku/FontCustomPlatformData.h new file mode 100644 index 0000000..c5a814e --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontCustomPlatformData.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include "FontRenderingMode.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + + class FontPlatformData; + class SharedBuffer; + + struct FontCustomPlatformData : Noncopyable { + public: + FontCustomPlatformData() { } + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode); + }; + + FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); + +} + +#endif diff --git a/WebCore/platform/graphics/haiku/FontHaiku.cpp b/WebCore/platform/graphics/haiku/FontHaiku.cpp new file mode 100644 index 0000000..48744d9 --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontHaiku.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "FontData.h" +#include "FontDescription.h" +#include "FontSelector.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include <Font.h> +#include <String.h> +#include <View.h> + + +// FIXME: Temp routine to convert unicode character to UTF8. +int charUnicodeToUTF8HACK(unsigned short glyph, char* out) +{ + int i = 0; + + if (glyph < 0x0080) + out[i++] = static_cast<char>(glyph); + else if (glyph < 0x0800) { // 2 bytes + out[i++] = 0xc0 | (glyph >> 6); + out[i++] = 0x80 | (glyph & 0x3F); + } else if (glyph > 0x0800) { // 3 bytes + out[i++] = 0xe0 | (glyph >> 12); + out[i++] = 0x80 | ((glyph >> 6) & 0x3F); + out[i++] = 0x80 | (glyph & 0x3F); + } + + out[i] = '\0'; + return i; +} + +namespace WebCore { + +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + +void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const +{ + Color color = graphicsContext->fillColor(); + BView* view = graphicsContext->platformContext(); + BFont* m_font = font->platformData().font(); + + graphicsContext->setCompositeOperation(CompositeSourceOver); + view->SetHighColor(color); + view->SetFont(m_font); + + GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); + float offset = point.x(); + for (int i = 0; i < numGlyphs; i++) { + char out[4]; + charUnicodeToUTF8HACK(glyphs[i], out); + + view->DrawString(out, sizeof(out), BPoint(offset, point.y())); + offset += glyphBuffer.advanceAt(from + i); + } +} + +void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, + int from, int to) const +{ + notImplemented(); +} + + +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +{ + notImplemented(); + return 0; +} + +FloatRect Font::selectionRectForComplexText(const TextRun&, const IntPoint&, int, int, int) const +{ + notImplemented(); + return FloatRect(); +} + +int Font::offsetForPositionForComplexText(const TextRun&, int, bool) const +{ + notImplemented(); + return 0; +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FontPlatformData.h b/WebCore/platform/graphics/haiku/FontPlatformData.h new file mode 100644 index 0000000..9feab8e --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontPlatformData.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef FontPlatformData_H +#define FontPlatformData_H + +#include "FontDescription.h" +#include "GlyphBuffer.h" +#include <interface/Font.h> + +namespace WebCore { + + class FontPlatformData { + public: + FontPlatformData(WTF::HashTableDeletedValueType) + : m_font(hashTableDeletedFontValue()) + { } + + FontPlatformData() + : m_font(0) + { } + + FontPlatformData(const FontDescription&, const AtomicString& family); + FontPlatformData(float size, bool bold, bool oblique); + FontPlatformData(const FontPlatformData&); + + ~FontPlatformData(); + + BFont* font() const { return m_font; } + + bool isFixedPitch(); + float size() const { return m_size; } + bool bold() const { return m_bold; } + bool oblique() const { return m_oblique; } + + unsigned hash() const; + bool isHashTableDeletedValue() const; + + bool operator==(const FontPlatformData&) const; + +#ifndef NDEBUG + String description() const; +#endif + + BFont* m_font; + float m_size; + bool m_bold; + bool m_oblique; + + private: + static BFont* hashTableDeletedFontValue() { return reinterpret_cast<BFont*>(-1); } + }; + +} // namespace WebCore + +#endif + diff --git a/WebCore/platform/graphics/haiku/GradientHaiku.cpp b/WebCore/platform/graphics/haiku/GradientHaiku.cpp new file mode 100644 index 0000000..469a17f --- /dev/null +++ b/WebCore/platform/graphics/haiku/GradientHaiku.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> All rights reserved. + * Copyright (C) 2009 Maxime Simon <simon.maxime@theolliviers.com> + * + * 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 "Gradient.h" + +#include "CSSParser.h" +#include "NotImplemented.h" + + +namespace WebCore { + +void Gradient::platformDestroy() +{ + notImplemented(); +} + +PlatformGradient Gradient::platformGradient() +{ + notImplemented(); + return 0; +} + +void Gradient::fill(GraphicsContext*, const FloatRect&) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp new file mode 100644 index 0000000..4728d56 --- /dev/null +++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -0,0 +1,541 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext.h" + +#include "CString.h" +#include "Color.h" +#include "Font.h" +#include "FontData.h" +#include "NotImplemented.h" +#include "Path.h" +#include "Pen.h" +#include "TransformationMatrix.h" +#include <GraphicsDefs.h> +#include <Region.h> +#include <View.h> +#include <Window.h> +#include <stdio.h> + + +namespace WebCore { + +class GraphicsContextPlatformPrivate { +public: + GraphicsContextPlatformPrivate(BView* view); + ~GraphicsContextPlatformPrivate(); + + BView* m_view; +}; + +GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(BView* view) + : m_view(view) +{ +} + +GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() +{ +} + +GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate(context)) +{ + setPaintingDisabled(!context); +} + +GraphicsContext::~GraphicsContext() +{ + destroyGraphicsContextPrivate(m_common); + delete m_data; +} + +PlatformGraphicsContext* GraphicsContext::platformContext() const +{ + return m_data->m_view; +} + +void GraphicsContext::savePlatformState() +{ + m_data->m_view->PushState(); +} + +void GraphicsContext::restorePlatformState() +{ + m_data->m_view->PopState(); +} + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->m_view->FillRect(rect); + if (strokeStyle() != NoStroke) + m_data->m_view->StrokeRect(rect, getHaikuStrokeStyle()); +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + if (strokeStyle() == NoStroke) + return; + + m_data->m_view->StrokeLine(point1, point2, getHaikuStrokeStyle()); +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->m_view->FillEllipse(rect); + if (strokeStyle() != NoStroke) + m_data->m_view->StrokeEllipse(rect, getHaikuStrokeStyle()); +} + +void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) +{ + if (paintingDisabled()) + return; + + m_data->m_view->StrokeArc(rect, startAngle, angleSpan, getHaikuStrokeStyle()); +} + +void GraphicsContext::strokePath() +{ + notImplemented(); +} + +void GraphicsContext::drawConvexPolygon(size_t pointsLength, const FloatPoint* points, bool shouldAntialias) +{ + if (paintingDisabled()) + return; + + BPoint bPoints[pointsLength]; + for (size_t i = 0; i < pointsLength; i++) + bPoints[i] = points[i]; + + m_data->m_view->FillPolygon(bPoints, pointsLength); + if (strokeStyle() != NoStroke) + // Stroke with low color + m_data->m_view->StrokePolygon(bPoints, pointsLength, true, getHaikuStrokeStyle()); +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled()) + return; + + rgb_color oldColor = m_data->m_view->HighColor(); + m_data->m_view->SetHighColor(color); + m_data->m_view->FillRect(rect); + m_data->m_view->SetHighColor(oldColor); +} + +void GraphicsContext::fillRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; +} + +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled() || !color.alpha()) + return; + + notImplemented(); + // FIXME: A simple implementation could just use FillRoundRect if all + // the sizes are the same, or even if they are not. Otherwise several + // FillRect and FillArc calls are needed. +} + +void GraphicsContext::fillPath() +{ + notImplemented(); +} + +void GraphicsContext::beginPath() +{ + notImplemented(); +} + +void GraphicsContext::addPath(const Path& path) +{ + notImplemented(); +} + +void GraphicsContext::clip(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + BRegion region(rect); + m_data->m_view->ConstrainClippingRegion(®ion); +} + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + + // FIXME: maybe we should implement this with BShape? + + if (rects.size() > 1) { + BRegion region; + for (int i = 0; i < rectCount; ++i) + region.Include(BRect(rects[i])); + + m_data->m_view->SetHighColor(color); + m_data->m_view->StrokeRect(region.Frame(), B_MIXED_COLORS); + } +} + +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +{ + if (paintingDisabled()) + return; + + IntPoint endPoint = origin + IntSize(width, 0); + drawLine(origin, endPoint); +} + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +{ + notImplemented(); + return rect; +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clearRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::strokeRect(const FloatRect& rect, float width) +{ + if (paintingDisabled()) + return; + + float oldSize = m_data->m_view->PenSize(); + m_data->m_view->SetPenSize(width); + m_data->m_view->StrokeRect(rect, getHaikuStrokeStyle()); + m_data->m_view->SetPenSize(oldSize); +} + +void GraphicsContext::setLineCap(LineCap lineCap) +{ + if (paintingDisabled()) + return; + + cap_mode mode = B_BUTT_CAP; + switch (lineCap) { + case RoundCap: + mode = B_ROUND_CAP; + break; + case SquareCap: + mode = B_SQUARE_CAP; + break; + case ButtCap: + default: + break; + } + + m_data->m_view->SetLineMode(mode, m_data->m_view->LineJoinMode(), m_data->m_view->LineMiterLimit()); +} + +void GraphicsContext::setLineJoin(LineJoin lineJoin) +{ + if (paintingDisabled()) + return; + + join_mode mode = B_MITER_JOIN; + switch (lineJoin) { + case RoundJoin: + mode = B_ROUND_JOIN; + break; + case BevelJoin: + mode = B_BEVEL_JOIN; + break; + case MiterJoin: + default: + break; + } + + m_data->m_view->SetLineMode(m_data->m_view->LineCapMode(), mode, m_data->m_view->LineMiterLimit()); +} + +void GraphicsContext::setMiterLimit(float limit) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetLineMode(m_data->m_view->LineCapMode(), m_data->m_view->LineJoinMode(), limit); +} + +void GraphicsContext::setAlpha(float opacity) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + if (paintingDisabled()) + return; + + drawing_mode mode = B_OP_COPY; + switch (op) { + case CompositeClear: + case CompositeCopy: + // Use the default above + break; + case CompositeSourceOver: + mode = B_OP_OVER; + break; + default: + printf("GraphicsContext::setCompositeOperation: Unsupported composite operation %s\n", + compositeOperatorName(op).utf8().data()); + } + m_data->m_view->SetDrawingMode(mode); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + + m_data->m_view->ConstrainClippingRegion(path.platformPath()); +} + +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + +void GraphicsContext::clipOut(const Path& path) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) +{ + notImplemented(); +} + +TransformationMatrix GraphicsContext::getCTM() const +{ + notImplemented(); + return TransformationMatrix(); +} + +void GraphicsContext::translate(float x, float y) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +IntPoint GraphicsContext::origin() +{ + notImplemented(); + return IntPoint(0, 0); +} + +void GraphicsContext::rotate(float radians) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::scale(const FloatSize& size) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clipOut(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::concatCTM(const TransformationMatrix& transform) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::setPlatformShouldAntialias(bool enable) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) +{ +} + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformFont(const Font& font) +{ + m_data->m_view->SetFont(font.primaryFont()->platformData().font()); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetHighColor(color); +} + +pattern GraphicsContext::getHaikuStrokeStyle() +{ + switch (strokeStyle()) { + case SolidStroke: + return B_SOLID_HIGH; + break; + case DottedStroke: + return B_MIXED_COLORS; + break; + case DashedStroke: + // FIXME: use a better dashed stroke! + notImplemented(); + return B_MIXED_COLORS; + break; + default: + return B_SOLID_LOW; + break; + } +} + +void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) +{ + // FIXME: see getHaikuStrokeStyle. + notImplemented(); +} + +void GraphicsContext::setPlatformStrokeThickness(float thickness) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetPenSize(thickness); +} + +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetHighColor(color); +} + +void GraphicsContext::clearPlatformShadow() +{ + notImplemented(); +} + +void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&, ColorSpace) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/IconHaiku.cpp b/WebCore/platform/graphics/haiku/IconHaiku.cpp new file mode 100644 index 0000000..3663ee2 --- /dev/null +++ b/WebCore/platform/graphics/haiku/IconHaiku.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" +#include "Icon.h" + +#include "GraphicsContext.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "PlatformString.h" + + +namespace WebCore { + +Icon::~Icon() +{ + notImplemented(); +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + notImplemented(); + return 0; +} + +void Icon::paint(GraphicsContext*, const IntRect&) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/ImageBufferData.h b/WebCore/platform/graphics/haiku/ImageBufferData.h new file mode 100644 index 0000000..f978c34 --- /dev/null +++ b/WebCore/platform/graphics/haiku/ImageBufferData.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ImageBufferData_h +#define ImageBufferData_h + +namespace WebCore { + + class IntSize; + + class ImageBufferData { + public: + ImageBufferData(const IntSize&); + }; + +} // namespace WebCore + +#endif // ImageBufferData_h + diff --git a/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp new file mode 100644 index 0000000..276c968 --- /dev/null +++ b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * 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 "ImageBuffer.h" + +#include "GraphicsContext.h" +#include "ImageData.h" +#include "NotImplemented.h" + + +namespace WebCore { + +ImageBufferData::ImageBufferData(const IntSize&) +{ +} + +ImageBuffer::ImageBuffer(const IntSize&, ImageColorSpace imageColorSpace, bool& success) + : m_data(IntSize()) +{ + notImplemented(); + success = false; +} + +ImageBuffer::~ImageBuffer() +{ +} + +GraphicsContext* ImageBuffer::context() const +{ + notImplemented(); + return 0; +} + +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + notImplemented(); + return 0; +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + notImplemented(); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + notImplemented(); +} + +String ImageBuffer::toDataURL(const String&) const +{ + notImplemented(); + return String(); +} + +Image* ImageBuffer::image() const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/ImageHaiku.cpp b/WebCore/platform/graphics/haiku/ImageHaiku.cpp new file mode 100644 index 0000000..df08822 --- /dev/null +++ b/WebCore/platform/graphics/haiku/ImageHaiku.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * Copyright (C) 2008 Andrea Anzani <andrea.anzani@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" + +#include "BitmapImage.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "PlatformString.h" +#include <Application.h> +#include <Bitmap.h> +#include <View.h> + + +// This function loads resources from WebKit +Vector<char> loadResourceIntoArray(const char*); + + +namespace WebCore { + +bool FrameData::clear(bool clearMetadata) +{ + if (clearMetadata) + m_haveMetadata = false; + + if (m_frame) { + delete m_frame; + m_frame = 0; + m_duration = 0.0f; + m_hasAlpha = true; + return true; + } + + return false; +} + +WTF::PassRefPtr<Image> Image::loadPlatformResource(const char* name) +{ + Vector<char> array = loadResourceIntoArray(name); + WTF::PassRefPtr<BitmapImage> image = BitmapImage::create(); + RefPtr<SharedBuffer> buffer = SharedBuffer::create(array.data(), array.size()); + image->setData(buffer, true); + + return image; +} + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +// Drawing Routines +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) +{ + startAnimation(); + + BBitmap* image = nativeImageForCurrentFrame(); + if (!image || !image->IsValid()) // If the image hasn't fully loaded. + return; + + if (mayFillWithSolidColor()) { + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); + return; + } + + ctxt->save(); + ctxt->setCompositeOperation(op); + + BRect srcRect(src); + BRect dstRect(dst); + + // Test using example site at + // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html + ctxt->platformContext()->SetDrawingMode(B_OP_ALPHA); + ctxt->platformContext()->DrawBitmap(image, srcRect & image->Bounds(), dstRect); + ctxt->restore(); +} + +void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& srcPoint, ColorSpace, CompositeOperator op, const FloatRect& dstRect) +{ + // FIXME: finish this to support also phased position (srcPoint) + startAnimation(); + + BBitmap* image = nativeImageForCurrentFrame(); + if (!image || !image->IsValid()) // If the image hasn't fully loaded. + return; + + float currentW = 0; + float currentH = 0; + + context->save(); + context->platformContext()->SetDrawingMode(B_OP_ALPHA); + context->clip(enclosingIntRect(dstRect)); + + while (currentW < dstRect.width()) { + while (currentH < dstRect.height()) { + context->platformContext()->DrawBitmap(image, BPoint(dstRect.x() + currentW, dstRect.y() + currentH)); + currentH += tileRect.height(); + } + currentW += tileRect.width(); + currentH = 0; + } + context->restore(); +} + +void BitmapImage::checkForSolidColor() +{ + // FIXME: need to check the RGBA32 buffer to see if it is 1x1. + m_isSolidColor = false; + m_checkedForSolidColor = true; +} + +BBitmap* BitmapImage::getBBitmap() const +{ + return const_cast<BitmapImage*>(this)->frameAtIndex(0); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/IntPointHaiku.cpp b/WebCore/platform/graphics/haiku/IntPointHaiku.cpp new file mode 100644 index 0000000..327e503 --- /dev/null +++ b/WebCore/platform/graphics/haiku/IntPointHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntPoint.h" + +#include <Point.h> + + +namespace WebCore { + +IntPoint::IntPoint(const BPoint& point) + : m_x(static_cast<int>(point.x)) + , m_y(static_cast<int>(point.y)) +{ +} + +IntPoint::operator BPoint() const +{ + return BPoint(m_x, m_y); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/IntRectHaiku.cpp b/WebCore/platform/graphics/haiku/IntRectHaiku.cpp new file mode 100644 index 0000000..74a0b9d --- /dev/null +++ b/WebCore/platform/graphics/haiku/IntRectHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntRect.h" + +#include <Rect.h> + + +namespace WebCore { + +IntRect::IntRect(const BRect& rect) + : m_location(rect.LeftTop()) + , m_size(rect.IntegerWidth(), rect.IntegerHeight()) +{ +} + +IntRect::operator BRect() const +{ + return BRect(BPoint(x(), y()), BSize(width(), height())); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp b/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp new file mode 100644 index 0000000..08c3a9d --- /dev/null +++ b/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntSize.h" + +#include <Size.h> + + +namespace WebCore { + +IntSize::IntSize(const BSize& size) + : m_width(size.IntegerWidth()) + , m_height(size.IntegerHeight()) +{ +} + +IntSize::operator BSize() const +{ + return BSize(width(), height()); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/PathHaiku.cpp b/WebCore/platform/graphics/haiku/PathHaiku.cpp new file mode 100644 index 0000000..d0da025 --- /dev/null +++ b/WebCore/platform/graphics/haiku/PathHaiku.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * 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 "Path.h" + +#include "FloatRect.h" +#include "NotImplemented.h" +#include "PlatformString.h" +#include <Region.h> + + +namespace WebCore { + +Path::Path() + : m_path(new BRegion()) +{ +} + +Path::~Path() +{ + delete m_path; +} + +Path::Path(const Path& other) + : m_path(new BRegion(*other.platformPath())) +{ +} + +Path& Path::operator=(const Path& other) +{ + if (&other != this) + m_path = other.platformPath(); + + return *this; +} + +bool Path::hasCurrentPoint() const +{ + return !isEmpty(); +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + return m_path->Contains(point); +} + +void Path::translate(const FloatSize& size) +{ + notImplemented(); +} + +FloatRect Path::boundingRect() const +{ + return m_path->Frame(); +} + +void Path::moveTo(const FloatPoint& point) +{ + // FIXME: Use OffsetBy? + notImplemented(); +} + +void Path::addLineTo(const FloatPoint& p) +{ + notImplemented(); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + notImplemented(); +} + +void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + notImplemented(); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + notImplemented(); +} + +void Path::closeSubpath() +{ + notImplemented(); +} + +void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise) +{ + notImplemented(); +} + +void Path::addRect(const FloatRect& r) +{ + m_path->Include(r); +} + +void Path::addEllipse(const FloatRect& r) +{ + notImplemented(); +} + +void Path::clear() +{ + m_path->MakeEmpty(); +} + +bool Path::isEmpty() const +{ + return !m_path->Frame().IsValid(); +} + +String Path::debugString() const +{ + notImplemented(); + return String(); +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + notImplemented(); +} + +void Path::transform(const TransformationMatrix& transform) +{ + notImplemented(); +} + +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + notImplemented(); + return FloatRect(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp new file mode 100644 index 0000000..adb7573 --- /dev/null +++ b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#include "FloatRect.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "NotImplemented.h" +#include <Rect.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> + + +extern int charUnicodeToUTF8HACK(unsigned short, char*); + +namespace WebCore { + +void SimpleFontData::platformInit() +{ + BFont* font = m_platformData.font(); + if (!font) + return; + + font_height height; + font->GetHeight(&height); + m_ascent = static_cast<int>(height.ascent); + m_descent = static_cast<int>(height.descent); + m_lineSpacing = m_ascent + m_descent; + m_xHeight = height.ascent * 0.56f; // Hack taken from the win port. + m_lineGap = height.leading; +} + +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); +} + +void SimpleFontData::platformDestroy() +{ + delete m_smallCapsFontData; + m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + FontDescription desc = FontDescription(fontDescription); + desc.setSpecifiedSize(0.70f * fontDescription.computedSize()); + const FontPlatformData* fontPlatformData = new FontPlatformData(desc, desc.family().family()); + m_smallCapsFontData = new SimpleFontData(*fontPlatformData); + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + // FIXME: We will need to implement this to load non-ASCII encoding sites + return true; +} + +void SimpleFontData::determinePitch() +{ + m_treatAsFixedPitch = m_platformData.font() && m_platformData.font()->IsFixed(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + if (!m_platformData.font()) + return 0; + + char charArray[4]; + float escapements[1]; + + charUnicodeToUTF8HACK(glyph, charArray); + m_platformData.font()->GetEscapements(charArray, 1, escapements); + return escapements[0] * m_platformData.font()->Size(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.h b/WebCore/platform/graphics/mac/Canvas3DLayer.h new file mode 100644 index 0000000..122ef39 --- /dev/null +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Canvas3DLayer_h +#define Canvas3DLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#import "WebLayer.h" + +namespace WebCore { + class GraphicsLayer; +} + +@interface Canvas3DLayer : CAOpenGLLayer +{ + WebCore::GraphicsLayer* m_layerOwner; + CGLContextObj m_contextObj; + GLuint m_texture; +} + +- (id)initWithContext:(CGLContextObj)context texture:(GLuint)texture; + +- (CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace; + +@end + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // Canvas3DLayer_h diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.mm b/WebCore/platform/graphics/mac/Canvas3DLayer.mm new file mode 100644 index 0000000..94819d4 --- /dev/null +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.mm @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) +#if ENABLE(3D_CANVAS) + +#import "Canvas3DLayer.h" + +#import "GraphicsLayer.h" +#import <QuartzCore/QuartzCore.h> +#import <OpenGL/OpenGL.h> +#import <wtf/RetainPtr.h> +#include <wtf/FastMalloc.h> + +using namespace WebCore; + +@implementation Canvas3DLayer + +-(id)initWithContext:(CGLContextObj)context texture:(GLuint)texture +{ + m_contextObj = context; + m_texture = texture; + self = [super init]; + return self; +} + +-(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask +{ + // FIXME: The mask param tells you which display (on a multi-display system) + // is to be used. But since we are now getting the pixel format from the + // Canvas CGL context, we don't use it. This seems to do the right thing on + // one multi-display system. But there may be cases where this is not the case. + // If needed we will have to set the display mask in the Canvas CGLContext and + // make sure it matches. + UNUSED_PARAM(mask); + return CGLRetainPixelFormat(CGLGetPixelFormat(m_contextObj)); +} + +-(CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat +{ + CGLContextObj contextObj; + CGLCreateContext(pixelFormat, m_contextObj, &contextObj); + return contextObj; +} + +-(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + CGLSetCurrentContext(m_contextObj); + glFinish(); + CGLSetCurrentContext(glContext); + + CGRect frame = [self frame]; + + // draw the FBO into the layer + glViewport(0, 0, frame.size.width, frame.size.height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1, 1, -1, 1, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_texture); + + glBegin(GL_TRIANGLE_FAN); + glTexCoord2f(0, 0); + glVertex2f(-1, -1); + glTexCoord2f(1, 0); + glVertex2f(1, -1); + glTexCoord2f(1, 1); + glVertex2f(1, 1); + glTexCoord2f(0, 1); + glVertex2f(-1, 1); + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + // Call super to finalize the drawing. By default all it does is call glFlush(). + [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; +} + +static void freeData(void *, const void *data, size_t /* size */) +{ + fastFree(const_cast<void *>(data)); +} + +-(CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace +{ + CGLSetCurrentContext(m_contextObj); + + RetainPtr<CGColorSpaceRef> imageColorSpace = colorSpace; + if (!imageColorSpace) + imageColorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); + + CGRect layerBounds = CGRectIntegral([self bounds]); + + size_t width = layerBounds.size.width; + size_t height = layerBounds.size.height; + + size_t rowBytes = (width * 4 + 15) & ~15; + size_t dataSize = rowBytes * height; + void* data = fastMalloc(dataSize); + if (!data) + return 0; + + glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4); + glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data); + + CGDataProviderRef provider = CGDataProviderCreateWithData(0, data, dataSize, freeData); + CGImageRef image = CGImageCreate(width, height, 8, 32, rowBytes, imageColorSpace.get(), + kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, + provider, 0, true, + kCGRenderingIntentDefault); + CGDataProviderRelease(provider); + return image; +} + +@end + +@implementation Canvas3DLayer(WebLayerAdditions) + +-(void)setLayerOwner:(GraphicsLayer*)aLayer +{ + m_layerOwner = aLayer; +} + +-(GraphicsLayer*)layerOwner +{ + return m_layerOwner; +} + +@end + +#endif // ENABLE(3D_CANVAS) +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp index 05f29b5..265b2c3 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,30 +10,24 @@ * 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. + * 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 "CoreTextController.h" - -#if USE(CORE_TEXT) +#include "ComplexTextController.h" #include "CharacterNames.h" #include "Font.h" -#include "FontCache.h" -#include "SimpleFontData.h" #include "TextBreakIterator.h" -#include <wtf/MathExtras.h> using namespace std; @@ -53,54 +47,7 @@ static inline CGFloat ceilCGFloat(CGFloat f) return static_cast<CGFloat>(ceil(f)); } -CoreTextController::CoreTextRun::CoreTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) - : m_CTRun(ctRun) - , m_fontData(fontData) - , m_characters(characters) - , m_stringLocation(stringLocation) - , m_stringLength(stringLength) -{ - m_glyphCount = CTRunGetGlyphCount(ctRun); - m_indices = CTRunGetStringIndicesPtr(ctRun); - if (!m_indices) { - m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); - CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex)); - m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get())); - CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices)); - } -} - -// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on -// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path. -CoreTextController::CoreTextRun::CoreTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) - : m_fontData(fontData) - , m_characters(characters) - , m_stringLocation(stringLocation) - , m_stringLength(stringLength) -{ - Vector<CFIndex, 16> indices; - unsigned r = 0; - while (r < stringLength) { - indices.append(r); - if (U_IS_SURROGATE(characters[r])) { - ASSERT(r + 1 < stringLength); - ASSERT(U_IS_SURROGATE_LEAD(characters[r])); - ASSERT(U_IS_TRAIL(characters[r + 1])); - r += 2; - } else - r++; - } - m_glyphCount = indices.size(); - if (!ltr) { - for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) - std::swap(indices[r], indices[end]); - } - m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); - CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex)); - m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); -} - -CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) +ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(*font) , m_run(run) , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection) @@ -111,6 +58,7 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo , m_numGlyphsSoFar(0) , m_currentRun(0) , m_glyphInCurrentRun(0) + , m_characterInCurrentGlyph(0) , m_finalRoundingWidth(0) , m_fallbackFonts(fallbackFonts) , m_lastRoundingGlyph(0) @@ -130,16 +78,12 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo m_padPerSpace = ceilf(m_run.padding() / numSpaces); } - collectCoreTextRuns(); + collectComplexTextRuns(); adjustGlyphsAndAdvances(); } -int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) +int ComplexTextController::offsetForPosition(int h, bool includePartialGlyphs) { - // FIXME: For positions occurring within a ligature, we should return the closest "ligature caret" or - // approximate it by dividing the width of the ligature by the number of characters it encompasses. - // However, Core Text does not expose a low-level API for directly finding - // out how many characters a ligature encompasses (the "attachment count"). if (h >= m_totalWidth) return m_run.ltr() ? m_end : 0; if (h < 0) @@ -147,17 +91,27 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) CGFloat x = h; - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); size_t offsetIntoAdjustedGlyphs = 0; for (size_t r = 0; r < runCount; ++r) { - const CoreTextRun& coreTextRun = m_coreTextRuns[r]; - for (unsigned j = 0; j < coreTextRun.glyphCount(); ++j) { + const ComplexTextRun& complexTextRun = *m_complexTextRuns[r]; + for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) { CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width; - if (x <= adjustedAdvance) { - CFIndex hitIndex = coreTextRun.indexAt(j); - int stringLength = coreTextRun.stringLength(); - TextBreakIterator* cursorPositionIterator = cursorMovementIterator(coreTextRun.characters(), stringLength); + if (x < adjustedAdvance) { + CFIndex hitGlyphStart = complexTextRun.indexAt(j); + CFIndex hitGlyphEnd; + if (m_run.ltr()) + hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : complexTextRun.stringLength()); + else + hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : complexTextRun.stringLength()); + + // FIXME: Instead of dividing the glyph's advance equially between the characters, this + // could use the glyph's "ligature carets". However, there is no Core Text API to get the + // ligature carets. + CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance); + int stringLength = complexTextRun.stringLength(); + TextBreakIterator* cursorPositionIterator = cursorMovementIterator(complexTextRun.characters(), stringLength); int clusterStart; if (isTextBreak(cursorPositionIterator, hitIndex)) clusterStart = hitIndex; @@ -168,45 +122,49 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) } if (!includePartialGlyphs) - return coreTextRun.stringLocation() + clusterStart; + return complexTextRun.stringLocation() + clusterStart; int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex); if (clusterEnd == TextBreakDone) clusterEnd = stringLength; - CGFloat clusterWidth = adjustedAdvance; - // FIXME: The search stops at the boundaries of coreTextRun. In theory, it should go on into neighboring CoreTextRuns + CGFloat clusterWidth; + // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no // reordering and on font fallback should occur within a CTLine. if (clusterEnd - clusterStart > 1) { + clusterWidth = adjustedAdvance; int firstGlyphBeforeCluster = j - 1; - while (firstGlyphBeforeCluster >= 0 && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { + while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width; clusterWidth += width; x += width; firstGlyphBeforeCluster--; } unsigned firstGlyphAfterCluster = j + 1; - while (firstGlyphAfterCluster < coreTextRun.glyphCount() && coreTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) { + while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) { clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width; firstGlyphAfterCluster++; } + } else { + clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart); + x -= clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1); } if (x <= clusterWidth / 2) - return coreTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd); + return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd); else - return coreTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart); + return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart); } x -= adjustedAdvance; } - offsetIntoAdjustedGlyphs += coreTextRun.glyphCount(); + offsetIntoAdjustedGlyphs += complexTextRun.glyphCount(); } ASSERT_NOT_REACHED(); return 0; } -void CoreTextController::collectCoreTextRuns() +void ComplexTextController::collectComplexTextRuns() { if (!m_end) return; @@ -227,7 +185,7 @@ void CoreTextController::collectCoreTextRuns() static const UChar hyphen = '-'; if (hasTrailingSoftHyphen && m_run.rtl()) { - collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); + collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); indexOfFontTransition--; curr--; } @@ -290,7 +248,7 @@ void CoreTextController::collectCoreTextRuns() if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) { int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition; int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition; - collectCoreTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0); + collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0); indexOfFontTransition = index; } } @@ -298,19 +256,15 @@ void CoreTextController::collectCoreTextRuns() int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition - (hasTrailingSoftHyphen ? 1 : 0); if (itemLength) { int itemStart = m_run.rtl() ? 0 : indexOfFontTransition; - collectCoreTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0); + collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0); } if (hasTrailingSoftHyphen && m_run.ltr()) - collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); + collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); } -void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) +void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) { - // FIXME: For offsets falling inside a ligature, we should advance only as far as the appropriate "ligature caret" - // or divide the width of the ligature by the number of offsets it encompasses and make an advance proportional - // to the offsets into the ligature. However, Core Text does not expose a low-level API for - // directly finding out how many characters a ligature encompasses (the "attachment count"). if (static_cast<int>(offset) > m_end) offset = m_end; @@ -319,24 +273,44 @@ void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) m_currentCharacter = offset; - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); bool ltr = m_run.ltr(); unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar; while (m_currentRun < runCount) { - const CoreTextRun& coreTextRun = m_coreTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun]; - size_t glyphCount = coreTextRun.glyphCount(); + const ComplexTextRun& complexTextRun = *m_complexTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun]; + size_t glyphCount = complexTextRun.glyphCount(); unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun; while (m_glyphInCurrentRun < glyphCount) { - if (coreTextRun.indexAt(g) + coreTextRun.stringLocation() >= m_currentCharacter) - return; + unsigned glyphStartOffset = complexTextRun.indexAt(g); + unsigned glyphEndOffset; + if (ltr) + glyphEndOffset = max<unsigned>(glyphStartOffset, g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.stringLength()); + else + glyphEndOffset = max<unsigned>(glyphStartOffset, g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.stringLength()); + CGSize adjustedAdvance = m_adjustedAdvances[k]; - if (glyphBuffer) - glyphBuffer->add(m_adjustedGlyphs[k], coreTextRun.fontData(), adjustedAdvance); - m_runWidthSoFar += adjustedAdvance.width; + + if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter) + return; + + if (glyphBuffer && !m_characterInCurrentGlyph) + glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), adjustedAdvance); + + unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph; + m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset; + // FIXME: Instead of dividing the glyph's advance equially between the characters, this + // could use the glyph's "ligature carets". However, there is no Core Text API to get the + // ligature carets. + m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset); + + if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter) + return; + m_numGlyphsSoFar++; m_glyphInCurrentRun++; + m_characterInCurrentGlyph = 0; if (ltr) { g++; k++; @@ -352,100 +326,35 @@ void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) m_runWidthSoFar += m_finalRoundingWidth; } -void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) -{ - if (!fontData) { - // Create a run of missing glyphs from the primary font. - m_coreTextRuns.append(CoreTextRun(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); - return; - } - - if (m_fallbackFonts && fontData != m_font.primaryFont()) - m_fallbackFonts->add(fontData); - - RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); - - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes())); - - RetainPtr<CTTypesetterRef> typesetter; - - if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) { - static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel }; - static const void* ltrOptionValues[] = { kCFBooleanFalse }; - static const void* rtlOptionValues[] = { kCFBooleanTrue }; - static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); - } else - typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get())); - - RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0))); - - CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); - - CFIndex runCount = CFArrayGetCount(runArray); - - for (CFIndex r = 0; r < runCount; r++) { - CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); - ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); - m_coreTextRuns.append(CoreTextRun(ctRun, fontData, cp, stringLocation, length)); - } -} - -void CoreTextController::adjustGlyphsAndAdvances() +void ComplexTextController::adjustGlyphsAndAdvances() { - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); for (size_t r = 0; r < runCount; ++r) { - const CoreTextRun& coreTextRun = m_coreTextRuns[r]; - unsigned glyphCount = coreTextRun.glyphCount(); - const SimpleFontData* fontData = coreTextRun.fontData(); - - Vector<CGGlyph, 256> glyphsVector; - const CGGlyph* glyphs; - - Vector<CGSize, 256> advancesVector; - const CGSize* advances; - - if (coreTextRun.ctRun()) { - glyphs = CTRunGetGlyphsPtr(coreTextRun.ctRun()); - if (!glyphs) { - glyphsVector.grow(glyphCount); - CTRunGetGlyphs(coreTextRun.ctRun(), CFRangeMake(0, 0), glyphsVector.data()); - glyphs = glyphsVector.data(); - } + const ComplexTextRun& complexTextRun = *m_complexTextRuns[r]; + unsigned glyphCount = complexTextRun.glyphCount(); + const SimpleFontData* fontData = complexTextRun.fontData(); - advances = CTRunGetAdvancesPtr(coreTextRun.ctRun()); - if (!advances) { - advancesVector.grow(glyphCount); - CTRunGetAdvances(coreTextRun.ctRun(), CFRangeMake(0, 0), advancesVector.data()); - advances = advancesVector.data(); - } - } else { - // Synthesize a run of missing glyphs. - glyphsVector.fill(0, glyphCount); - glyphs = glyphsVector.data(); - advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), glyphCount); - advances = advancesVector.data(); - } + const CGGlyph* glyphs = complexTextRun.glyphs(); + const CGSize* advances = complexTextRun.advances(); bool lastRun = r + 1 == runCount; - const UChar* cp = coreTextRun.characters(); + const UChar* cp = complexTextRun.characters(); CGFloat roundedSpaceWidth = roundCGFloat(fontData->spaceWidth()); bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances(); bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled(); for (unsigned i = 0; i < glyphCount; i++) { - CFIndex characterIndex = coreTextRun.indexAt(i); + CFIndex characterIndex = complexTextRun.indexAt(i); UChar ch = *(cp + characterIndex); bool lastGlyph = lastRun && i + 1 == glyphCount; UChar nextCh; if (lastGlyph) nextCh = ' '; else if (i + 1 < glyphCount) - nextCh = *(cp + coreTextRun.indexAt(i + 1)); + nextCh = *(cp + complexTextRun.indexAt(i + 1)); else - nextCh = *(m_coreTextRuns[r + 1].characters() + m_coreTextRuns[r + 1].indexAt(0)); + nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0)); bool treatAsSpace = Font::treatAsSpace(ch); CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i]; @@ -533,5 +442,3 @@ void CoreTextController::adjustGlyphsAndAdvances() } } // namespace WebCore - -#endif // USE(CORE_TEXT) diff --git a/WebCore/platform/graphics/mac/ComplexTextController.h b/WebCore/platform/graphics/mac/ComplexTextController.h new file mode 100644 index 0000000..7a915e2 --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextController.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 ComplexTextController_h +#define ComplexTextController_h + +#include "GlyphBuffer.h" +#include <wtf/HashSet.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +class Font; +class SimpleFontData; +class TextRun; + +class ComplexTextController { +public: + ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); + + // Advance and emit glyphs up to the specified character. + void advance(unsigned to, GlyphBuffer* = 0); + + // Compute the character offset for a given x coordinate. + int offsetForPosition(int x, bool includePartialGlyphs); + + // Returns the width of everything we've consumed so far. + float runWidthSoFar() const { return m_runWidthSoFar; } + + float totalWidth() const { return m_totalWidth; } + + // Extra width to the left of the leftmost glyph. + float finalRoundingWidth() const { return m_finalRoundingWidth; } + +private: + class ComplexTextRun : public RefCounted<ComplexTextRun> { + public: +#if USE(CORE_TEXT) + static PassRefPtr<ComplexTextRun> create(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) + { + return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength)); + } +#elif USE(ATSUI) + static PassRefPtr<ComplexTextRun> create(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride) + { + return adoptRef(new ComplexTextRun(atsuTextLayout, fontData, characters, stringLocation, stringLength, ltr, directionalOverride)); + } +#endif + static PassRefPtr<ComplexTextRun> create(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + { + return adoptRef(new ComplexTextRun(fontData, characters, stringLocation, stringLength, ltr)); + } + + unsigned glyphCount() const { return m_glyphCount; } + const SimpleFontData* fontData() const { return m_fontData; } + const UChar* characters() const { return m_characters; } + unsigned stringLocation() const { return m_stringLocation; } + size_t stringLength() const { return m_stringLength; } + CFIndex indexAt(size_t i) const { return m_indices[i]; } + const CGGlyph* glyphs() const { return m_glyphs; } + const CGSize* advances() const { return m_advances; } + + private: +#if USE(CORE_TEXT) + ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength); +#elif USE(ATSUI) + ComplexTextRun(ATSUTextLayout, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride); +#endif + ComplexTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr); + +#if USE(ATSUI) +#ifdef BUILDING_ON_TIGER + typedef UInt32 URefCon; +#endif + static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef, URefCon, void*, ATSULayoutOperationCallbackStatus*); +#endif + +#if USE(CORE_TEXT) + RetainPtr<CTRunRef> m_CTRun; +#endif + unsigned m_glyphCount; + const SimpleFontData* m_fontData; + const UChar* m_characters; + unsigned m_stringLocation; + size_t m_stringLength; +#if USE(CORE_TEXT) + RetainPtr<CFMutableDataRef> m_indicesData; + const CFIndex* m_indices; +#elif USE(ATSUI) + Vector<CFIndex, 64> m_indices; +#endif + Vector<CGGlyph, 64> m_glyphsVector; + const CGGlyph* m_glyphs; + Vector<CGSize, 64> m_advancesVector; + const CGSize* m_advances; +#if USE(ATSUI) + bool m_ltr; + bool m_directionalOverride; +#endif + }; + + void collectComplexTextRuns(); + void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); + void adjustGlyphsAndAdvances(); + + const Font& m_font; + const TextRun& m_run; + bool m_mayUseNaturalWritingDirection; + + Vector<UChar, 256> m_smallCapsBuffer; + + Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns; + Vector<CGSize, 256> m_adjustedAdvances; + Vector<CGGlyph, 256> m_adjustedGlyphs; + + unsigned m_currentCharacter; + int m_end; + + CGFloat m_totalWidth; + + float m_runWidthSoFar; + unsigned m_numGlyphsSoFar; + size_t m_currentRun; + unsigned m_glyphInCurrentRun; + unsigned m_characterInCurrentGlyph; + float m_finalRoundingWidth; + float m_padding; + float m_padPerSpace; + + HashSet<const SimpleFontData*>* m_fallbackFonts; + + unsigned m_lastRoundingGlyph; +}; + +} // namespace WebCore + +#endif // ComplexTextController_h diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp new file mode 100644 index 0000000..78c588f --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp @@ -0,0 +1,341 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * 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 "ComplexTextController.h" + +#if USE(ATSUI) + +#include "CharacterNames.h" +#include "Font.h" +#include "ShapeArabic.h" + +#ifdef __LP64__ +// ATSUTextInserted() is SPI in 64-bit. +extern "C" { +OSStatus ATSUTextInserted(ATSUTextLayout iTextLayout, UniCharArrayOffset iInsertionLocation, UniCharCount iInsertionLength); +} +#endif + +using namespace WTF::Unicode; + +namespace WebCore { + +OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef atsuLineRef, URefCon refCon, void*, ATSULayoutOperationCallbackStatus* callbackStatus) +{ + ComplexTextRun* complexTextRun = reinterpret_cast<ComplexTextRun*>(refCon); + OSStatus status; + ItemCount count; + ATSLayoutRecord *layoutRecords; + + status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, reinterpret_cast<void**>(&layoutRecords), &count); + if (status != noErr) { + *callbackStatus = kATSULayoutOperationCallbackStatusContinue; + return status; + } + + count--; + ItemCount j = 0; + CFIndex indexOffset = 0; + + if (complexTextRun->m_directionalOverride) { + j++; + count -= 2; + indexOffset = -1; + } + + complexTextRun->m_glyphCount = count; + complexTextRun->m_glyphsVector.reserveCapacity(count); + complexTextRun->m_advancesVector.reserveCapacity(count); + complexTextRun->m_indices.reserveCapacity(count); + + bool atBeginning = true; + CGFloat lastX = 0; + + for (ItemCount i = 0; i < count; ++i, ++j) { + if (layoutRecords[j].glyphID == kATSDeletedGlyphcode) { + complexTextRun->m_glyphCount--; + continue; + } + complexTextRun->m_glyphsVector.uncheckedAppend(layoutRecords[j].glyphID); + complexTextRun->m_indices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset); + CGFloat x = FixedToFloat(layoutRecords[j].realPos); + if (!atBeginning) + complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(x - lastX, 0)); + lastX = x; + atBeginning = false; + } + + complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(FixedToFloat(layoutRecords[j].realPos) - lastX, 0)); + + complexTextRun->m_glyphs = complexTextRun->m_glyphsVector.data(); + complexTextRun->m_advances = complexTextRun->m_advancesVector.data(); + + status = ATSUDirectReleaseLayoutDataArrayPtr(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, reinterpret_cast<void**>(&layoutRecords)); + *callbackStatus = kATSULayoutOperationCallbackStatusContinue; + return noErr; +} + +static inline bool isArabicLamWithAlefLigature(UChar c) +{ + return c >= 0xfef5 && c <= 0xfefc; +} + +static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength) +{ + unsigned shapingStart = 0; + while (shapingStart < totalLength) { + unsigned shapingEnd; + // We do not want to pass a Lam with Alef ligature followed by a space to the shaper, + // since we want to be able to identify this sequence as the result of shaping a Lam + // followed by an Alef and padding with a space. + bool foundLigatureSpace = false; + for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd) + foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' '; + shapingEnd++; + + UErrorCode shapingError = U_ZERO_ERROR; + unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError); + + if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) { + for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) { + if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ') + dest[++j] = zeroWidthSpace; + } + if (foundLigatureSpace) { + dest[shapingEnd] = ' '; + shapingEnd++; + } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) { + // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef, + // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR. + ASSERT(dest[shapingStart] == ' '); + dest[shapingStart] = zeroWidthSpace; + } + } else { + // Something went wrong. Abandon shaping and just copy the rest of the buffer. + LOG_ERROR("u_shapeArabic failed(%d)", shapingError); + shapingEnd = totalLength; + memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar)); + } + shapingStart = shapingEnd; + } +} + +ComplexTextController::ComplexTextRun::ComplexTextRun(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) + , m_ltr(ltr) + , m_directionalOverride(directionalOverride) +{ + OSStatus status; + + status = ATSUSetTextLayoutRefCon(atsuTextLayout, reinterpret_cast<URefCon>(this)); + + ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers; + + Boolean rtl = !ltr; + + Vector<UChar, 256> substituteCharacters; + bool shouldCheckForMirroring = !ltr && !fontData->m_ATSUMirrors; + bool shouldCheckForArabic = !fontData->shapesArabic(); + bool shouldShapeArabic = false; + + bool mirrored = false; + for (size_t i = 0; i < stringLength; ++i) { + if (shouldCheckForMirroring) { + UChar mirroredChar = u_charMirror(characters[i]); + if (mirroredChar != characters[i]) { + if (!mirrored) { + mirrored = true; + substituteCharacters.grow(stringLength); + memcpy(substituteCharacters.data(), characters, stringLength * sizeof(UChar)); + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } + substituteCharacters[i] = mirroredChar; + } + } + if (shouldCheckForArabic && isArabicChar(characters[i])) { + shouldCheckForArabic = false; + shouldShapeArabic = true; + } + } + + if (shouldShapeArabic) { + Vector<UChar, 256> shapedArabic(stringLength); + shapeArabic(substituteCharacters.isEmpty() ? characters : substituteCharacters.data(), shapedArabic.data(), stringLength); + substituteCharacters.swap(shapedArabic); + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } + + if (directionalOverride) { + UChar override = ltr ? leftToRightOverride : rightToLeftOverride; + if (substituteCharacters.isEmpty()) { + substituteCharacters.grow(stringLength + 2); + substituteCharacters[0] = override; + memcpy(substituteCharacters.data() + 1, characters, stringLength * sizeof(UChar)); + substituteCharacters[stringLength + 1] = popDirectionalFormatting; + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } else { + substituteCharacters.prepend(override); + substituteCharacters.append(popDirectionalFormatting); + } + ATSUTextInserted(atsuTextLayout, 0, 2); + } + + ATSULayoutOperationOverrideSpecifier overrideSpecifier; + overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment; + overrideSpecifier.overrideUPP = overrideLayoutOperation; + + ATSUAttributeTag tags[] = { kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag }; + ByteCount sizes[] = { sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) }; + ATSUAttributeValuePtr values[] = { &lineLayoutOptions, &rtl, &overrideSpecifier }; + + status = ATSUSetLayoutControls(atsuTextLayout, 3, tags, sizes, values); + + ItemCount boundsCount; + status = ATSUGetGlyphBounds(atsuTextLayout, 0, 0, 0, m_stringLength, kATSUseFractionalOrigins, 0, 0, &boundsCount); + + status = ATSUDisposeTextLayout(atsuTextLayout); +} + +ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + m_indices.reserveCapacity(stringLength); + unsigned r = 0; + while (r < stringLength) { + m_indices.uncheckedAppend(r); + if (U_IS_SURROGATE(characters[r])) { + ASSERT(r + 1 < stringLength); + ASSERT(U_IS_SURROGATE_LEAD(characters[r])); + ASSERT(U_IS_TRAIL(characters[r + 1])); + r += 2; + } else + r++; + } + m_glyphCount = m_indices.size(); + if (!ltr) { + for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) + std::swap(m_indices[r], m_indices[end]); + } + + m_glyphsVector.fill(0, m_glyphCount); + m_glyphs = m_glyphsVector.data(); + m_advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), m_glyphCount); + m_advances = m_advancesVector.data(); +} + +static bool fontHasMirroringInfo(ATSUFontID fontID) +{ + ByteCount propTableSize; + OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize); + if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info + return true; + else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error + LOG_ERROR("ATSFontGetTable failed (%d)", static_cast<int>(status)); + + return false; +} + +static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode) +{ + // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are + // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example. + // See bugzilla 5166. + if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures()) + return; + + ATSUFontFeatureType featureTypes[] = { kLigaturesType }; + ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector }; + OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors); + if (status != noErr) + LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", static_cast<int>(status)); +} + +static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode) +{ + if (fontData->m_ATSUStyleInitialized) + return; + + ATSUFontID fontID = fontData->platformData().m_atsuFontID; + if (!fontID) { + LOG_ERROR("unable to get ATSUFontID for %p", fontData->platformData().font()); + return; + } + + OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle); + if (status != noErr) + LOG_ERROR("ATSUCreateStyle failed (%d)", static_cast<int>(status)); + + Fixed fontSize = FloatToFixed(fontData->platformData().m_size); + Fract kerningInhibitFactor = FloatToFract(1); + static CGAffineTransform verticalFlip = CGAffineTransformMakeScale(1, -1); + + ByteCount styleSizes[4] = { sizeof(fontSize), sizeof(fontID), sizeof(verticalFlip), sizeof(kerningInhibitFactor) }; + ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; + ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &verticalFlip, &kerningInhibitFactor }; + + bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; + status = ATSUSetAttributes(fontData->m_ATSUStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues); + if (status != noErr) + LOG_ERROR("ATSUSetAttributes failed (%d)", static_cast<int>(status)); + + fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID); + + disableLigatures(fontData, textMode); + + fontData->m_ATSUStyleInitialized = true; +} + +void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +{ + if (!fontData) { + // Create a run of missing glyphs from the primary font. + m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); + return; + } + + if (m_fallbackFonts && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + + initializeATSUStyle(fontData, m_font.fontDescription().textRenderingMode()); + + OSStatus status; + ATSUTextLayout atsuTextLayout; + UniCharCount runLength = length; + + status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &fontData->m_ATSUStyle, &atsuTextLayout); + if (status != noErr) { + LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed with error %d", static_cast<int>(status)); + return; + } + m_complexTextRuns.append(ComplexTextRun::create(atsuTextLayout, fontData, cp, stringLocation, length, m_run.ltr(), m_run.directionalOverride())); +} + +} // namespace WebCore + +#endif // USE(ATSUI) diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp new file mode 100644 index 0000000..c9daf84 --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 "ComplexTextController.h" + +#if USE(CORE_TEXT) + +#include "Font.h" + +namespace WebCore { + +ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) + : m_CTRun(ctRun) + , m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + m_glyphCount = CTRunGetGlyphCount(m_CTRun.get()); + m_indices = CTRunGetStringIndicesPtr(m_CTRun.get()); + if (!m_indices) { + m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); + CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex)); + m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get())); + CTRunGetStringIndices(m_CTRun.get(), CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices)); + } + + m_glyphs = CTRunGetGlyphsPtr(m_CTRun.get()); + if (!m_glyphs) { + m_glyphsVector.grow(m_glyphCount); + CTRunGetGlyphs(m_CTRun.get(), CFRangeMake(0, 0), m_glyphsVector.data()); + m_glyphs = m_glyphsVector.data(); + } + + m_advances = CTRunGetAdvancesPtr(m_CTRun.get()); + if (!m_advances) { + m_advancesVector.grow(m_glyphCount); + CTRunGetAdvances(m_CTRun.get(), CFRangeMake(0, 0), m_advancesVector.data()); + m_advances = m_advancesVector.data(); + } + +} + +// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on +// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path. +ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + Vector<CFIndex, 16> indices; + unsigned r = 0; + while (r < stringLength) { + indices.append(r); + if (U_IS_SURROGATE(characters[r])) { + ASSERT(r + 1 < stringLength); + ASSERT(U_IS_SURROGATE_LEAD(characters[r])); + ASSERT(U_IS_TRAIL(characters[r + 1])); + r += 2; + } else + r++; + } + m_glyphCount = indices.size(); + if (!ltr) { + for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) + std::swap(indices[r], indices[end]); + } + m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); + CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex)); + m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); + + // Synthesize a run of missing glyphs. + m_glyphsVector.fill(0, m_glyphCount); + m_glyphs = m_glyphsVector.data(); + m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount); + m_advances = m_advancesVector.data(); +} + +void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +{ + if (!fontData) { + // Create a run of missing glyphs from the primary font. + m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); + return; + } + + if (m_fallbackFonts && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + + RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); + + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode()))); + + RetainPtr<CTTypesetterRef> typesetter; + + if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) { + static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel }; + static const void* ltrOptionValues[] = { kCFBooleanFalse }; + static const void* rtlOptionValues[] = { kCFBooleanTrue }; + static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); + } else + typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get())); + + RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0))); + + CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); + + CFIndex runCount = CFArrayGetCount(runArray); + + for (CFIndex r = 0; r < runCount; r++) { + CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); + ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); + m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length)); + } +} + +} // namespace WebCore + +#endif // USE(CORE_TEXT) diff --git a/WebCore/platform/graphics/mac/CoreTextController.h b/WebCore/platform/graphics/mac/CoreTextController.h deleted file mode 100644 index 4dd6f93..0000000 --- a/WebCore/platform/graphics/mac/CoreTextController.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 CoreTextController_h -#define CoreTextController_h - -#if USE(CORE_TEXT) - -#include "Font.h" -#include "GlyphBuffer.h" -#include <wtf/RetainPtr.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class CoreTextController { -public: - CoreTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); - - // Advance and emit glyphs up to the specified character. - void advance(unsigned to, GlyphBuffer* = 0); - - // Compute the character offset for a given x coordinate. - int offsetForPosition(int x, bool includePartialGlyphs); - - // Returns the width of everything we've consumed so far. - float runWidthSoFar() const { return m_runWidthSoFar; } - - float totalWidth() const { return m_totalWidth; } - - // Extra width to the left of the leftmost glyph. - float finalRoundingWidth() const { return m_finalRoundingWidth; } - -private: - class CoreTextRun { - public: - CoreTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength); - CoreTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr); - - CTRunRef ctRun() const { return m_CTRun.get(); } - unsigned glyphCount() const { return m_glyphCount; } - const SimpleFontData* fontData() const { return m_fontData; } - const UChar* characters() const { return m_characters; } - unsigned stringLocation() const { return m_stringLocation; } - size_t stringLength() const { return m_stringLength; } - CFIndex indexAt(size_t i) const { return m_indices[i]; } - - private: - RetainPtr<CTRunRef> m_CTRun; - unsigned m_glyphCount; - const SimpleFontData* m_fontData; - const UChar* m_characters; - unsigned m_stringLocation; - size_t m_stringLength; - const CFIndex* m_indices; - // Used only if CTRunGet*Ptr fails or if this is a missing glyphs run. - RetainPtr<CFMutableDataRef> m_indicesData; - }; - - void collectCoreTextRuns(); - void collectCoreTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); - void adjustGlyphsAndAdvances(); - - const Font& m_font; - const TextRun& m_run; - bool m_mayUseNaturalWritingDirection; - - Vector<UChar, 256> m_smallCapsBuffer; - - Vector<CoreTextRun, 16> m_coreTextRuns; - Vector<CGSize, 256> m_adjustedAdvances; - Vector<CGGlyph, 256> m_adjustedGlyphs; - - unsigned m_currentCharacter; - int m_end; - - CGFloat m_totalWidth; - - float m_runWidthSoFar; - unsigned m_numGlyphsSoFar; - size_t m_currentRun; - unsigned m_glyphInCurrentRun; - float m_finalRoundingWidth; - float m_padding; - float m_padPerSpace; - - HashSet<const SimpleFontData*>* m_fallbackFonts; - - unsigned m_lastRoundingGlyph; -}; - -} // namespace WebCore -#endif // USE(CORE_TEXT) -#endif // CoreTextController_h diff --git a/WebCore/platform/graphics/mac/FontMacCoreText.cpp b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp index 9dffc7a..0db2601 100644 --- a/WebCore/platform/graphics/mac/FontMacCoreText.cpp +++ b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,25 +10,22 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "Font.h" -#if USE(CORE_TEXT) - -#include "CoreTextController.h" +#include "ComplexTextController.h" #include "FontFallbackList.h" #include "GlyphBuffer.h" #include "GraphicsContext.h" @@ -41,7 +38,7 @@ namespace WebCore { FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const { - CoreTextController controller(this, run); + ComplexTextController controller(this, run); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to); @@ -63,7 +60,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F GlyphBuffer glyphBuffer; float startX = point.x(); - CoreTextController controller(this, run); + ComplexTextController controller(this, run); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to, &glyphBuffer); @@ -88,15 +85,14 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { - CoreTextController controller(this, run, true, fallbackFonts); + ComplexTextController controller(this, run, true, fallbackFonts); return controller.totalWidth(); } int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const { - CoreTextController controller(this, run); + ComplexTextController controller(this, run); return controller.offsetForPosition(x, includePartialGlyphs); } -} -#endif // USE(CORE_TEXT) +} // namespace WebCore diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index e40bbab..256b5a4 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -24,6 +24,7 @@ #include <ApplicationServices/ApplicationServices.h> #include "SharedBuffer.h" #include "FontPlatformData.h" +#include "OpenTypeSanitizer.h" namespace WebCore { @@ -43,14 +44,24 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); +#if ENABLE(OPENTYPE_SANITIZER) + OpenTypeSanitizer sanitizer(buffer); + RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize(); + if (!transcodeBuffer) + return 0; // validation failed. + buffer = transcodeBuffer.get(); +#endif + ATSFontContainerRef containerRef = 0; ATSFontRef fontRef = 0; + RetainPtr<CGFontRef> cgFontRef; + #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) RetainPtr<CFDataRef> bufferData(AdoptCF, buffer->createCFData()); RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(bufferData.get())); - CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider.get()); + cgFontRef.adoptCF(CGFontCreateWithDataProvider(dataProvider.get())); if (!cgFontRef) return 0; #else @@ -75,13 +86,11 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) return 0; } - CGFontRef cgFontRef = CGFontCreateWithPlatformFont(&fontRef); + cgFontRef.adoptCF(CGFontCreateWithPlatformFont(&fontRef)); #ifndef BUILDING_ON_TIGER // Workaround for <rdar://problem/5675504>. - if (cgFontRef && !CGFontGetNumberOfGlyphs(cgFontRef)) { - CFRelease(cgFontRef); + if (cgFontRef && !CGFontGetNumberOfGlyphs(cgFontRef.get())) cgFontRef = 0; - } #endif if (!cgFontRef) { ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); @@ -89,7 +98,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) } #endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - return new FontCustomPlatformData(containerRef, fontRef, cgFontRef); + return new FontCustomPlatformData(containerRef, fontRef, cgFontRef.releaseRef()); } } diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index df9494a..bb9561e 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -50,10 +50,33 @@ bool Font::canReturnFallbackFontsForComplexText() void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = context->platformContext(); + bool newShouldUseFontSmoothing = shouldUseSmoothing(); + + switch(fontDescription().fontSmoothing()) { + case Antialiased: { + context->setShouldAntialias(true); + newShouldUseFontSmoothing = false; + break; + } + case SubpixelAntialiased: { + context->setShouldAntialias(true); + newShouldUseFontSmoothing = true; + break; + } + case NoSmoothing: { + context->setShouldAntialias(false); + newShouldUseFontSmoothing = false; + break; + } + case AutoSmoothing: { + // For the AutoSmooth case, don't do anything! Keep the default settings. + break; + } + default: + ASSERT_NOT_REACHED(); + } bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext); - bool newShouldUseFontSmoothing = shouldUseSmoothing(); - if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) CGContextSetShouldSmoothFonts(cgContext, newShouldUseFontSmoothing); @@ -92,6 +115,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons IntSize shadowSize; int shadowBlur; Color shadowColor; + ColorSpace fillColorSpace = context->fillColorSpace(); context->getShadow(shadowSize, shadowBlur, shadowColor); bool hasSimpleShadow = context->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; @@ -100,14 +124,14 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons context->clearShadow(); Color fillColor = context->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - context->setFillColor(shadowFillColor); + context->setFillColor(shadowFillColor, fillColorSpace); CGContextSetTextPosition(cgContext, point.x() + shadowSize.width(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } - context->setFillColor(fillColor); + context->setFillColor(fillColor, fillColorSpace); } CGContextSetTextPosition(cgContext, point.x(), point.y()); @@ -118,7 +142,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } if (hasSimpleShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, fillColorSpace); if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing); diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm deleted file mode 100644 index 051abb7..0000000 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006 Apple Computer, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#import "config.h" -#import "Font.h" - -#if USE(ATSUI) - -#import "CharacterNames.h" -#import "GraphicsContext.h" -#import "Logging.h" -#import "ShapeArabic.h" -#import "SimpleFontData.h" -#import <AppKit/NSGraphicsContext.h> -#import <wtf/OwnArrayPtr.h> - -#define SYNTHETIC_OBLIQUE_ANGLE 14 - -#ifdef __LP64__ -#define URefCon void* -#else -#define URefCon UInt32 -#endif - -using namespace std; - -namespace WebCore { - -struct ATSULayoutParameters : Noncopyable -{ - ATSULayoutParameters(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0) - : m_run(run) - , m_font(0) - , m_hasSyntheticBold(false) - , m_syntheticBoldPass(false) - , m_padPerSpace(0) - , m_fallbackFonts(fallbackFonts) - { - } - - ~ATSULayoutParameters() - { - ATSUDisposeTextLayout(m_layout); - } - - void initialize(const Font*, const GraphicsContext* = 0); - - const TextRun& m_run; - - const Font* m_font; - - ATSUTextLayout m_layout; - OwnArrayPtr<const SimpleFontData*> m_fonts; - - OwnArrayPtr<UChar> m_charBuffer; - bool m_hasSyntheticBold; - bool m_syntheticBoldPass; - float m_padPerSpace; - HashSet<const SimpleFontData*>* m_fallbackFonts; -}; - -static TextRun copyRunForDirectionalOverrideIfNecessary(const TextRun& run, OwnArrayPtr<UChar>& charactersWithOverride) -{ - if (!run.directionalOverride()) - return run; - - charactersWithOverride.set(new UChar[run.length() + 2]); - charactersWithOverride[0] = run.rtl() ? rightToLeftOverride : leftToRightOverride; - memcpy(&charactersWithOverride[1], run.data(0), sizeof(UChar) * run.length()); - charactersWithOverride[run.length() + 1] = popDirectionalFormatting; - - TextRun result = run; - result.setText(charactersWithOverride.get(), run.length() + 2); - return result; -} - -static bool fontHasMirroringInfo(ATSUFontID fontID) -{ - ByteCount propTableSize; - OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize); - if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info - return true; - else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error - LOG_ERROR("ATSFontGetTable failed (%d)", status); - - return false; -} - -static void disableLigatures(const SimpleFontData* fontData) -{ - // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are - // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example. - // See bugzilla 5166. - if (fontData->platformData().allowsLigatures()) - return; - - ATSUFontFeatureType featureTypes[] = { kLigaturesType }; - ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector }; - OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors); - if (status != noErr) - LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", status); -} - -static void initializeATSUStyle(const SimpleFontData* fontData) -{ - if (fontData->m_ATSUStyleInitialized) - return; - - ATSUFontID fontID = fontData->platformData().m_atsuFontID; - if (!fontID) { - LOG_ERROR("unable to get ATSUFontID for %@", fontData->platformData().font()); - return; - } - - OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle); - if (status != noErr) - // Who knows how many ATSU functions will crash when passed a NULL style... - LOG_ERROR("ATSUCreateStyle failed (%d)", status); - - CGAffineTransform transform = CGAffineTransformMakeScale(1, -1); - if (fontData->platformData().m_syntheticOblique) - transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); - Fixed fontSize = FloatToFixed(fontData->platformData().m_size); - ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) }; - // Turn off automatic kerning until it is supported in the CG code path (bug 6136) - Fract kerningInhibitFactor = FloatToFract(1.0); - - ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; - ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor }; - status = ATSUSetAttributes(fontData->m_ATSUStyle, 4, styleTags, styleSizes, styleValues); - if (status != noErr) - LOG_ERROR("ATSUSetAttributes failed (%d)", status); - - fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID); - - // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bug 6135 is fixed. - disableLigatures(fontData); - - fontData->m_ATSUStyleInitialized = true; -} - -static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef iLineRef, URefCon iRefCon, void*, ATSULayoutOperationCallbackStatus* oCallbackStatus) -{ - ATSULayoutParameters* params = reinterpret_cast<ATSULayoutParameters*>(iRefCon); - OSStatus status; - ItemCount count; - ATSLayoutRecord *layoutRecords; - - if (params->m_run.applyWordRounding()) { - status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, (void **)&layoutRecords, &count); - if (status != noErr) { - *oCallbackStatus = kATSULayoutOperationCallbackStatusContinue; - return status; - } - - Fixed lastNativePos = 0; - float lastAdjustedPos = 0; - const UChar* characters = params->m_charBuffer ? params->m_charBuffer.get() : params->m_run.characters(); - const SimpleFontData** renderers = params->m_fonts.get(); - const SimpleFontData* renderer; - const SimpleFontData* lastRenderer = 0; - ByteCount offset = layoutRecords[0].originalOffset; - UChar nextCh = *(UChar *)(((char *)characters)+offset); - bool shouldRound = false; - bool syntheticBoldPass = params->m_syntheticBoldPass; - Fixed syntheticBoldOffset = 0; - bool hasExtraSpacing = (params->m_font->letterSpacing() || params->m_font->wordSpacing() || params->m_run.padding()) && !params->m_run.spacingDisabled(); - float padding = params->m_run.padding(); - // In the CoreGraphics code path, the rounding hack is applied in logical order. - // Here it is applied in visual left-to-right order, which may be better. - ItemCount lastRoundingChar = 0; - ItemCount i; - for (i = 1; i < count; i++) { - bool isLastChar = i == count - 1; - renderer = renderers[offset / 2]; - float width; - if (nextCh == zeroWidthSpace || Font::treatAsZeroWidthSpace(nextCh) && !Font::treatAsSpace(nextCh)) { - width = 0; - layoutRecords[i-1].glyphID = renderer->spaceGlyph(); - } else { - width = FixedToFloat(layoutRecords[i].realPos - lastNativePos); - if (renderer != lastRenderer && width) { - lastRenderer = renderer; - // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems - // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI - // does in any of its device-metrics modes. - shouldRound = renderer->platformData().roundsGlyphAdvances(); - if (syntheticBoldPass) - syntheticBoldOffset = FloatToFixed(renderer->syntheticBoldOffset()); - if (params->m_fallbackFonts && renderer != params->m_font->primaryFont()) - params->m_fallbackFonts->add(renderer); - } - if (shouldRound) - width = roundf(width); - width += renderer->syntheticBoldOffset(); - if (renderer->pitch() == FixedPitch ? width == renderer->spaceWidth() : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace)) - width = renderer->adjustedSpaceWidth(); - } - lastNativePos = layoutRecords[i].realPos; - - if (hasExtraSpacing) { - if (width && params->m_font->letterSpacing()) - width +=params->m_font->letterSpacing(); - if (Font::treatAsSpace(nextCh)) { - if (params->m_run.padding()) { - if (padding < params->m_padPerSpace) { - width += padding; - padding = 0; - } else { - width += params->m_padPerSpace; - padding -= params->m_padPerSpace; - } - } - if (offset != 0 && !Font::treatAsSpace(*((UChar *)(((char *)characters)+offset) - 1)) && params->m_font->wordSpacing()) - width += params->m_font->wordSpacing(); - } - } - - UChar ch = nextCh; - offset = layoutRecords[i].originalOffset; - // Use space for nextCh at the end of the loop so that we get inside the rounding hack code. - // We won't actually round unless the other conditions are satisfied. - nextCh = isLastChar ? ' ' : *(UChar *)(((char *)characters)+offset); - - if (Font::isRoundingHackCharacter(ch)) - width = ceilf(width); - lastAdjustedPos = lastAdjustedPos + width; - if (Font::isRoundingHackCharacter(nextCh) && (!isLastChar || params->m_run.applyRunRounding())){ - if (params->m_run.ltr()) - lastAdjustedPos = ceilf(lastAdjustedPos); - else { - float roundingWidth = ceilf(lastAdjustedPos) - lastAdjustedPos; - Fixed rw = FloatToFixed(roundingWidth); - ItemCount j; - for (j = lastRoundingChar; j < i; j++) - layoutRecords[j].realPos += rw; - lastRoundingChar = i; - lastAdjustedPos += roundingWidth; - } - } - if (syntheticBoldPass) { - if (syntheticBoldOffset) - layoutRecords[i-1].realPos += syntheticBoldOffset; - else - layoutRecords[i-1].glyphID = renderer->spaceGlyph(); - } - layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos); - } - - status = ATSUDirectReleaseLayoutDataArrayPtr(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords); - } - *oCallbackStatus = kATSULayoutOperationCallbackStatusHandled; - return noErr; -} - -static inline bool isArabicLamWithAlefLigature(UChar c) -{ - return c >= 0xfef5 && c <= 0xfefc; -} - -static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength, unsigned shapingStart) -{ - while (shapingStart < totalLength) { - unsigned shapingEnd; - // We do not want to pass a Lam with Alef ligature followed by a space to the shaper, - // since we want to be able to identify this sequence as the result of shaping a Lam - // followed by an Alef and padding with a space. - bool foundLigatureSpace = false; - for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd) - foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' '; - shapingEnd++; - - UErrorCode shapingError = U_ZERO_ERROR; - unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError); - - if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) { - for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) { - if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ') - dest[++j] = zeroWidthSpace; - } - if (foundLigatureSpace) { - dest[shapingEnd] = ' '; - shapingEnd++; - } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) { - // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef, - // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR. - ASSERT(dest[shapingStart] == ' '); - dest[shapingStart] = zeroWidthSpace; - } - } else { - // Something went wrong. Abandon shaping and just copy the rest of the buffer. - LOG_ERROR("u_shapeArabic failed(%d)", shapingError); - shapingEnd = totalLength; - memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar)); - } - shapingStart = shapingEnd; - } -} - -void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* graphicsContext) -{ - m_font = font; - - const SimpleFontData* fontData = font->primaryFont(); - m_fonts.set(new const SimpleFontData*[m_run.length()]); - if (font->isSmallCaps()) - m_charBuffer.set(new UChar[m_run.length()]); - - ATSUTextLayout layout; - OSStatus status; - ATSULayoutOperationOverrideSpecifier overrideSpecifier; - - initializeATSUStyle(fontData); - - // FIXME: This is currently missing the following required features that the CoreGraphics code path has: - // - \n, \t, and nonbreaking space render as a space. - - UniCharCount runLength = m_run.length(); - - if (m_charBuffer) - memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar)); - - status = ATSUCreateTextLayoutWithTextPtr( - (m_charBuffer ? m_charBuffer.get() : m_run.characters()), - 0, // offset - runLength, // length - runLength, // total length - 1, // styleRunCount - &runLength, // length of style run - &fontData->m_ATSUStyle, - &layout); - if (status != noErr) - LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed(%d)", status); - m_layout = layout; - ATSUSetTextLayoutRefCon(m_layout, (URefCon)this); - - // FIXME: There are certain times when this method is called, when we don't have access to a GraphicsContext - // measuring text runs with floatWidthForComplexText is one example. - // ATSUI requires that we pass a valid CGContextRef to it when specifying kATSUCGContextTag (crashes when passed 0) - // ATSUI disables sub-pixel rendering if kATSUCGContextTag is not specified! So we're in a bind. - // Sometimes [[NSGraphicsContext currentContext] graphicsPort] may return the wrong (or no!) context. Nothing we can do about it (yet). - CGContextRef cgContext = graphicsContext ? graphicsContext->platformContext() : (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - - ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers; - Boolean rtl = m_run.rtl(); - overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment; - overrideSpecifier.overrideUPP = overrideLayoutOperation; - ATSUAttributeTag tags[] = { kATSUCGContextTag, kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag }; - ByteCount sizes[] = { sizeof(CGContextRef), sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) }; - ATSUAttributeValuePtr values[] = { &cgContext, &lineLayoutOptions, &rtl, &overrideSpecifier }; - - status = ATSUSetLayoutControls(layout, (m_run.applyWordRounding() ? 4 : 3), tags, sizes, values); - if (status != noErr) - LOG_ERROR("ATSUSetLayoutControls failed(%d)", status); - - status = ATSUSetTransientFontMatching(layout, YES); - if (status != noErr) - LOG_ERROR("ATSUSetTransientFontMatching failed(%d)", status); - - m_hasSyntheticBold = false; - ATSUFontID ATSUSubstituteFont; - UniCharArrayOffset substituteOffset = 0; - UniCharCount substituteLength; - UniCharArrayOffset lastOffset; - const SimpleFontData* substituteFontData = 0; - - while (substituteOffset < runLength) { - // FIXME: Using ATSUMatchFontsToText() here results in several problems: the CSS font family list is not necessarily followed for the 2nd - // and onwards unmatched characters; segmented fonts do not work correctly; behavior does not match the simple text and Uniscribe code - // paths. Change this function to use Font::glyphDataForCharacter() for each character instead. - lastOffset = substituteOffset; - status = ATSUMatchFontsToText(layout, substituteOffset, kATSUToTextEnd, &ATSUSubstituteFont, &substituteOffset, &substituteLength); - if (status == kATSUFontsMatched || status == kATSUFontsNotMatched) { - const FontData* fallbackFontData = m_font->fontDataForCharacters(m_run.characters() + substituteOffset, substituteLength); - substituteFontData = fallbackFontData ? fallbackFontData->fontDataForCharacter(m_run[0]) : 0; - if (substituteFontData) { - initializeATSUStyle(substituteFontData); - if (substituteFontData->m_ATSUStyle) - ATSUSetRunStyle(layout, substituteFontData->m_ATSUStyle, substituteOffset, substituteLength); - } else - substituteFontData = fontData; - } else { - substituteOffset = runLength; - substituteLength = 0; - } - - bool shapedArabic = false; - bool isSmallCap = false; - UniCharArrayOffset firstSmallCap = 0; - const SimpleFontData *r = fontData; - UniCharArrayOffset i; - for (i = lastOffset; ; i++) { - if (i == substituteOffset || i == substituteOffset + substituteLength) { - if (isSmallCap) { - isSmallCap = false; - initializeATSUStyle(r->smallCapsFontData(m_font->fontDescription())); - ATSUSetRunStyle(layout, r->smallCapsFontData(m_font->fontDescription())->m_ATSUStyle, firstSmallCap, i - firstSmallCap); - } - if (i == substituteOffset && substituteLength > 0) - r = substituteFontData; - else - break; - } - if (!shapedArabic && WTF::Unicode::isArabicChar(m_run[i]) && !r->shapesArabic()) { - shapedArabic = true; - if (!m_charBuffer) { - m_charBuffer.set(new UChar[runLength]); - memcpy(m_charBuffer.get(), m_run.characters(), i * sizeof(UChar)); - ATSUTextMoved(layout, m_charBuffer.get()); - } - shapeArabic(m_run.characters(), m_charBuffer.get(), runLength, i); - } - if (m_run.rtl() && !r->m_ATSUMirrors) { - UChar mirroredChar = u_charMirror(m_run[i]); - if (mirroredChar != m_run[i]) { - if (!m_charBuffer) { - m_charBuffer.set(new UChar[runLength]); - memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar)); - ATSUTextMoved(layout, m_charBuffer.get()); - } - m_charBuffer[i] = mirroredChar; - } - } - if (m_font->isSmallCaps()) { - const SimpleFontData* smallCapsData = r->smallCapsFontData(m_font->fontDescription()); - UChar c = m_charBuffer[i]; - UChar newC; - if (U_GET_GC_MASK(c) & U_GC_M_MASK) - m_fonts[i] = isSmallCap ? smallCapsData : r; - else if (!u_isUUppercase(c) && (newC = u_toupper(c)) != c) { - m_charBuffer[i] = newC; - if (!isSmallCap) { - isSmallCap = true; - firstSmallCap = i; - } - m_fonts[i] = smallCapsData; - } else { - if (isSmallCap) { - isSmallCap = false; - initializeATSUStyle(smallCapsData); - ATSUSetRunStyle(layout, smallCapsData->m_ATSUStyle, firstSmallCap, i - firstSmallCap); - } - m_fonts[i] = r; - } - } else - m_fonts[i] = r; - if (m_fonts[i]->syntheticBoldOffset()) - m_hasSyntheticBold = true; - } - substituteOffset += substituteLength; - } - if (m_run.padding()) { - float numSpaces = 0; - unsigned k; - for (k = 0; k < runLength; k++) - if (Font::treatAsSpace(m_run[k])) - numSpaces++; - - if (numSpaces == 0) - m_padPerSpace = 0; - else - m_padPerSpace = ceilf(m_run.padding() / numSpaces); - } else - m_padPerSpace = 0; -} - -FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const -{ - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - if (run.directionalOverride()) { - from++; - to++; - } - - ATSULayoutParameters params(adjustedRun); - params.initialize(this); - - ATSTrapezoid firstGlyphBounds; - ItemCount actualNumBounds; - - OSStatus status = ATSUGetGlyphBounds(params.m_layout, 0, 0, from, to - from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds); - if (status != noErr || actualNumBounds != 1) { - static ATSTrapezoid zeroTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; - firstGlyphBounds = zeroTrapezoid; - } - - float beforeWidth = MIN(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x)); - float afterWidth = MAX(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x)); - - FloatRect rect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); - - return rect; -} - -void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, const FloatPoint& point, int from, int to) const -{ - OSStatus status; - - int drawPortionLength = to - from; - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - if (run.directionalOverride()) - from++; - - ATSULayoutParameters params(adjustedRun); - params.initialize(this, graphicsContext); - - // ATSUI can't draw beyond -32768 to +32767 so we translate the CTM and tell ATSUI to draw at (0, 0). - CGContextRef context = graphicsContext->platformContext(); - CGContextTranslateCTM(context, point.x(), point.y()); - - IntSize shadowSize; - int shadowBlur; - Color shadowColor; - graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor); - - bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; - if (hasSimpleShadow) { - // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. - graphicsContext->clearShadow(); - Color fillColor = graphicsContext->fillColor(); - Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - graphicsContext->setFillColor(shadowFillColor); - CGContextTranslateCTM(context, shadowSize.width(), shadowSize.height()); - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - if (status == noErr && params.m_hasSyntheticBold) { - // Force relayout for the bold pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = true; - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - // Force relayout for the next pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = false; - } - CGContextTranslateCTM(context, -shadowSize.width(), -shadowSize.height()); - graphicsContext->setFillColor(fillColor); - } - - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - if (status == noErr && params.m_hasSyntheticBold) { - // Force relayout for the bold pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = true; - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - } - CGContextTranslateCTM(context, -point.x(), -point.y()); - - if (status != noErr) - // Nothing to do but report the error (dev build only). - LOG_ERROR("ATSUDrawText() failed(%d)", status); - - if (hasSimpleShadow) - graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); -} - -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const -{ - if (run.length() == 0) - return 0; - - ATSULayoutParameters params(run, fallbackFonts); - params.initialize(this); - - OSStatus status; - - ATSTrapezoid firstGlyphBounds; - ItemCount actualNumBounds; - status = ATSUGetGlyphBounds(params.m_layout, 0, 0, 0, run.length(), kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds); - if (status != noErr) - LOG_ERROR("ATSUGetGlyphBounds() failed(%d)", status); - if (actualNumBounds != 1) - LOG_ERROR("unexpected result from ATSUGetGlyphBounds(): actualNumBounds(%d) != 1", actualNumBounds); - - return MAX(FixedToFloat(firstGlyphBounds.upperRight.x), FixedToFloat(firstGlyphBounds.lowerRight.x)) - - MIN(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x)); -} - -int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool /*includePartialGlyphs*/) const -{ - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - - ATSULayoutParameters params(adjustedRun); - params.initialize(this); - - UniCharArrayOffset primaryOffset = 0; - - // FIXME: No idea how to avoid including partial glyphs. - // Not even sure if that's the behavior this yields now. - Boolean isLeading; - UniCharArrayOffset secondaryOffset = 0; - OSStatus status = ATSUPositionToOffset(params.m_layout, FloatToFixed(x), FloatToFixed(-1), &primaryOffset, &isLeading, &secondaryOffset); - unsigned offset; - if (status == noErr) { - offset = (unsigned)primaryOffset; - if (run.directionalOverride() && offset > 0) - offset--; - } else - // Failed to find offset! Return 0 offset. - offset = 0; - - return offset; -} - -} -#endif // USE(ATSUI) diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp new file mode 100644 index 0000000..41f63a9 --- /dev/null +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -0,0 +1,1365 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) + +#include "GraphicsContext3D.h" + +#include "CachedImage.h" +#include "WebGLActiveInfo.h" +#include "WebGLArray.h" +#include "WebGLBuffer.h" +#include "WebGLFramebuffer.h" +#include "WebGLFloatArray.h" +#include "WebGLIntArray.h" +#include "CanvasObject.h" +#include "WebGLProgram.h" +#include "WebGLRenderbuffer.h" +#include "WebGLShader.h" +#include "WebGLTexture.h" +#include "WebGLUnsignedByteArray.h" +#include "CString.h" +#include "HTMLCanvasElement.h" +#include "HTMLImageElement.h" +#include "ImageBuffer.h" +#include "NotImplemented.h" +#include "WebKitCSSMatrix.h" + +#include <CoreGraphics/CGBitmapContext.h> +#include <OpenGL/CGLRenderers.h> + +namespace WebCore { + +static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest) +{ + attribs.clear(); + + attribs.append(kCGLPFAColorSize); + attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits)); + attribs.append(kCGLPFADepthSize); + attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits)); + + if (accelerated) + attribs.append(kCGLPFAAccelerated); + else { + attribs.append(kCGLPFARendererID); + attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID)); + } + + if (supersample) + attribs.append(kCGLPFASupersample); + + if (closest) + attribs.append(kCGLPFAClosestPolicy); + + attribs.append(static_cast<CGLPixelFormatAttribute>(0)); +} + +PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create() +{ + OwnPtr<GraphicsContext3D> context(new GraphicsContext3D()); + return context->m_contextObj ? context.release() : 0; +} + +GraphicsContext3D::GraphicsContext3D() + : m_contextObj(0) + , m_texture(0) + , m_fbo(0) + , m_depthBuffer(0) +{ + Vector<CGLPixelFormatAttribute> attribs; + CGLPixelFormatObj pixelFormatObj = 0; + GLint numPixelFormats = 0; + + // We will try: + // + // 1) 32 bit RGBA/32 bit depth/accelerated/supersampled + // 2) 32 bit RGBA/32 bit depth/accelerated + // 3) 32 bit RGBA/16 bit depth/accelerated + // 4) closest to 32 bit RGBA/16 bit depth/software renderer + // + // If none of that works, we simply fail and set m_contextObj to 0. + + setPixelFormat(attribs, 32, 32, true, true, false); + CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); + if (numPixelFormats == 0) { + setPixelFormat(attribs, 32, 32, true, false, false); + CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); + + if (numPixelFormats == 0) { + setPixelFormat(attribs, 32, 16, true, false, false); + CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); + + if (numPixelFormats == 0) { + setPixelFormat(attribs, 32, 16, false, false, true); + CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); + + if (numPixelFormats == 0) { + // Could not find an acceptable renderer - fail + return; + } + } + } + } + + CGLError err = CGLCreateContext(pixelFormatObj, 0, &m_contextObj); + CGLDestroyPixelFormat(pixelFormatObj); + + if (err != kCGLNoError || !m_contextObj) { + // Could not create the context - fail + m_contextObj = 0; + return; + } + + // Set the current context to the one given to us. + CGLSetCurrentContext(m_contextObj); + + // 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); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + ::glBindTexture(GL_TEXTURE_2D, 0); + + // create an FBO + ::glGenFramebuffersEXT(1, &m_fbo); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + + ::glGenRenderbuffersEXT(1, &m_depthBuffer); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer); + ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 1, 1); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + + ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer); + + ::glClearColor(0, 0, 0, 0); +} + +GraphicsContext3D::~GraphicsContext3D() +{ + if (m_contextObj) { + CGLSetCurrentContext(m_contextObj); + ::glDeleteRenderbuffersEXT(1, & m_depthBuffer); + ::glDeleteTextures(1, &m_texture); + ::glDeleteFramebuffersEXT(1, &m_fbo); + CGLSetCurrentContext(0); + CGLDestroyContext(m_contextObj); + } +} + +void GraphicsContext3D::makeContextCurrent() +{ + CGLSetCurrentContext(m_contextObj); +} + +void GraphicsContext3D::beginPaint(WebGLRenderingContext* context) +{ + UNUSED_PARAM(context); +} + +void GraphicsContext3D::endPaint() +{ +} + +void GraphicsContext3D::reshape(int width, int height) +{ + if (width == m_currentWidth && height == m_currentHeight || !m_contextObj) + return; + + m_currentWidth = width; + m_currentHeight = height; + + CGLSetCurrentContext(m_contextObj); + + ::glBindTexture(GL_TEXTURE_2D, m_texture); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + ::glBindTexture(GL_TEXTURE_2D, 0); + + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer); + ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + + ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer); + GLenum status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + // FIXME: cleanup + notImplemented(); + } + + ::glViewport(0, 0, m_currentWidth, m_currentHeight); + ::glClear(GL_COLOR_BUFFER_BIT); + ::glFlush(); +} + +static inline void ensureContext(CGLContextObj context) +{ + if (!context) + return; + + CGLContextObj currentContext = CGLGetCurrentContext(); + if (currentContext != context) + CGLSetCurrentContext(context); +} + +void GraphicsContext3D::activeTexture(unsigned long texture) +{ + ensureContext(m_contextObj); + ::glActiveTexture(texture); +} + +void GraphicsContext3D::attachShader(WebGLProgram* program, WebGLShader* shader) +{ + ASSERT(program); + ASSERT(shader); + ensureContext(m_contextObj); + ::glAttachShader((GLuint) program->object(), (GLuint) shader->object()); +} + +void GraphicsContext3D::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name) +{ + ASSERT(program); + ensureContext(m_contextObj); + ::glBindAttribLocation((GLuint) program->object(), index, name.utf8().data()); +} + +void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer) +{ + ensureContext(m_contextObj); + ::glBindBuffer(target, buffer ? (GLuint) buffer->object() : 0); +} + + +void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer) +{ + ensureContext(m_contextObj); + ::glBindFramebufferEXT(target, buffer ? (GLuint) buffer->object() : m_fbo); +} + +void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer) +{ + ensureContext(m_contextObj); + ::glBindRenderbufferEXT(target, renderbuffer ? (GLuint) renderbuffer->object() : 0); +} + + +void GraphicsContext3D::bindTexture(unsigned long target, WebGLTexture* texture) +{ + ensureContext(m_contextObj); + ::glBindTexture(target, texture ? (GLuint) texture->object() : 0); +} + +void GraphicsContext3D::blendColor(double red, double green, double blue, double alpha) +{ + ensureContext(m_contextObj); + ::glBlendColor(static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue), static_cast<float>(alpha)); +} + +void GraphicsContext3D::blendEquation( unsigned long mode ) +{ + ensureContext(m_contextObj); + ::glBlendEquation(mode); +} + +void GraphicsContext3D::blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha) +{ + ensureContext(m_contextObj); + ::glBlendEquationSeparate(modeRGB, modeAlpha); +} + + +void GraphicsContext3D::blendFunc(unsigned long sfactor, unsigned long dfactor) +{ + ensureContext(m_contextObj); + ::glBlendFunc(sfactor, dfactor); +} + +void GraphicsContext3D::blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha) +{ + ensureContext(m_contextObj); + ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long usage) +{ + ensureContext(m_contextObj); + ::glBufferData(target, size, 0, usage); +} +void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage) +{ + if (!array || !array->length()) + return; + + ensureContext(m_contextObj); + ::glBufferData(target, array->byteLength(), array->baseAddress(), usage); +} + +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array) +{ + if (!array || !array->length()) + return; + + ensureContext(m_contextObj); + ::glBufferSubData(target, offset, array->byteLength(), array->baseAddress()); +} + +unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target) +{ + ensureContext(m_contextObj); + return ::glCheckFramebufferStatusEXT(target); +} + +void GraphicsContext3D::clearColor(double r, double g, double b, double a) +{ + ensureContext(m_contextObj); + ::glClearColor(static_cast<float>(r), static_cast<float>(g), static_cast<float>(b), static_cast<float>(a)); +} + +void GraphicsContext3D::clear(unsigned long mask) +{ + ensureContext(m_contextObj); + ::glClear(mask); +} + +void GraphicsContext3D::clearDepth(double depth) +{ + ensureContext(m_contextObj); + ::glClearDepth(depth); +} + +void GraphicsContext3D::clearStencil(long s) +{ + ensureContext(m_contextObj); + ::glClearStencil(s); +} + +void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha) +{ + ensureContext(m_contextObj); + ::glColorMask(red, green, blue, alpha); +} + +void GraphicsContext3D::compileShader(WebGLShader* shader) +{ + ASSERT(shader); + ensureContext(m_contextObj); + ::glCompileShader((GLuint) shader->object()); +} + +void GraphicsContext3D::copyTexImage2D(unsigned long target, long level, unsigned long internalformat, long x, long y, unsigned long width, unsigned long height, long border) +{ + ensureContext(m_contextObj); + ::glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); +} + +void GraphicsContext3D::copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, unsigned long width, unsigned long height) +{ + ensureContext(m_contextObj); + ::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); +} + +void GraphicsContext3D::cullFace(unsigned long mode) +{ + ensureContext(m_contextObj); + ::glCullFace(mode); +} + +void GraphicsContext3D::depthFunc(unsigned long func) +{ + ensureContext(m_contextObj); + ::glDepthFunc(func); +} + +void GraphicsContext3D::depthMask(bool flag) +{ + ensureContext(m_contextObj); + ::glDepthMask(flag); +} + +void GraphicsContext3D::depthRange(double zNear, double zFar) +{ + ensureContext(m_contextObj); + ::glDepthRange(zNear, zFar); +} + +void GraphicsContext3D::detachShader(WebGLProgram* program, WebGLShader* shader) +{ + ASSERT(program); + ASSERT(shader); + ensureContext(m_contextObj); + ::glDetachShader((GLuint) program->object(), (GLuint) shader->object()); +} + +void GraphicsContext3D::disable(unsigned long cap) +{ + ensureContext(m_contextObj); + ::glDisable(cap); +} + +void GraphicsContext3D::disableVertexAttribArray(unsigned long index) +{ + ensureContext(m_contextObj); + ::glDisableVertexAttribArray(index); +} + +void GraphicsContext3D::drawArrays(unsigned long mode, long first, long count) +{ + ensureContext(m_contextObj); + ::glDrawArrays(mode, first, count); +} + +void GraphicsContext3D::drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset) +{ + ensureContext(m_contextObj); + ::glDrawElements(mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::enable(unsigned long cap) +{ + ensureContext(m_contextObj); + ::glEnable(cap); +} + +void GraphicsContext3D::enableVertexAttribArray(unsigned long index) +{ + ensureContext(m_contextObj); + ::glEnableVertexAttribArray(index); +} + +void GraphicsContext3D::finish() +{ + ensureContext(m_contextObj); + ::glFinish(); +} + +void GraphicsContext3D::flush() +{ + ensureContext(m_contextObj); + ::glFlush(); +} + +void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer) +{ + ensureContext(m_contextObj); + ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer ? (GLuint) buffer->object() : 0); +} + +void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level) +{ + ensureContext(m_contextObj); + ::glFramebufferTexture2DEXT(target, attachment, textarget, texture ? (GLuint) texture->object() : 0, level); +} + +void GraphicsContext3D::frontFace(unsigned long mode) +{ + ensureContext(m_contextObj); + ::glFrontFace(mode); +} + +void GraphicsContext3D::generateMipmap(unsigned long target) +{ + ensureContext(m_contextObj); + ::glGenerateMipmapEXT(target); +} + +bool GraphicsContext3D::getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo& info) +{ + if (!program->object()) { + synthesizeGLError(INVALID_VALUE); + return false; + } + ensureContext(m_contextObj); + GLint maxAttributeSize = 0; + ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize); + GLchar name[maxAttributeSize]; // GL_ACTIVE_ATTRIBUTE_MAX_LENGTH includes null termination + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + ::glGetActiveAttrib(static_cast<GLuint>(program->object()), index, maxAttributeSize, &nameLength, &size, &type, name); + if (!nameLength) + return false; + info.name = String(name, nameLength); + info.type = type; + info.size = size; + return true; +} + +bool GraphicsContext3D::getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo& info) +{ + if (!program->object()) { + synthesizeGLError(INVALID_VALUE); + return false; + } + ensureContext(m_contextObj); + GLint maxUniformSize = 0; + ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize); + GLchar name[maxUniformSize]; // GL_ACTIVE_UNIFORM_MAX_LENGTH includes null termination + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + ::glGetActiveUniform(static_cast<GLuint>(program->object()), index, maxUniformSize, &nameLength, &size, &type, name); + if (!nameLength) + return false; + info.name = String(name, nameLength); + info.type = type; + info.size = size; + return true; +} + +int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& name) +{ + if (!program) + return -1; + + ensureContext(m_contextObj); + return ::glGetAttribLocation((GLuint) program->object(), name.utf8().data()); +} + +unsigned long GraphicsContext3D::getError() +{ + if (m_syntheticErrors.size() > 0) { + ListHashSet<unsigned long>::iterator iter = m_syntheticErrors.begin(); + unsigned long err = *iter; + m_syntheticErrors.remove(iter); + return err; + } + + ensureContext(m_contextObj); + return ::glGetError(); +} + +String GraphicsContext3D::getString(unsigned long name) +{ + ensureContext(m_contextObj); + return String((const char*) ::glGetString(name)); +} + +void GraphicsContext3D::hint(unsigned long target, unsigned long mode) +{ + ensureContext(m_contextObj); + ::glHint(target, mode); +} + +bool GraphicsContext3D::isBuffer(WebGLBuffer* buffer) +{ + if (!buffer) + return false; + + ensureContext(m_contextObj); + return ::glIsBuffer((GLuint) buffer->object()); +} + +bool GraphicsContext3D::isEnabled(unsigned long cap) +{ + ensureContext(m_contextObj); + return ::glIsEnabled(cap); +} + +bool GraphicsContext3D::isFramebuffer(WebGLFramebuffer* framebuffer) +{ + if (!framebuffer) + return false; + + ensureContext(m_contextObj); + return ::glIsFramebufferEXT((GLuint) framebuffer->object()); +} + +bool GraphicsContext3D::isProgram(WebGLProgram* program) +{ + if (!program) + return false; + + ensureContext(m_contextObj); + return ::glIsProgram((GLuint) program->object()); +} + +bool GraphicsContext3D::isRenderbuffer(WebGLRenderbuffer* renderbuffer) +{ + if (!renderbuffer) + return false; + + ensureContext(m_contextObj); + return ::glIsRenderbufferEXT((GLuint) renderbuffer->object()); +} + +bool GraphicsContext3D::isShader(WebGLShader* shader) +{ + if (!shader) + return false; + + ensureContext(m_contextObj); + return ::glIsShader((GLuint) shader->object()); +} + +bool GraphicsContext3D::isTexture(WebGLTexture* texture) +{ + if (!texture) + return false; + + ensureContext(m_contextObj); + return ::glIsTexture((GLuint) texture->object()); +} + +void GraphicsContext3D::lineWidth(double width) +{ + ensureContext(m_contextObj); + ::glLineWidth(static_cast<float>(width)); +} + +void GraphicsContext3D::linkProgram(WebGLProgram* program) +{ + ASSERT(program); + ensureContext(m_contextObj); + ::glLinkProgram((GLuint) program->object()); +} + +void GraphicsContext3D::pixelStorei(unsigned long pname, long param) +{ + ensureContext(m_contextObj); + ::glPixelStorei(pname, param); +} + +void GraphicsContext3D::polygonOffset(double factor, double units) +{ + ensureContext(m_contextObj); + ::glPolygonOffset(static_cast<float>(factor), static_cast<float>(units)); +} + +PassRefPtr<WebGLArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type) +{ + ensureContext(m_contextObj); + + // FIXME: For now we only accept GL_UNSIGNED_BYTE/GL_RGBA. In reality OpenGL ES 2.0 accepts that pair and one other + // as specified by GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE. But for now we will + // not accept those. + // FIXME: Also, we should throw when an unacceptable value is passed + if (type != GL_UNSIGNED_BYTE || format != GL_RGBA) + return 0; + + RefPtr<WebGLUnsignedByteArray> array = WebGLUnsignedByteArray::create(width * height * 4); + ::glReadPixels(x, y, width, height, format, type, (GLvoid*) array->data()); + return array; +} + +void GraphicsContext3D::releaseShaderCompiler() +{ + // FIXME: This is not implemented on desktop OpenGL. We need to have ifdefs for the different GL variants + ensureContext(m_contextObj); + //::glReleaseShaderCompiler(); +} + +void GraphicsContext3D::renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height) +{ + ensureContext(m_contextObj); + ::glRenderbufferStorageEXT(target, internalformat, width, height); +} + +void GraphicsContext3D::sampleCoverage(double value, bool invert) +{ + ensureContext(m_contextObj); + ::glSampleCoverage(static_cast<float>(value), invert); +} + +void GraphicsContext3D::scissor(long x, long y, unsigned long width, unsigned long height) +{ + ensureContext(m_contextObj); + ::glScissor(x, y, width, height); +} + +void GraphicsContext3D::shaderSource(WebGLShader* shader, const String& string) +{ + ASSERT(shader); + + ensureContext(m_contextObj); + const CString& cs = string.utf8(); + const char* s = cs.data(); + + int length = string.length(); + ::glShaderSource((GLuint) shader->object(), 1, &s, &length); +} + +void GraphicsContext3D::stencilFunc(unsigned long func, long ref, unsigned long mask) +{ + ensureContext(m_contextObj); + ::glStencilFunc(func, ref, mask); +} + +void GraphicsContext3D::stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask) +{ + ensureContext(m_contextObj); + ::glStencilFuncSeparate(face, func, ref, mask); +} + +void GraphicsContext3D::stencilMask(unsigned long mask) +{ + ensureContext(m_contextObj); + ::glStencilMask(mask); +} + +void GraphicsContext3D::stencilMaskSeparate(unsigned long face, unsigned long mask) +{ + ensureContext(m_contextObj); + ::glStencilMaskSeparate(face, mask); +} + +void GraphicsContext3D::stencilOp(unsigned long fail, unsigned long zfail, unsigned long zpass) +{ + ensureContext(m_contextObj); + ::glStencilOp(fail, zfail, zpass); +} + +void GraphicsContext3D::stencilOpSeparate(unsigned long face, unsigned long fail, unsigned long zfail, unsigned long zpass) +{ + ensureContext(m_contextObj); + ::glStencilOpSeparate(face, fail, zfail, zpass); +} + +void GraphicsContext3D::texParameterf(unsigned target, unsigned pname, float value) +{ + ensureContext(m_contextObj); + ::glTexParameterf(target, pname, static_cast<float>(value)); +} + +void GraphicsContext3D::texParameteri(unsigned target, unsigned pname, int value) +{ + ensureContext(m_contextObj); + ::glTexParameteri(target, pname, static_cast<float>(value)); +} + +void GraphicsContext3D::uniform1f(long location, float v0) +{ + ensureContext(m_contextObj); + ::glUniform1f(location, v0); +} + +void GraphicsContext3D::uniform1fv(long location, float* array, int size) +{ + ensureContext(m_contextObj); + ::glUniform1fv(location, size, array); +} + +void GraphicsContext3D::uniform2f(long location, float v0, float v1) +{ + ensureContext(m_contextObj); + ::glUniform2f(location, v0, v1); +} + +void GraphicsContext3D::uniform2fv(long location, float* array, int size) +{ + // FIXME: length needs to be a multiple of 2 + ensureContext(m_contextObj); + ::glUniform2fv(location, size, array); +} + +void GraphicsContext3D::uniform3f(long location, float v0, float v1, float v2) +{ + ensureContext(m_contextObj); + ::glUniform3f(location, v0, v1, v2); +} + +void GraphicsContext3D::uniform3fv(long location, float* array, int size) +{ + // FIXME: length needs to be a multiple of 3 + ensureContext(m_contextObj); + ::glUniform3fv(location, size, array); +} + +void GraphicsContext3D::uniform4f(long location, float v0, float v1, float v2, float v3) +{ + ensureContext(m_contextObj); + ::glUniform4f(location, v0, v1, v2, v3); +} + +void GraphicsContext3D::uniform4fv(long location, float* array, int size) +{ + // FIXME: length needs to be a multiple of 4 + ensureContext(m_contextObj); + ::glUniform4fv(location, size, array); +} + +void GraphicsContext3D::uniform1i(long location, int v0) +{ + ensureContext(m_contextObj); + ::glUniform1i(location, v0); +} + +void GraphicsContext3D::uniform1iv(long location, int* array, int size) +{ + ensureContext(m_contextObj); + ::glUniform1iv(location, size, array); +} + +void GraphicsContext3D::uniform2i(long location, int v0, int v1) +{ + ensureContext(m_contextObj); + ::glUniform2i(location, v0, v1); +} + +void GraphicsContext3D::uniform2iv(long location, int* array, int size) +{ + // FIXME: length needs to be a multiple of 2 + ensureContext(m_contextObj); + ::glUniform2iv(location, size, array); +} + +void GraphicsContext3D::uniform3i(long location, int v0, int v1, int v2) +{ + ensureContext(m_contextObj); + ::glUniform3i(location, v0, v1, v2); +} + +void GraphicsContext3D::uniform3iv(long location, int* array, int size) +{ + // FIXME: length needs to be a multiple of 3 + ensureContext(m_contextObj); + ::glUniform3iv(location, size, array); +} + +void GraphicsContext3D::uniform4i(long location, int v0, int v1, int v2, int v3) +{ + ensureContext(m_contextObj); + ::glUniform4i(location, v0, v1, v2, v3); +} + +void GraphicsContext3D::uniform4iv(long location, int* array, int size) +{ + // FIXME: length needs to be a multiple of 4 + ensureContext(m_contextObj); + ::glUniform4iv(location, size, array); +} + +void GraphicsContext3D::uniformMatrix2fv(long location, bool transpose, float* array, int size) +{ + // FIXME: length needs to be a multiple of 4 + ensureContext(m_contextObj); + ::glUniformMatrix2fv(location, size, transpose, array); +} + +void GraphicsContext3D::uniformMatrix3fv(long location, bool transpose, float* array, int size) +{ + // FIXME: length needs to be a multiple of 9 + ensureContext(m_contextObj); + ::glUniformMatrix3fv(location, size, transpose, array); +} + +void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* array, int size) +{ + // FIXME: length needs to be a multiple of 16 + ensureContext(m_contextObj); + ::glUniformMatrix4fv(location, size, transpose, array); +} + +void GraphicsContext3D::useProgram(WebGLProgram* program) +{ + ASSERT(program); + + ensureContext(m_contextObj); + ::glUseProgram((GLuint) program->object()); +} + +void GraphicsContext3D::validateProgram(WebGLProgram* program) +{ + ASSERT(program); + + ensureContext(m_contextObj); + ::glValidateProgram((GLuint) program->object()); +} + +void GraphicsContext3D::vertexAttrib1f(unsigned long indx, float v0) +{ + ensureContext(m_contextObj); + ::glVertexAttrib1f(indx, v0); +} + +void GraphicsContext3D::vertexAttrib1fv(unsigned long indx, float* array) +{ + ensureContext(m_contextObj); + ::glVertexAttrib1fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib2f(unsigned long indx, float v0, float v1) +{ + ensureContext(m_contextObj); + ::glVertexAttrib2f(indx, v0, v1); +} + +void GraphicsContext3D::vertexAttrib2fv(unsigned long indx, float* array) +{ + ensureContext(m_contextObj); + ::glVertexAttrib2fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib3f(unsigned long indx, float v0, float v1, float v2) +{ + ensureContext(m_contextObj); + ::glVertexAttrib3f(indx, v0, v1, v2); +} + +void GraphicsContext3D::vertexAttrib3fv(unsigned long indx, float* array) +{ + ensureContext(m_contextObj); + ::glVertexAttrib3fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib4f(unsigned long indx, float v0, float v1, float v2, float v3) +{ + ensureContext(m_contextObj); + ::glVertexAttrib4f(indx, v0, v1, v2, v3); +} + +void GraphicsContext3D::vertexAttrib4fv(unsigned long indx, float* array) +{ + ensureContext(m_contextObj); + ::glVertexAttrib4fv(indx, array); +} + +void GraphicsContext3D::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, unsigned long stride, unsigned long offset) +{ + ensureContext(m_contextObj); + ::glVertexAttribPointer(indx, size, type, normalized, stride, reinterpret_cast<void*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::viewport(long x, long y, unsigned long width, unsigned long height) +{ + ensureContext(m_contextObj); + ::glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height)); +} + +void GraphicsContext3D::getBooleanv(unsigned long pname, unsigned char* value) +{ + ensureContext(m_contextObj); + ::glGetBooleanv(pname, value); +} + +void GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname, int* value) +{ + ensureContext(m_contextObj); + ::glGetBufferParameteriv(target, pname, value); +} + +void GraphicsContext3D::getFloatv(unsigned long pname, float* value) +{ + ensureContext(m_contextObj); + ::glGetFloatv(pname, value); +} + +void GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value) +{ + ensureContext(m_contextObj); + ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value); +} + +void GraphicsContext3D::getIntegerv(unsigned long pname, int* value) +{ + ensureContext(m_contextObj); + ::glGetIntegerv(pname, value); +} + +void GraphicsContext3D::getProgramiv(WebGLProgram* program, unsigned long pname, int* value) +{ + ensureContext(m_contextObj); + ::glGetProgramiv((GLuint) program->object(), pname, value); +} + +String GraphicsContext3D::getProgramInfoLog(WebGLProgram* program) +{ + ASSERT(program); + + ensureContext(m_contextObj); + GLint length; + ::glGetProgramiv((GLuint) program->object(), GL_INFO_LOG_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + + ::glGetProgramInfoLog((GLuint) program->object(), length, &size, info); + String s(info); + fastFree(info); + return s; +} + +void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname, int* value) +{ + ensureContext(m_contextObj); + ::glGetRenderbufferParameterivEXT(target, pname, value); +} + +void GraphicsContext3D::getShaderiv(WebGLShader* shader, unsigned long pname, int* value) +{ + ASSERT(shader); + + ensureContext(m_contextObj); + ::glGetShaderiv((GLuint) shader->object(), pname, value); +} + +String GraphicsContext3D::getShaderInfoLog(WebGLShader* shader) +{ + ASSERT(shader); + + ensureContext(m_contextObj); + GLint length; + ::glGetShaderiv((GLuint) shader->object(), GL_INFO_LOG_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + + ::glGetShaderInfoLog((GLuint) shader->object(), length, &size, info); + String s(info); + fastFree(info); + return s; +} + +String GraphicsContext3D::getShaderSource(WebGLShader* shader) +{ + ASSERT(shader); + + ensureContext(m_contextObj); + GLint length; + ::glGetShaderiv((GLuint) shader->object(), GL_SHADER_SOURCE_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + + ::glGetShaderSource((GLuint) shader->object(), length, &size, info); + String s(info); + fastFree(info); + return s; +} + + +void GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname, float* value) +{ + ensureContext(m_contextObj); + ::glGetTexParameterfv(target, pname, value); +} + +void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname, int* value) +{ + ensureContext(m_contextObj); + ::glGetTexParameteriv(target, pname, value); +} + +void GraphicsContext3D::getUniformfv(WebGLProgram* program, long location, float* value) +{ + ensureContext(m_contextObj); + ::glGetUniformfv((GLuint) program->object(), location, value); +} + +void GraphicsContext3D::getUniformiv(WebGLProgram* program, long location, int* value) +{ + ensureContext(m_contextObj); + ::glGetUniformiv((GLuint) program->object(), location, value); +} + +long GraphicsContext3D::getUniformLocation(WebGLProgram* program, const String& name) +{ + ASSERT(program); + + ensureContext(m_contextObj); + return ::glGetUniformLocation((GLuint) program->object(), name.utf8().data()); +} + +void GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname, float* value) +{ + ensureContext(m_contextObj); + ::glGetVertexAttribfv(index, pname, value); +} + +void GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname, int* value) +{ + ensureContext(m_contextObj); + ::glGetVertexAttribiv(index, pname, value); +} + +long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long pname) +{ + ensureContext(m_contextObj); + + void* pointer; + ::glGetVertexAttribPointerv(index, pname, &pointer); + return reinterpret_cast<long>(pointer); +} + +// Assumes the texture you want to go into is bound +static void imageToTexture(Image* image, unsigned target, unsigned level) +{ + if (!image) + return; + + CGImageRef textureImage = image->getCGImageRef(); + if (!textureImage) + return; + + size_t textureWidth = CGImageGetWidth(textureImage); + size_t textureHeight = CGImageGetHeight(textureImage); + + GLubyte* textureData = (GLubyte*) fastMalloc(textureWidth * textureHeight * 4); + if (!textureData) + return; + + CGContextRef textureContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, 8, textureWidth * 4, + CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast); + CGContextSetBlendMode(textureContext, kCGBlendModeCopy); + CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)textureWidth, (CGFloat)textureHeight), textureImage); + CGContextRelease(textureContext); + + ::glTexImage2D(target, level, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData); + fastFree(textureData); +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, WebGLArray* pixels) +{ + // FIXME: Need to do bounds checking on the buffer here. + ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels->baseAddress()); + return 0; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, ImageData* pixels) +{ + // FIXME: need to implement this form + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(internalformat); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(border); + UNUSED_PARAM(format); + UNUSED_PARAM(type); + UNUSED_PARAM(pixels); + return -1; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha) +{ + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + ASSERT(image); + + ensureContext(m_contextObj); + imageToTexture(image, target, level); + return 0; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha) +{ + // FIXME: need to implement this form + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(video); + + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, WebGLArray* pixels) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(format); + UNUSED_PARAM(type); + UNUSED_PARAM(pixels); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, ImageData* pixels) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(format); + UNUSED_PARAM(type); + UNUSED_PARAM(pixels); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, Image* image, bool flipY, bool premultiplyAlpha) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(image); + + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(video); + + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + return -1; +} + +unsigned GraphicsContext3D::createBuffer() +{ + ensureContext(m_contextObj); + GLuint o; + glGenBuffers(1, &o); + return o; +} + +unsigned GraphicsContext3D::createFramebuffer() +{ + ensureContext(m_contextObj); + GLuint o; + glGenFramebuffersEXT(1, &o); + return o; +} + +unsigned GraphicsContext3D::createProgram() +{ + ensureContext(m_contextObj); + return glCreateProgram(); +} + +unsigned GraphicsContext3D::createRenderbuffer() +{ + ensureContext(m_contextObj); + GLuint o; + glGenRenderbuffersEXT(1, &o); + return o; +} + +unsigned GraphicsContext3D::createShader(unsigned long type) +{ + ensureContext(m_contextObj); + return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER); +} + +unsigned GraphicsContext3D::createTexture() +{ + ensureContext(m_contextObj); + GLuint o; + glGenTextures(1, &o); + return o; +} + +void GraphicsContext3D::deleteBuffer(unsigned buffer) +{ + ensureContext(m_contextObj); + glDeleteBuffers(1, &buffer); +} + +void GraphicsContext3D::deleteFramebuffer(unsigned framebuffer) +{ + ensureContext(m_contextObj); + glDeleteFramebuffersEXT(1, &framebuffer); +} + +void GraphicsContext3D::deleteProgram(unsigned program) +{ + ensureContext(m_contextObj); + glDeleteProgram(program); +} + +void GraphicsContext3D::deleteRenderbuffer(unsigned renderbuffer) +{ + ensureContext(m_contextObj); + glDeleteRenderbuffersEXT(1, &renderbuffer); +} + +void GraphicsContext3D::deleteShader(unsigned shader) +{ + ensureContext(m_contextObj); + glDeleteShader(shader); +} + +void GraphicsContext3D::deleteTexture(unsigned texture) +{ + ensureContext(m_contextObj); + glDeleteTextures(1, &texture); +} + +int GraphicsContext3D::sizeInBytes(int type) +{ + switch (type) { + case GL_BYTE: + return sizeof(GLbyte); + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + case GL_SHORT: + return sizeof(GLshort); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_INT: + return sizeof(GLint); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + case GL_FLOAT: + return sizeof(GLfloat); + default: + return 0; + } +} + +void GraphicsContext3D::synthesizeGLError(unsigned long error) +{ + m_syntheticErrors.add(error); +} + +} + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index 2404319..6c9b872 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -50,27 +50,26 @@ void GraphicsContext::drawFocusRing(const Color& color) int radius = (focusRingWidth() - 1) / 2; int offset = radius + focusRingOffset(); - CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0; + RetainPtr<CGColorRef> colorRef; + if (color.isValid()) + colorRef.adoptCF(createCGColor(color)); - CGMutablePathRef focusRingPath = CGPathCreateMutable(); + RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable()); const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); for (unsigned i = 0; i < rectCount; i++) - CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset)); + CGPathAddRect(focusRingPath.get(), 0, CGRectInset(rects[i], -offset, -offset)); CGContextRef context = platformContext(); #ifdef BUILDING_ON_TIGER CGContextBeginTransparencyLayer(context, NULL); #endif CGContextBeginPath(context); - CGContextAddPath(context, focusRingPath); - wkDrawFocusRing(context, colorRef, radius); + CGContextAddPath(context, focusRingPath.get()); + wkDrawFocusRing(context, colorRef.get(), radius); #ifdef BUILDING_ON_TIGER CGContextEndTransparencyLayer(context); #endif - CGColorRelease(colorRef); - - CGPathRelease(focusRingPath); } #ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp. diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index ebdc6ac..8024091 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -54,6 +54,7 @@ public: // for hosting this GraphicsLayer in a native layer hierarchy virtual NativeLayer nativeLayer() const; + virtual bool setChildren(const Vector<GraphicsLayer*>&); virtual void addChild(GraphicsLayer*); virtual void addChildAtIndex(GraphicsLayer*, int index); virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling); @@ -62,6 +63,8 @@ public: virtual void removeFromParent(); + virtual void setMaskLayer(GraphicsLayer*); + virtual void setPosition(const FloatPoint&); virtual void setAnchorPoint(const FloatPoint3D&); virtual void setSize(const FloatSize&); @@ -86,6 +89,10 @@ public: virtual void setNeedsDisplay(); virtual void setNeedsDisplayInRect(const FloatRect&); +#if ENABLE(3D_CANVAS) + virtual void setGraphicsContext3DNeedsDisplay(); +#endif + virtual void setContentsRect(const IntRect&); virtual void suspendAnimations(double time); @@ -98,13 +105,14 @@ public: virtual void setContentsToImage(Image*); virtual void setContentsToVideo(PlatformLayer*); +#if ENABLE(3D_CANVAS) + virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*); +#endif virtual PlatformLayer* platformLayer() const; -#ifndef NDEBUG virtual void setDebugBackgroundColor(const Color&); virtual void setDebugBorder(const Color&, float borderWidth); -#endif virtual void setGeometryOrientation(CompositingCoordinatesOrientation); @@ -170,8 +178,12 @@ private: void updateContentsImage(); void updateContentsVideo(); +#if ENABLE(3D_CANVAS) + void updateContentsGraphicsContext3D(); +#endif void updateContentsRect(); void updateGeometryOrientation(); + void updateMaskLayer(); void updateLayerAnimations(); @@ -199,8 +211,12 @@ private: DirtyRectsChanged = 1 << 16, ContentsImageChanged = 1 << 17, ContentsVideoChanged = 1 << 18, - ContentsRectChanged = 1 << 19, - GeometryOrientationChanged = 1 << 20 +#if ENABLE(3D_CANVAS) + ContentsGraphicsContext3DChanged = 1 << 19, +#endif + ContentsRectChanged = 1 << 20, + GeometryOrientationChanged = 1 << 21, + MaskLayerChanged = 1 << 22 }; typedef unsigned LayerChangeFlags; void noteLayerPropertyChanged(LayerChangeFlags flags); @@ -215,6 +231,9 @@ private: NoContentsLayer = 0, ContentsLayerForImage, ContentsLayerForVideo +#if ENABLE(3D_CANVAS) + ,ContentsLayerForGraphicsLayer3D +#endif }; ContentsLayerPurpose m_contentsLayerPurpose; @@ -260,6 +279,11 @@ private: Vector<FloatRect> m_dirtyRects; LayerChangeFlags m_uncommittedChanges; + +#if ENABLE(3D_CANVAS) + PlatformGraphicsContext3D m_platformGraphicsContext3D; + Platform3DObject m_platformTexture; +#endif }; } // namespace WebCore diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index e5b9035..dea6bfc 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -31,6 +31,9 @@ #import "Animation.h" #import "BlockExceptions.h" +#if ENABLE(3D_CANVAS) +#import "Canvas3DLayer.h" +#endif #import "CString.h" #import "FloatConversion.h" #import "FloatRect.h" @@ -44,6 +47,7 @@ #import "WebLayer.h" #import "WebTiledLayer.h" #import <limits.h> +#import <objc/objc-auto.h> #import <wtf/CurrentTime.h> #import <wtf/UnusedParam.h> #import <wtf/RetainPtr.h> @@ -145,11 +149,11 @@ static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, case TransformOperation::ROTATE_Y: return [NSNumber numberWithDouble:transformOp ? deg2rad(static_cast<const RotateTransformOperation*>(transformOp)->angle()) : 0]; case TransformOperation::SCALE_X: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 0]; + return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 1]; case TransformOperation::SCALE_Y: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 0]; + return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 1]; case TransformOperation::SCALE_Z: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 0]; + return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 1]; case TransformOperation::TRANSLATE_X: return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0]; case TransformOperation::TRANSLATE_Y: @@ -157,13 +161,23 @@ static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, case TransformOperation::TRANSLATE_Z: return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0]; case TransformOperation::SCALE: + case TransformOperation::SCALE_3D: + return [NSArray arrayWithObjects: + [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 1], + [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 1], + [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 1], + nil]; case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_3D: + return [NSArray arrayWithObjects: + [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0], + [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->y(size) : 0], + [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0], + nil]; case TransformOperation::SKEW_X: case TransformOperation::SKEW_Y: case TransformOperation::SKEW: case TransformOperation::MATRIX: - case TransformOperation::SCALE_3D: - case TransformOperation::TRANSLATE_3D: case TransformOperation::ROTATE_3D: case TransformOperation::MATRIX_3D: case TransformOperation::PERSPECTIVE: @@ -204,6 +218,12 @@ static NSString* getValueFunctionNameForTransformOperation(TransformOperation::O return @"translateY"; // kCAValueFunctionTranslateY; case TransformOperation::TRANSLATE_Z: return @"translateZ"; // kCAValueFunctionTranslateZ; + case TransformOperation::SCALE: + case TransformOperation::SCALE_3D: + return @"scale"; // kCAValueFunctionScale; + case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_3D: + return @"translate"; // kCAValueFunctionTranslate; default: return nil; } @@ -255,7 +275,6 @@ static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& tim return 0; } -#ifndef NDEBUG static void setLayerBorderColor(PlatformLayer* layer, const Color& color) { CGColorRef borderColor = createCGColor(color); @@ -267,7 +286,6 @@ static void clearBorderColor(PlatformLayer* layer) { [layer setBorderColor:nil]; } -#endif static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color) { @@ -281,6 +299,18 @@ static void clearLayerBackgroundColor(PlatformLayer* layer) [layer setBackgroundColor:0]; } +static void safeSetSublayers(CALayer* layer, NSArray* sublayers) +{ + // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC. + if (objc_collectingEnabled() && ![sublayers count]) { + while ([[layer sublayers] count]) + [[[layer sublayers] objectAtIndex:0] removeFromSuperlayer]; + return; + } + + [layer setSublayers:sublayers]; +} + static bool caValueFunctionSupported() { static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; @@ -298,20 +328,6 @@ GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoord return CompositingCoordinatesBottomUp; } -#ifndef NDEBUG -bool GraphicsLayer::showDebugBorders() -{ - static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"]; - return showDebugBorders; -} - -bool GraphicsLayer::showRepaintCounter() -{ - static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"]; - return showRepaintCounter; -} -#endif - static NSDictionary* nullActionsDictionary() { NSNull* nullValue = [NSNull null]; @@ -331,16 +347,20 @@ static NSDictionary* nullActionsDictionary() return actions; } -GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client) +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) { return new GraphicsLayerCA(client); } GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) -: GraphicsLayer(client) -, m_contentsLayerPurpose(NoContentsLayer) -, m_contentsLayerHasBackgroundColor(false) -, m_uncommittedChanges(NoChange) + : GraphicsLayer(client) + , m_contentsLayerPurpose(NoContentsLayer) + , m_contentsLayerHasBackgroundColor(false) + , m_uncommittedChanges(NoChange) +#if ENABLE(3D_CANVAS) + , m_platformGraphicsContext3D(NullPlatformGraphicsContext3D) + , m_platformTexture(NullPlatform3DObject) +#endif { BEGIN_BLOCK_OBJC_EXCEPTIONS m_layer.adoptNS([[WebLayer alloc] init]); @@ -350,9 +370,7 @@ GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) setContentsOrientation(defaultContentsOrientation()); #endif -#ifndef NDEBUG updateDebugIndicators(); -#endif m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]); [m_animationDelegate.get() setLayer:this]; @@ -392,6 +410,15 @@ NativeLayer GraphicsLayerCA::nativeLayer() const return m_layer.get(); } +bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + if (childrenChanged) + noteLayerPropertyChanged(ChildrenChanged); + + return childrenChanged; +} + void GraphicsLayerCA::addChild(GraphicsLayer* childLayer) { GraphicsLayer::addChild(childLayer); @@ -432,6 +459,15 @@ void GraphicsLayerCA::removeFromParent() GraphicsLayer::removeFromParent(); } +void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer) +{ + if (layer == m_maskLayer) + return; + + GraphicsLayer::setMaskLayer(layer); + noteLayerPropertyChanged(MaskLayerChanged); +} + void GraphicsLayerCA::setPosition(const FloatPoint& point) { if (point == m_position) @@ -672,10 +708,10 @@ void GraphicsLayerCA::setContentsToImage(Image* image) CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get()); static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); - if (CFEqual(colorSpace, deviceRGB)) { - // CoreGraphics renders images tagged with DeviceRGB using GenericRGB. When we hand such + if (colorSpace && CFEqual(colorSpace, deviceRGB)) { + // CoreGraphics renders images tagged with DeviceRGB using the color space of the main display. When we hand such // images to CA we need to tag them similarly so CA rendering matches CG rendering. - static CGColorSpaceRef genericRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + static CGColorSpaceRef genericRGB = CGDisplayCopyColorSpace(kCGDirectMainDisplay); m_pendingContentsImage.adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB)); } m_contentsLayerPurpose = ContentsLayerForImage; @@ -733,6 +769,9 @@ void GraphicsLayerCA::recursiveCommitChanges() { commitLayerChanges(); + if (m_maskLayer) + static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChanges(); + const Vector<GraphicsLayer*>& childLayers = children(); size_t numChildren = childLayers.size(); for (size_t i = 0; i < numChildren; ++i) { @@ -763,7 +802,12 @@ void GraphicsLayerCA::commitLayerChanges() if (m_uncommittedChanges & ContentsVideoChanged) // Needs to happen before ChildrenChanged updateContentsVideo(); - + +#if ENABLE(3D_CANVAS) + if (m_uncommittedChanges & ContentsGraphicsContext3DChanged) // Needs to happen before ChildrenChanged + updateContentsGraphicsContext3D(); +#endif + if (m_uncommittedChanges & BackgroundColorChanged) // Needs to happen before ChildrenChanged, and after updating image or video updateLayerBackgroundColor(); @@ -812,6 +856,9 @@ void GraphicsLayerCA::commitLayerChanges() if (m_uncommittedChanges & GeometryOrientationChanged) updateGeometryOrientation(); + if (m_uncommittedChanges & MaskLayerChanged) + updateMaskLayer(); + m_uncommittedChanges = NoChange; END_BLOCK_OBJC_EXCEPTIONS } @@ -821,10 +868,12 @@ void GraphicsLayerCA::updateSublayerList() NSMutableArray* newSublayers = nil; if (m_transformLayer) { - // FIXME: add the primary layer in the correct order with negative z-order children. + // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind. newSublayers = [[NSMutableArray alloc] initWithObjects:m_layer.get(), nil]; } else if (m_contentsLayer) { // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. newSublayers = [[NSMutableArray alloc] initWithObjects:m_contentsLayer.get(), nil]; } @@ -843,17 +892,16 @@ void GraphicsLayerCA::updateSublayerList() [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; if (m_transformLayer) { - [m_transformLayer.get() setSublayers:newSublayers]; + safeSetSublayers(m_transformLayer.get(), newSublayers); if (m_contentsLayer) { // If we have a transform layer, then the contents layer is parented in the // primary layer (which is itself a child of the transform layer). - [m_layer.get() setSublayers:nil]; + safeSetSublayers(m_layer.get(), nil); [m_layer.get() addSublayer:m_contentsLayer.get()]; } - } else { - [m_layer.get() setSublayers:newSublayers]; - } + } else + safeSetSublayers(m_layer.get(), newSublayers); [newSublayers release]; } @@ -919,9 +967,7 @@ void GraphicsLayerCA::updateChildrenTransform() void GraphicsLayerCA::updateMasksToBounds() { [m_layer.get() setMasksToBounds:m_masksToBounds]; -#ifndef NDEBUG updateDebugIndicators(); -#endif } void GraphicsLayerCA::updateContentsOpaque() @@ -1006,9 +1052,7 @@ void GraphicsLayerCA::updateLayerDrawsContent() else [m_layer.get() setContents:nil]; -#ifndef NDEBUG updateDebugIndicators(); -#endif } void GraphicsLayerCA::updateLayerBackgroundColor() @@ -1061,6 +1105,18 @@ void GraphicsLayerCA::updateContentsVideo() } } +#if ENABLE(3D_CANVAS) +void GraphicsLayerCA::updateContentsGraphicsContext3D() +{ + // Canvas3D layer was set as m_contentsLayer, and will get parented in updateSublayerList(). + if (m_contentsLayer) { + setupContentsLayer(m_contentsLayer.get()); + [m_contentsLayer.get() setNeedsDisplay]; + updateContentsRect(); + } +} +#endif + void GraphicsLayerCA::updateContentsRect() { if (!m_contentsLayer) @@ -1094,6 +1150,12 @@ void GraphicsLayerCA::updateGeometryOrientation() #endif } +void GraphicsLayerCA::updateMaskLayer() +{ + CALayer* maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0; + [m_layer.get() setMask:maskCALayer]; +} + void GraphicsLayerCA::updateLayerAnimations() { if (m_transitionPropertiesToRemove.size()) { @@ -1182,6 +1244,21 @@ void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedP [layer addAnimation:caAnim forKey:animationName]; } +// Workaround for <rdar://problem/7311367> +static void bug7311367Workaround(CALayer* transformLayer, const TransformationMatrix& transform) +{ + if (!transformLayer) + return; + + CATransform3D caTransform; + copyTransform(caTransform, transform); + caTransform.m41 += 1; + [transformLayer setTransform:caTransform]; + + caTransform.m41 -= 1; + [transformLayer setTransform:caTransform]; +} + bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int index) { PlatformLayer* layer = animatedLayer(property); @@ -1192,10 +1269,11 @@ bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int return false; [layer removeAnimationForKey:animationName]; + + bug7311367Workaround(m_transformLayer.get(), m_transform); return true; } - static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimation* to) { [to setBeginTime:[from beginTime]]; @@ -1247,6 +1325,40 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, int ind [layer addAnimation:pausedAnim forKey:animationName]; // This will replace the running animation. } +#if ENABLE(3D_CANVAS) +void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* graphicsContext3D) +{ + PlatformGraphicsContext3D context = graphicsContext3D->platformGraphicsContext3D(); + Platform3DObject texture = graphicsContext3D->platformTexture(); + + if (context == m_platformGraphicsContext3D && texture == m_platformTexture) + return; + + m_platformGraphicsContext3D = context; + m_platformTexture = texture; + + noteLayerPropertyChanged(ChildrenChanged); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (m_platformGraphicsContext3D != NullPlatformGraphicsContext3D && m_platformTexture != NullPlatform3DObject) { + // create the inner 3d layer + m_contentsLayer.adoptNS([[Canvas3DLayer alloc] initWithContext:static_cast<CGLContextObj>(m_platformGraphicsContext3D) texture:static_cast<GLuint>(m_platformTexture)]); +#ifndef NDEBUG + [m_contentsLayer.get() setName:@"3D Layer"]; +#endif + } else { + // remove the inner layer + m_contentsLayer = 0; + } + + END_BLOCK_OBJC_EXCEPTIONS + + noteLayerPropertyChanged(ContentsGraphicsContext3DChanged); + m_contentsLayerPurpose = m_contentsLayer ? ContentsLayerForGraphicsLayer3D : NoContentsLayer; +} +#endif + void GraphicsLayerCA::repaintLayerDirtyRects() { if (!m_dirtyRects.size()) @@ -1582,7 +1694,6 @@ PlatformLayer* GraphicsLayerCA::platformLayer() const return primaryLayer(); } -#ifndef NDEBUG void GraphicsLayerCA::setDebugBackgroundColor(const Color& color) { BEGIN_BLOCK_OBJC_EXCEPTIONS @@ -1609,7 +1720,6 @@ void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth) END_BLOCK_OBJC_EXCEPTIONS } -#endif // NDEBUG bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const { @@ -1656,7 +1766,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer) } [m_layer.get() setLayerOwner:this]; - [m_layer.get() setSublayers:[oldLayer.get() sublayers]]; + safeSetSublayers(m_layer.get(), [oldLayer.get() sublayers]); [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()]; @@ -1687,9 +1797,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer) // need to tell new layer to draw itself setNeedsDisplay(); -#ifndef NDEBUG updateDebugIndicators(); -#endif } GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCA::defaultContentsOrientation() const @@ -1733,12 +1841,10 @@ void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer) } else [contentsLayer setAnchorPoint:CGPointZero]; -#ifndef NDEBUG if (showDebugBorders()) { setLayerBorderColor(contentsLayer, Color(0, 0, 128, 180)); [contentsLayer setBorderWidth:1.0f]; } -#endif } void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity) @@ -1765,6 +1871,14 @@ void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags) m_uncommittedChanges |= flags; } +#if ENABLE(3D_CANVAS) +void GraphicsLayerCA::setGraphicsContext3DNeedsDisplay() +{ + if (m_contentsLayerPurpose == ContentsLayerForGraphicsLayer3D) + [m_contentsLayer.get() setNeedsDisplay]; +} +#endif + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm index 63abe59..aee7234 100644 --- a/WebCore/platform/graphics/mac/IconMac.mm +++ b/WebCore/platform/graphics/mac/IconMac.mm @@ -39,27 +39,32 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - // Don't pass relative filenames -- we don't want a result that depends on the current directory. - // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[] - if (filename.isEmpty() || filename[0U] != '/') + if (filenames.isEmpty()) return 0; - NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filename]; - if (!image) - return 0; + bool useIconFromFirstFile; +#ifdef BUILDING_ON_TIGER + // FIXME: find a better image for multiple files to use on Tiger. + useIconFromFirstFile = true; +#else + useIconFromFirstFile = filenames.size() == 1; +#endif + if (useIconFromFirstFile) { + // Don't pass relative filenames -- we don't want a result that depends on the current directory. + // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[] + if (filenames[0].isEmpty() || filenames[0][0U] != '/') + return 0; - return adoptRef(new Icon(image)); -} + NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filenames[0]]; + if (!image) + return 0; -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) -{ - if (filenames.isEmpty()) - return 0; + return adoptRef(new Icon(image)); + } #ifdef BUILDING_ON_TIGER - // FIXME: find a better image to use on Tiger. - return createIconForFile(filenames[0]); + return 0; #else NSImage* image = [NSImage imageNamed:NSImageNameMultipleDocuments]; if (!image) diff --git a/WebCore/platform/graphics/mac/ImageMac.mm b/WebCore/platform/graphics/mac/ImageMac.mm index a0d257b..672c3c8 100644 --- a/WebCore/platform/graphics/mac/ImageMac.mm +++ b/WebCore/platform/graphics/mac/ImageMac.mm @@ -94,16 +94,15 @@ CFDataRef BitmapImage::getTIFFRepresentation() RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, 0)); // FIXME: Use type kCGImageTypeIdentifierTIFF constant once is becomes available in the API - CGImageDestinationRef destination = CGImageDestinationCreateWithData(data.get(), CFSTR("public.tiff"), numValidFrames, 0); - + RetainPtr<CGImageDestinationRef> destination(AdoptCF, CGImageDestinationCreateWithData(data.get(), CFSTR("public.tiff"), numValidFrames, 0)); + if (!destination) return 0; for (unsigned i = 0; i < numValidFrames; ++i) - CGImageDestinationAddImage(destination, images[i], 0); + CGImageDestinationAddImage(destination.get(), images[i], 0); - CGImageDestinationFinalize(destination); - CFRelease(destination); + CGImageDestinationFinalize(destination.get()); m_tiffRep = data; return m_tiffRep.get(); diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 54eea00..7aaf95d 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -77,8 +77,12 @@ private: static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); static bool isAvailable(); + PlatformMedia platformMedia() const; + IntSize naturalSize() const; bool hasVideo() const; + bool hasAudio() const; + bool supportsFullscreen() const; void load(const String& url); void cancelLoad(); @@ -97,6 +101,9 @@ private: void setVolume(float); void setPreservesPitch(bool); + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); + void setEndTime(float time); int dataRate() const; @@ -104,7 +111,7 @@ private: MediaPlayer::NetworkState networkState() const { return m_networkState; } MediaPlayer::ReadyState readyState() const { return m_readyState; } - float maxTimeBuffered() const; + PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; bool totalBytesKnown() const; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index c1d7fcb..dfb5958 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -39,6 +39,7 @@ #import "KURL.h" #import "MIMETypeRegistry.h" #import "SoftLinking.h" +#import "TimeRanges.h" #import "WebCoreSystemInterface.h" #import <QTKit/QTKit.h> #import <objc/objc-runtime.h> @@ -84,6 +85,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieAskUnresolvedDataRefsAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieDataSizeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieDidEndNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieHasVideoAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieHasAudioAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieIsActiveAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoadStateAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *) @@ -119,6 +121,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieApertureModeAttribute, NSString *) #define QTMovieDataSizeAttribute getQTMovieDataSizeAttribute() #define QTMovieDidEndNotification getQTMovieDidEndNotification() #define QTMovieHasVideoAttribute getQTMovieHasVideoAttribute() +#define QTMovieHasAudioAttribute getQTMovieHasAudioAttribute() #define QTMovieIsActiveAttribute getQTMovieIsActiveAttribute() #define QTMovieLoadStateAttribute getQTMovieLoadStateAttribute() #define QTMovieLoadStateDidChangeNotification getQTMovieLoadStateDidChangeNotification() @@ -230,7 +233,7 @@ MediaPlayerPrivate::~MediaPlayerPrivate() void MediaPlayerPrivate::createQTMovie(const String& url) { - NSURL *cocoaURL = KURL(url); + NSURL *cocoaURL = KURL(ParsedURLString, url); NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys: cocoaURL, QTMovieURLAttribute, [NSNumber numberWithBool:m_player->preservesPitch()], QTMovieRateChangesPreservePitchAttribute, @@ -562,6 +565,12 @@ void MediaPlayerPrivate::load(const String& url) [m_objcObserver.get() setDelayCallbacks:NO]; } +PlatformMedia MediaPlayerPrivate::platformMedia() const +{ + PlatformMedia plaftformMedia = { m_qtMovie.get() }; + return plaftformMedia; +} + void MediaPlayerPrivate::play() { if (!metaDataAvailable()) @@ -719,18 +728,54 @@ bool MediaPlayerPrivate::hasVideo() const return [[m_qtMovie.get() attributeForKey:QTMovieHasVideoAttribute] boolValue]; } +bool MediaPlayerPrivate::hasAudio() const +{ + if (!m_qtMovie) + return false; + return [[m_qtMovie.get() attributeForKey:QTMovieHasAudioAttribute] boolValue]; +} + +bool MediaPlayerPrivate::supportsFullscreen() const +{ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + return true; +#else + // See <rdar://problem/7389945> + return false; +#endif +} + void MediaPlayerPrivate::setVolume(float volume) { + if (m_qtMovie) + [m_qtMovie.get() setVolume:volume]; +} + +bool MediaPlayerPrivate::hasClosedCaptions() const +{ if (!metaDataAvailable()) - return; - [m_qtMovie.get() setVolume:volume]; + return false; + return wkQTMovieHasClosedCaptions(m_qtMovie.get()); +} + +void MediaPlayerPrivate::setClosedCaptionsVisible(bool closedCaptionsVisible) +{ + if (metaDataAvailable()) { + wkQTMovieSetShowClosedCaptions(m_qtMovie.get(), closedCaptionsVisible); + +#if USE(ACCELERATED_COMPOSITING) && (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + if (closedCaptionsVisible && m_qtVideoLayer) { + // Captions will be rendered upsided down unless we flag the movie as flipped (again). See <rdar://7408440>. + [m_qtVideoLayer.get() setGeometryFlipped:YES]; + } +#endif + } } void MediaPlayerPrivate::setRate(float rate) { - if (!metaDataAvailable()) - return; - [m_qtMovie.get() setRate:rate]; + if (m_qtMovie) + [m_qtMovie.get() setRate:rate]; } void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch) @@ -758,10 +803,13 @@ int MediaPlayerPrivate::dataRate() const return wkQTMovieDataRate(m_qtMovie.get()); } - -float MediaPlayerPrivate::maxTimeBuffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { - return maxTimeLoaded(); + RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + float loaded = maxTimeLoaded(); + if (loaded > 0) + timeRanges->add(0, loaded); + return timeRanges.release(); } float MediaPlayerPrivate::maxTimeSeekable() const @@ -1136,10 +1184,10 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) TextRun textRun(text.characters(), text.length()); const Color color(255, 0, 0); context->scale(FloatSize(1.0f, -1.0f)); - context->setStrokeColor(color); + context->setStrokeColor(color, styleToUse->colorSpace()); context->setStrokeStyle(SolidStroke); context->setStrokeThickness(1.0f); - context->setFillColor(color); + context->setFillColor(color, styleToUse->colorSpace()); context->drawText(styleToUse->font(), textRun, IntPoint(2, -3)); } } diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index cdde7cf..97a7251 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -50,6 +50,8 @@ - (BOOL)_isFakeFixedPitch; @end +using namespace std; + namespace WebCore { const float smallCapsFontSizeMultiplier = 0.7f; @@ -269,7 +271,7 @@ void SimpleFontData::platformInit() // and web pages that foolishly use this metric for width will be laid out // poorly if we return an accurate height. Classic case is Times 13 point, // which has an "x" that is 7x6 pixels. - m_xHeight = MAX(NSMaxX(xBox), NSMaxY(xBox)); + m_xHeight = max(NSMaxX(xBox), NSMaxY(xBox)); } else m_xHeight = [m_platformData.font() xHeight]; } @@ -443,13 +445,13 @@ CTFontRef SimpleFontData::getCTFont() const return m_CTFont.get(); } -CFDictionaryRef SimpleFontData::getCFStringAttributes() const +CFDictionaryRef SimpleFontData::getCFStringAttributes(TextRenderingMode textMode) const { if (m_CFStringAttributes) return m_CFStringAttributes.get(); - static const float kerningAdjustmentValue = 0; - static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue); + bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; + bool allowLigatures = platformData().allowsLigatures() || allowKerning; static const int ligaturesNotAllowedValue = 0; static CFNumberRef ligaturesNotAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesNotAllowedValue); @@ -457,10 +459,23 @@ CFDictionaryRef SimpleFontData::getCFStringAttributes() const static const int ligaturesAllowedValue = 1; static CFNumberRef ligaturesAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesAllowedValue); - static const void* attributeKeys[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName }; - const void* attributeValues[] = { getCTFont(), kerningAdjustment, platformData().allowsLigatures() ? ligaturesAllowed : ligaturesNotAllowed }; - - m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, attributeKeys, attributeValues, sizeof(attributeKeys) / sizeof(*attributeKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + if (!allowKerning) { + static const float kerningAdjustmentValue = 0; + static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue); + static const void* keysWithKerningDisabled[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName }; + const void* valuesWithKerningDisabled[] = { getCTFont(), kerningAdjustment, allowLigatures + ? ligaturesAllowed : ligaturesNotAllowed }; + m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, keysWithKerningDisabled, valuesWithKerningDisabled, + sizeof(keysWithKerningDisabled) / sizeof(*keysWithKerningDisabled), + &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + } else { + // By omitting the kCTKernAttributeName attribute, we get Core Text's standard kerning. + static const void* keysWithKerningEnabled[] = { kCTFontAttributeName, kCTLigatureAttributeName }; + const void* valuesWithKerningEnabled[] = { getCTFont(), allowLigatures ? ligaturesAllowed : ligaturesNotAllowed }; + m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, keysWithKerningEnabled, valuesWithKerningEnabled, + sizeof(keysWithKerningEnabled) / sizeof(*keysWithKerningEnabled), + &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + } return m_CFStringAttributes.get(); } diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm index 2647466..56b28e6 100644 --- a/WebCore/platform/graphics/mac/WebLayer.mm +++ b/WebCore/platform/graphics/mac/WebLayer.mm @@ -80,7 +80,6 @@ using namespace WebCore; } #endif -#ifndef NDEBUG if (layerContents->showRepaintCounter()) { bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]]; @@ -107,7 +106,6 @@ using namespace WebCore; CGContextRestoreGState(context); } -#endif CGContextRestoreGState(context); } diff --git a/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp new file mode 100644 index 0000000..b4cdb09 --- /dev/null +++ b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#if ENABLE(OPENTYPE_SANITIZER) +#include "OpenTypeSanitizer.h" + +#include "SharedBuffer.h" +#include "opentype-sanitiser.h" +#include "ots-memory-stream.h" +#include <wtf/OwnArrayPtr.h> + +namespace WebCore { + +PassRefPtr<SharedBuffer> OpenTypeSanitizer::sanitize() +{ + if (!m_buffer) + return 0; + + // This is the largest web font size which we'll try to transcode. + static const size_t maxWebFontSize = 30 * 1024 * 1024; // 30 MB + if (m_buffer->size() > maxWebFontSize) + return 0; + + // A transcoded font is usually smaller than an original font. + // However, it can be slightly bigger than the original one due to + // name table replacement and/or padding for glyf table. + static const size_t padLen = 20 * 1024; // 20 kB + + OwnArrayPtr<unsigned char> transcodeRawBuffer(new unsigned char[m_buffer->size() + padLen]); + ots::MemoryStream output(transcodeRawBuffer.get(), m_buffer->size() + padLen); + if (!ots::Process(&output, reinterpret_cast<const uint8_t*>(m_buffer->data()), m_buffer->size())) + return 0; + + const size_t transcodeLen = output.Tell(); + return SharedBuffer::create(transcodeRawBuffer.get(), transcodeLen); +} + +} // namespace WebCore + +#endif // ENABLE(OPENTYPE_SANITIZER) diff --git a/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h new file mode 100644 index 0000000..3f93448 --- /dev/null +++ b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OpenTypeSanitizer_h +#define OpenTypeSanitizer_h + +#if ENABLE(OPENTYPE_SANITIZER) +#include <wtf/Forward.h> + +namespace WebCore { + +class SharedBuffer; + +class OpenTypeSanitizer { +public: + explicit OpenTypeSanitizer(SharedBuffer* buffer) + : m_buffer(buffer) + { + } + + PassRefPtr<SharedBuffer> sanitize(); + +private: + SharedBuffer* const m_buffer; +}; + +} // namespace WebCore + +#endif // ENABLE(OPENTYPE_SANITIZER) +#endif // OpenTypeSanitizer_h diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index 895887f..3a60160 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -339,7 +340,10 @@ bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayD return true; } -HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) +// code shared by renameFont and renameAndActivateFont +// adds fontName to the font table in fontData, and writes the new font table to rewrittenFontTable +// returns the size of the name table (which is used by renameAndActivateFont), or 0 on early abort +static size_t renameFontInternal(SharedBuffer* fontData, const String& fontName, Vector<char> &rewrittenFontData) { size_t originalDataSize = fontData->size(); const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(fontData->data()); @@ -357,7 +361,7 @@ HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) // Rounded up to a multiple of 4 to simplify the checksum calculation. size_t nameTableSize = ((offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord) + fontName.length() * sizeof(UChar)) & ~3) + 4; - Vector<char> rewrittenFontData(fontData->size() + nameTableSize); + rewrittenFontData.resize(fontData->size() + nameTableSize); char* data = rewrittenFontData.data(); memcpy(data, fontData->data(), originalDataSize); @@ -394,15 +398,50 @@ HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) for (unsigned i = 0; i * sizeof(BigEndianULong) < nameTableSize; ++i) rewrittenSfnt->tables[t].checkSum = rewrittenSfnt->tables[t].checkSum + reinterpret_cast<BigEndianULong*>(name)[i]; + return nameTableSize; +} + +#if PLATFORM(WINCE) +// AddFontMemResourceEx does not exist on WinCE, so we must handle the font data manually +// This function just renames the font and overwrites the old font data with the new +bool renameFont(SharedBuffer* fontData, const String& fontName) +{ + // abort if the data is too small to be a font header with a "tables" entry + if (fontData->size() < offsetof(sfntHeader, tables)) + return false; + + // abort if the data is too small to hold all the tables specified in the header + const sfntHeader* header = reinterpret_cast<const sfntHeader*>(fontData->data()); + if (fontData->size() < offsetof(sfntHeader, tables) + header->numTables * sizeof(TableDirectoryEntry)) + return false; + + Vector<char> rewrittenFontData; + if (!renameFontInternal(fontData, fontName, rewrittenFontData)) + return false; + + fontData->clear(); + fontData->append(rewrittenFontData.data(), rewrittenFontData.size()); + return true; +} +#else +// Rename the font and install the new font data into the system +HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) +{ + Vector<char> rewrittenFontData; + size_t nameTableSize = renameFontInternal(fontData, fontName, rewrittenFontData); + if (!nameTableSize) + return 0; + DWORD numFonts = 0; - HANDLE fontHandle = AddFontMemResourceEx(data, originalDataSize + nameTableSize, 0, &numFonts); + HANDLE fontHandle = AddFontMemResourceEx(rewrittenFontData.data(), fontData->size() + nameTableSize, 0, &numFonts); - if (fontHandle && numFonts != 1) { + if (fontHandle && numFonts < 1) { RemoveFontMemResourceEx(fontHandle); return 0; } return fontHandle; } +#endif } diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h index 13dad6f..4c75314 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,6 +36,10 @@ struct BigEndianUShort; struct EOTPrefix; class SharedBuffer; +#if PLATFORM(WINCE) +typedef unsigned __int8 UInt8; +#endif + struct EOTHeader { EOTHeader(); diff --git a/WebCore/platform/graphics/qt/ColorQt.cpp b/WebCore/platform/graphics/qt/ColorQt.cpp index 5d16740..151766a 100644 --- a/WebCore/platform/graphics/qt/ColorQt.cpp +++ b/WebCore/platform/graphics/qt/ColorQt.cpp @@ -40,7 +40,10 @@ Color::Color(const QColor& c) Color::operator QColor() const { - return QColor(red(), green(), blue(), alpha()); + if (m_valid) + return QColor(red(), green(), blue(), alpha()); + else + return QColor(); } } diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index 5d29389..82fb709 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -34,260 +34,39 @@ #include <wtf/ListHashSet.h> #include <wtf/StdLibExtras.h> +#include <QFont> + using namespace WTF; namespace WebCore { -FontCache* fontCache() -{ - DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ()); - return &globalFontCache; -} - -FontCache::FontCache() +void FontCache::platformInit() { } -void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) -{ -} - -// This type must be consistent with FontPlatformData's ctor - the one which -// gets FontDescription as it's parameter. -class FontPlatformDataCacheKey { -public: - FontPlatformDataCacheKey(const FontDescription& description) - : m_familyName() - , m_bold(false) - , m_size(description.computedPixelSize()) - , m_italic(description.italic()) - , m_smallCaps(description.smallCaps()) - , m_hash(0) - { - // FIXME: Map all FontWeight values to QFont weights in FontPlatformData's ctor and follow it here - if (FontPlatformData::toQFontWeight(description.weight()) > QFont::Normal) - m_bold = true; - - const FontFamily* family = &description.family(); - while (family) { - m_familyName.append(family->family()); - family = family->next(); - if (family) - m_familyName.append(','); - } - - computeHash(); - } - - FontPlatformDataCacheKey(const FontPlatformData& fontData) - : m_familyName(static_cast<String>(fontData.family())) - , m_size(fontData.pixelSize()) - , m_bold(fontData.bold()) - , m_italic(fontData.italic()) - , m_smallCaps(fontData.smallCaps()) - , m_hash(0) - { - computeHash(); - } - - FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { } - bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); } - - enum HashTableEmptyValueType { HashTableEmptyValue }; - - FontPlatformDataCacheKey(HashTableEmptyValueType) - : m_familyName() - , m_size(0) - , m_bold(false) - , m_italic(false) - , m_smallCaps(false) - , m_hash(0) - { - } - - bool operator==(const FontPlatformDataCacheKey& other) const - { - if (m_hash != other.m_hash) - return false; - - return equalIgnoringCase(m_familyName, other.m_familyName) && m_size == other.m_size && - m_bold == other.m_bold && m_italic == other.m_italic && m_smallCaps == other.m_smallCaps; - } - - unsigned hash() const - { - return m_hash; - } - - void computeHash() - { - unsigned hashCodes[] = { - CaseFoldingHash::hash(m_familyName), - m_size | static_cast<unsigned>(m_bold << sizeof(unsigned) * 8 - 1) - | static_cast<unsigned>(m_italic) << sizeof(unsigned) *8 - 2 - | static_cast<unsigned>(m_smallCaps) << sizeof(unsigned) * 8 - 3 - }; - m_hash = StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); - } - -private: - String m_familyName; - int m_size; - bool m_bold; - bool m_italic; - bool m_smallCaps; - unsigned m_hash; - - static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; } -}; - -struct FontPlatformDataCacheKeyHash { - static unsigned hash(const FontPlatformDataCacheKey& key) - { - return key.hash(); - } - - static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b) - { - return a == b; - } - - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> { - static const bool needsDestruction = true; - static const FontPlatformDataCacheKey& emptyValue() - { - DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (FontPlatformDataCacheKey::HashTableEmptyValue)); - return key; - } - static void constructDeletedValue(FontPlatformDataCacheKey& slot) - { - new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue); - } - static bool isDeletedValue(const FontPlatformDataCacheKey& value) - { - return value.isHashTableDeletedValue(); - } -}; - -typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache; - -// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this. -static FontPlatformDataCache* gFontPlatformDataCache = 0; - -FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName) -{ - if (!gFontPlatformDataCache) - gFontPlatformDataCache = new FontPlatformDataCache; - - FontPlatformDataCacheKey key(description); - FontPlatformData* platformData = gFontPlatformDataCache->get(key); - if (!platformData) { - platformData = new FontPlatformData(description); - gFontPlatformDataCache->add(key, platformData); - } - return platformData; -} - -typedef HashMap<FontPlatformDataCacheKey, std::pair<SimpleFontData*, unsigned>, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontDataCache; - -static FontDataCache* gFontDataCache = 0; - -static const int cMaxInactiveFontData = 40; -static const int cTargetInactiveFontData = 32; - -static ListHashSet<const SimpleFontData*>* gInactiveFontDataSet = 0; - -SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* fontPlatformData) -{ - if (!gFontDataCache) { - gFontDataCache = new FontDataCache; - gInactiveFontDataSet = new ListHashSet<const SimpleFontData*>; - } - - FontPlatformDataCacheKey key(*fontPlatformData); - FontDataCache::iterator it = gFontDataCache->find(key); - if (it == gFontDataCache->end()) { - SimpleFontData* fontData = new SimpleFontData(*fontPlatformData); - gFontDataCache->add(key, std::pair<SimpleFontData*, unsigned>(fontData, 1)); - return fontData; - } - if (!it->second.second++) { - ASSERT(gInactiveFontDataSet->contains(it->second.first)); - gInactiveFontDataSet->remove(it->second.first); - } - return it->second.first; -} - -FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&) +const SimpleFontData* FontCache::getFontDataForCharacters(const Font&, const UChar*, int) { return 0; } -void FontCache::releaseFontData(const WebCore::SimpleFontData* fontData) -{ - ASSERT(gFontDataCache); - ASSERT(!fontData->isCustomFont()); - - FontPlatformDataCacheKey key(fontData->platformData()); - FontDataCache::iterator it = gFontDataCache->find(key); - ASSERT(it != gFontDataCache->end()); - if (!--it->second.second) { - gInactiveFontDataSet->add(it->second.first); - if (gInactiveFontDataSet->size() > cMaxInactiveFontData) - purgeInactiveFontData(gInactiveFontDataSet->size() - cTargetInactiveFontData); - } -} - -void FontCache::purgeInactiveFontData(int count) +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) { - static bool isPurging; // Guard against reentry when e.g. a deleted FontData releases its small caps FontData. - if (isPurging) - return; - - isPurging = true; - - ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontDataSet->begin(); - ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontDataSet->end(); - for (int i = 0; i < count && it != end; ++i, ++it) { - FontPlatformDataCacheKey key = (*it)->platformData(); - pair<SimpleFontData*, unsigned> fontDataPair = gFontDataCache->take(key); - ASSERT(fontDataPair.first != 0); - ASSERT(!fontDataPair.second); - delete fontDataPair.first; - - FontPlatformData* platformData = gFontPlatformDataCache->take(key); - if (platformData) - delete platformData; - } - - if (it == end) { - // Removed everything - gInactiveFontDataSet->clear(); - } else { - for (int i = 0; i < count; ++i) - gInactiveFontDataSet->remove(gInactiveFontDataSet->begin()); - } - - isPurging = false; + return 0; } -void FontCache::addClient(FontSelector*) +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) { + const AtomicString fallbackFamily = QFont(fontDescription.family().family()).lastResortFont(); + return new FontPlatformData(fontDescription, fallbackFamily); } -void FontCache::removeClient(FontSelector*) +void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&) { } -void FontCache::invalidate() +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) { - if (!gFontPlatformDataCache || !gFontDataCache) - return; - - purgeInactiveFontData(); + return new FontPlatformData(fontDescription, familyName); } } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp index a19464e..6e9d053 100644 --- a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp @@ -43,7 +43,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b font.setWeight(QFont::Bold); font.setItalic(italic); - return FontPlatformData(font, bold); + return FontPlatformData(font); } FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp deleted file mode 100644 index c29fd56..0000000 --- a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - Copyright (C) 2008 Holger Hans Peter Freyther - - 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. - - Replacement of the stock FontFallbackList as Qt is going to find us a - replacement font, will do caching and the other stuff we implement in - WebKit. -*/ - -#include "config.h" -#include "FontFallbackList.h" - -#include "Font.h" -#include "FontCache.h" -#include "SegmentedFontData.h" - -#include <QDebug> - -namespace WebCore { - -FontFallbackList::FontFallbackList() - : m_pageZero(0) - , m_cachedPrimarySimpleFontData(0) - , m_fontSelector(0) - , m_familyIndex(0) - , m_pitch(UnknownPitch) - , m_loadingCustomFonts(false) - , m_generation(0) -{ -} - -void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSelector) -{ - releaseFontData(); - m_fontList.clear(); - m_pageZero = 0; - m_pages.clear(); - m_cachedPrimarySimpleFontData = 0; - m_familyIndex = 0; - m_pitch = UnknownPitch; - m_loadingCustomFonts = false; - m_fontSelector = fontSelector; - m_generation = 0; -} - -void FontFallbackList::releaseFontData() -{ - unsigned numFonts = m_fontList.size(); - for (unsigned i = 0; i < numFonts; ++i) { - if (m_fontList[i].second) - delete m_fontList[i].first; - else { - ASSERT(!m_fontList[i].first->isSegmented()); - fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first)); - } - } -} - -void FontFallbackList::determinePitch(const WebCore::Font* font) const -{ - const FontData* fontData = primaryFontData(font); - if (!fontData->isSegmented()) - m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch(); - else { - const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); - unsigned numRanges = segmentedFontData->numRanges(); - if (numRanges == 1) - m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch(); - else - m_pitch = VariablePitch; - } -} - -const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigned index) const -{ - if (index != 0) - return 0; - - // Search for the WebCore font that is already in the list - for (int i = m_fontList.size() - 1; i >= 0; --i) { - pair<const FontData*, bool> item = m_fontList[i]; - // item.second means that the item was created locally or not - if (!item.second) - return item.first; - } - - // Use the FontSelector to get a WebCore font and then fallback to Qt - const FontDescription& description = _font->fontDescription(); - const FontFamily* family = &description.family(); - while (family) { - if (m_fontSelector) { - FontData* data = m_fontSelector->getFontData(description, family->family()); - if (data) { - if (data->isLoading()) - m_loadingCustomFonts = true; - if (!data->isCustomFont()) { - // Custom fonts can be freed anytime so we must not hold them - m_fontList.append(pair<const FontData*, bool>(data, false)); - } - return data; - } - } - family = family->next(); - } - - if (m_fontList.size()) - return m_fontList[0].first; - - const FontData* result = new SimpleFontData(FontPlatformData(description, _font->wordSpacing(), _font->letterSpacing()), true); - m_fontList.append(pair<const FontData*, bool>(result, true)); - return result; -} - -const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const -{ - return primaryFontData(font); -} - -void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData& platformData) -{ - m_familyIndex = cAllFamiliesScanned; -} - -} diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h index 92219fd..4a3f8bc 100644 --- a/WebCore/platform/graphics/qt/FontPlatformData.h +++ b/WebCore/platform/graphics/qt/FontPlatformData.h @@ -26,20 +26,62 @@ #include "FontDescription.h" #include <QFont> +#include <QHash> namespace WebCore { class String; +class FontPlatformDataPrivate { +public: + FontPlatformDataPrivate() + : refCount(1) + , size(font.pointSizeF()) + , bold(font.bold()) + , oblique(false) + {} + FontPlatformDataPrivate(const float size, const bool bold, const bool oblique) + : refCount(1) + , size(size) + , bold(bold) + , oblique(oblique) + {} + FontPlatformDataPrivate(const QFont& font) + : refCount(1) + , font(font) + , size(font.pointSizeF()) + , bold(font.bold()) + , oblique(false) + {} + unsigned refCount; + QFont font; + float size; + bool bold : 1; + bool oblique : 1; +}; + + -class FontPlatformData -{ +class FontPlatformData : public FastAllocBase { public: -#if ENABLE(SVG_FONTS) FontPlatformData(float size, bool bold, bool oblique); -#endif - FontPlatformData(); - FontPlatformData(const FontDescription&, int wordSpacing = 0, int letterSpacing = 0); - FontPlatformData(const QFont&, bool bold); + FontPlatformData(const FontPlatformData &); + FontPlatformData(const FontDescription&, const AtomicString& familyName, int wordSpacing = 0, int letterSpacing = 0); + FontPlatformData(const QFont& font) + : m_data(new FontPlatformDataPrivate(font)) + {} + FontPlatformData(WTF::HashTableDeletedValueType) + : m_data(reinterpret_cast<FontPlatformDataPrivate*>(-1)) + {} + + ~FontPlatformData(); + + FontPlatformData& operator=(const FontPlatformData&); + bool operator==(const FontPlatformData&) const; + + bool isHashTableDeletedValue() const + { + return m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1); + } static inline QFont::Weight toQFontWeight(FontWeight fontWeight) { @@ -62,22 +104,62 @@ public: } } - QFont font() const { return m_font; } - float size() const { return m_size; } - QString family() const { return m_font.family(); } - bool bold() const { return m_bold; } - bool italic() const { return m_font.italic(); } - bool smallCaps() const { return m_font.capitalization() == QFont::SmallCaps; } - int pixelSize() const { return m_font.pixelSize(); } + QFont font() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font; + return QFont(); + } + float size() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->size; + return 0.0f; + } + QString family() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.family(); + return QString(); + } + bool bold() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->bold; + return false; + } + bool italic() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.italic(); + return false; + } + bool smallCaps() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.capitalization() == QFont::SmallCaps; + return false; + } + int pixelSize() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.pixelSize(); + return 0; + } + unsigned hash() const; #ifndef NDEBUG String description() const; #endif - - float m_size; - bool m_bold; - bool m_oblique; - QFont m_font; +private: + FontPlatformDataPrivate* m_data; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp index 7709be6..2cc2fc6 100644 --- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp +++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -26,56 +26,104 @@ namespace WebCore { -FontPlatformData::FontPlatformData(const FontDescription& description, int wordSpacing, int letterSpacing) - : m_size(0.0f) - , m_bold(false) - , m_oblique(false) +static inline bool isEmtpyValue(const float size, const bool bold, const bool oblique) { - QString familyName; + // this is the empty value by definition of the trait FontDataCacheKeyTraits + return !bold && !oblique && size == 0.f; +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) +{ + if (isEmtpyValue(size, bold, oblique)) + m_data = 0; + else + m_data = new FontPlatformDataPrivate(size, bold, oblique); +} + +FontPlatformData::FontPlatformData(const FontPlatformData &other) : m_data(other.m_data) +{ + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) + ++m_data->refCount; +} + +FontPlatformData::FontPlatformData(const FontDescription& description, const AtomicString& familyName, int wordSpacing, int letterSpacing) + : m_data(new FontPlatformDataPrivate()) +{ + QString familyNames(familyName); + if (!familyName.isEmpty()) + familyNames += QLatin1Char(','); + const FontFamily* family = &description.family(); while (family) { - familyName += family->family(); + familyNames += family->family(); family = family->next(); if (family) - familyName += QLatin1Char(','); + familyNames += QLatin1Char(','); } + QFont& font = m_data->font; + font.setFamily(familyName); + font.setPixelSize(qRound(description.computedSize())); + font.setItalic(description.italic()); + font.setWeight(toQFontWeight(description.weight())); + font.setWordSpacing(wordSpacing); + font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); + const bool smallCaps = description.smallCaps(); + font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); + + m_data->bold = font.bold(); + m_data->size = font.pointSizeF(); +} - m_font.setFamily(familyName); - m_font.setPixelSize(qRound(description.computedSize())); - m_font.setItalic(description.italic()); - - m_font.setWeight(toQFontWeight(description.weight())); - m_bold = m_font.bold(); - - bool smallCaps = description.smallCaps(); - m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); - m_font.setWordSpacing(wordSpacing); - m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); - m_size = m_font.pointSize(); +FontPlatformData::~FontPlatformData() +{ + if (!m_data || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return; + --m_data->refCount; + if (!m_data->refCount) + delete m_data; } -FontPlatformData::FontPlatformData(const QFont& font, bool bold) - : m_size(font.pointSize()) - , m_bold(bold) - , m_oblique(false) - , m_font(font) +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) { + if (m_data == other.m_data) + return *this; + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) { + --m_data->refCount; + if (!m_data->refCount) + delete m_data; + } + m_data = other.m_data; + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) + ++m_data->refCount; + return *this; } -#if ENABLE(SVG_FONTS) -FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) - : m_size(size) - , m_bold(bold) - , m_oblique(oblique) +bool FontPlatformData::operator==(const FontPlatformData& other) const { + if (m_data == other.m_data) + return true; + + if (!m_data || !other.m_data + || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1) || other.m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return false; + + const bool equals = (m_data->size == other.m_data->size + && m_data->bold == other.m_data->bold + && m_data->oblique == other.m_data->oblique + && m_data->font == other.m_data->font); + return equals; } -#endif -FontPlatformData::FontPlatformData() - : m_size(0.0f) - , m_bold(false) - , m_oblique(false) +unsigned FontPlatformData::hash() const { + if (!m_data) + return 0; + if (m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return 1; + return qHash(m_data->font.toString()) + ^ qHash(*reinterpret_cast<quint32*>(&m_data->size)) + ^ qHash(m_data->bold) + ^ qHash(m_data->oblique); } #ifndef NDEBUG diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index e8eb923..1e44626 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -42,7 +42,6 @@ #include <limits.h> -#if QT_VERSION >= 0x040400 namespace WebCore { static const QString qstring(const TextRun& run) @@ -197,7 +196,7 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon return w + run.padding(); } -int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const +int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool) const { const QString string = fixSpacing(qstring(run)); QTextLayout layout(string, font()); @@ -229,5 +228,3 @@ QFont Font::font() const } -#endif - diff --git a/WebCore/platform/graphics/qt/FontQt43.cpp b/WebCore/platform/graphics/qt/FontQt43.cpp deleted file mode 100644 index 45bf05d..0000000 --- a/WebCore/platform/graphics/qt/FontQt43.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - Copyright (C) 2008 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 - 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 "Font.h" -#include "FontDescription.h" -#include "FontFallbackList.h" -#include "FontSelector.h" - -#include "GraphicsContext.h" -#include <QTextLayout> -#include <QPainter> -#include <QFontMetrics> -#include <QFontInfo> -#include <qalgorithms.h> -#include <qdebug.h> - -#include <limits.h> - -#if QT_VERSION < 0x040400 - -namespace WebCore { - -struct TextRunComponent { - TextRunComponent() : font(0) {} - TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false); - TextRunComponent(int spaces, bool rtl, const QFont *font, int offset); - - inline bool isSpace() const { return spaces != 0; } - - QString string; - const QFont *font; - int width; - int offset; - int spaces; -}; - -TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc) - : string(reinterpret_cast<const QChar*>(start), length) - , font(f) - , offset(o) - , spaces(0) -{ - if (sc) - string = string.toUpper(); - string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); - width = QFontMetrics(*font).width(string); -} - -TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o) - : string(s, QLatin1Char(' ')) - , font(f) - , offset(o) - , spaces(s) -{ - string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); - width = spaces * QFontMetrics(*font).width(QLatin1Char(' ')); -} - - -static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run) -{ -// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length()); - int letterSpacing = font.letterSpacing(); - int wordSpacing = font.wordSpacing(); - bool smallCaps = font.fontDescription().smallCaps(); - int padding = run.padding(); - int numSpaces = 0; - if (padding) { - for (int i = 0; i < run.length(); i++) - if (Font::treatAsSpace(run[i])) - ++numSpaces; - } - - int offset = 0; - const QFont *f = &font.font(); - if (letterSpacing || smallCaps) { - // need to draw every letter on it's own - int start = 0; - if (Font::treatAsSpace(run[0])) { - int add = 0; - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += add + letterSpacing + components->last().width; - start = 1; -// qDebug() << "space at 0" << offset; - } else if (smallCaps) - f = (QChar::category(run[0]) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); - - for (int i = 1; i < run.length(); ++i) { - uint ch = run[i]; - if (QChar(ch).isHighSurrogate() && QChar(run[i-1]).isLowSurrogate()) - ch = QChar::surrogateToUcs4(ch, run[i-1]); - if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing) - continue; - if (Font::treatAsSpace(run[i])) { - int add = 0; -// qDebug() << " treatAsSpace:" << i << start; - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width + letterSpacing; -// qDebug() << " appending(1) " << components->last().string << components->last().width; - } - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += wordSpacing + add + components->last().width + letterSpacing; - start = i + 1; - continue; - } else if (!letterSpacing) { -// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) << -// QFontInfo(*f).pointSizeF(); - if (QChar::category(ch) == QChar::Letter_Lowercase) { - if (f == &font.scFont()) - continue; - } else { - if (f == &font.font()) - continue; - } - } - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width + letterSpacing; -// qDebug() << " appending(2) " << components->last().string << components->last().width; - } - if (smallCaps) - f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); - start = i; - } - if (run.length() - start > 0) { - components->append(TextRunComponent(run.characters() + start, run.length() - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width; -// qDebug() << " appending(3) " << components->last().string << components->last().width; - } - offset += letterSpacing; - } else { - int start = 0; - for (int i = 0; i < run.length(); ++i) { - if (Font::treatAsSpace(run[i])) { - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset)); - offset += components->last().width; - } - int add = 0; - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += add + components->last().width; - if (i) - offset += wordSpacing; - start = i + 1; - } - } - if (run.length() - start > 0) { - components->append(TextRunComponent(run.characters() + start, run.length() - start, - run.rtl(), - f, offset)); - offset += components->last().width; - } - } - return offset; -} - -void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const -{ - if (to < 0) - to = run.length(); - - QPainter *p = ctx->platformContext(); - Color color = ctx->fillColor(); - p->setPen(QColor(color)); - - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - if (from > 0 || to < run.length()) { - FloatRect clip = selectionRectForComplexText(run, - IntPoint(qRound(point.x()), qRound(point.y())), - QFontMetrics(font()).height(), from, to); - QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height()); - p->save(); - p->setClipRect(rect.toRect()); - } - - if (run.rtl()) { - for (int i = 0; i < components.size(); ++i) { - if (!components.at(i).isSpace()) { - p->setFont(*components.at(i).font); - QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y()); - p->drawText(pt, components.at(i).string); - } - } - } else { - for (int i = 0; i < components.size(); ++i) { - if (!components.at(i).isSpace()) { - p->setFont(*components.at(i).font); - QPointF pt(point.x() + components.at(i).offset, point.y()); - p->drawText(pt, components.at(i).string); - } - } - } - if (from > 0 || to < run.length()) - p->restore(); -} - -float Font::floatWidthForComplexText(const TextRun& run) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - return w; -} - -int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - int offset = 0; - if (run.rtl()) { - for (int i = 0; i < components.size(); ++i) { - int xe = w - components.at(i).offset; - int xs = xe - components.at(i).width; - if (position >= xs) { - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return offset; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - if (position - xs >= l.width()) - return offset; - int cursor = l.xToCursor(position - xs); - if (cursor > 1) - --cursor; - return offset + cursor; - } else - offset += components.at(i).string.length() - 1; - } - } else { - for (int i = 0; i < components.size(); ++i) { - int xs = components.at(i).offset; - int xe = xs + components.at(i).width; - if (position <= xe) { - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return offset; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - if (position - xs >= l.width()) - return offset + components.at(i).string.length() - 1; - int cursor = l.xToCursor(position - xs); - if (cursor > 1) - --cursor; - return offset + cursor; - } else - offset += components.at(i).string.length() - 1; - } - } - return run.length(); -} - -static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor) -{ - int start = 0; - for (int i = 0; i < components.size(); ++i) { - if (start + components.at(i).string.length() - 1 < cursor) { - start += components.at(i).string.length() - 1; - continue; - } - int xs = components.at(i).offset; - if (rtl) - xs = width - xs - components.at(i).width; - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return 0; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - return xs + l.cursorToX(cursor - start + 1); - } - return width; -} - -FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, - int h, int from, int to) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - if (from == 0 && to == run.length()) - return FloatRect(pt.x(), pt.y(), w, h); - - float x1 = cursorToX(components, w, run.rtl(), from); - float x2 = cursorToX(components, w, run.rtl(), to); - if (x2 < x1) - qSwap(x1, x2); - - return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); -} - -int Font::lineGap() const -{ - return QFontMetrics(m_font).leading(); -} - -} - -#endif diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index e259a4e..a095476 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -34,29 +34,29 @@ */ #include "config.h" +#include "GraphicsContext.h" #ifdef Q_WS_WIN #include <windows.h> #endif -#include "TransformationMatrix.h" #include "Color.h" #include "FloatConversion.h" #include "Font.h" -#include "GraphicsContext.h" #include "GraphicsContextPrivate.h" #include "ImageBuffer.h" +#include "NotImplemented.h" #include "Path.h" #include "Pattern.h" #include "Pen.h" -#include "NotImplemented.h" +#include "TransformationMatrix.h" #include <QBrush> #include <QDebug> #include <QGradient> -#include <QPainter> #include <QPaintDevice> #include <QPaintEngine> +#include <QPainter> #include <QPainterPath> #include <QPixmap> #include <QPolygonF> @@ -72,35 +72,35 @@ namespace WebCore { static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op) { switch (op) { - case CompositeClear: - return QPainter::CompositionMode_Clear; - case CompositeCopy: - return QPainter::CompositionMode_Source; - case CompositeSourceOver: - return QPainter::CompositionMode_SourceOver; - case CompositeSourceIn: - return QPainter::CompositionMode_SourceIn; - case CompositeSourceOut: - return QPainter::CompositionMode_SourceOut; - case CompositeSourceAtop: - return QPainter::CompositionMode_SourceAtop; - case CompositeDestinationOver: - return QPainter::CompositionMode_DestinationOver; - case CompositeDestinationIn: - return QPainter::CompositionMode_DestinationIn; - case CompositeDestinationOut: - return QPainter::CompositionMode_DestinationOut; - case CompositeDestinationAtop: - return QPainter::CompositionMode_DestinationAtop; - case CompositeXOR: - return QPainter::CompositionMode_Xor; - case CompositePlusDarker: - // there is no exact match, but this is the closest - return QPainter::CompositionMode_Darken; - case CompositeHighlight: - return QPainter::CompositionMode_SourceOver; - case CompositePlusLighter: - return QPainter::CompositionMode_Plus; + case CompositeClear: + return QPainter::CompositionMode_Clear; + case CompositeCopy: + return QPainter::CompositionMode_Source; + case CompositeSourceOver: + return QPainter::CompositionMode_SourceOver; + case CompositeSourceIn: + return QPainter::CompositionMode_SourceIn; + case CompositeSourceOut: + return QPainter::CompositionMode_SourceOut; + case CompositeSourceAtop: + return QPainter::CompositionMode_SourceAtop; + case CompositeDestinationOver: + return QPainter::CompositionMode_DestinationOver; + case CompositeDestinationIn: + return QPainter::CompositionMode_DestinationIn; + case CompositeDestinationOut: + return QPainter::CompositionMode_DestinationOut; + case CompositeDestinationAtop: + return QPainter::CompositionMode_DestinationAtop; + case CompositeXOR: + return QPainter::CompositionMode_Xor; + case CompositePlusDarker: + // there is no exact match, but this is the closest + return QPainter::CompositionMode_Darken; + case CompositeHighlight: + return QPainter::CompositionMode_SourceOver; + case CompositePlusLighter: + return QPainter::CompositionMode_Plus; } return QPainter::CompositionMode_SourceOver; @@ -109,12 +109,12 @@ static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op static inline Qt::PenCapStyle toQtLineCap(LineCap lc) { switch (lc) { - case ButtCap: - return Qt::FlatCap; - case RoundCap: - return Qt::RoundCap; - case SquareCap: - return Qt::SquareCap; + case ButtCap: + return Qt::FlatCap; + case RoundCap: + return Qt::RoundCap; + case SquareCap: + return Qt::SquareCap; } return Qt::FlatCap; @@ -123,12 +123,12 @@ static inline Qt::PenCapStyle toQtLineCap(LineCap lc) static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj) { switch (lj) { - case MiterJoin: - return Qt::SvgMiterJoin; - case RoundJoin: - return Qt::RoundJoin; - case BevelJoin: - return Qt::BevelJoin; + case MiterJoin: + return Qt::SvgMiterJoin; + case RoundJoin: + return Qt::RoundJoin; + case BevelJoin: + return Qt::BevelJoin; } return Qt::MiterJoin; @@ -210,8 +210,8 @@ public: return redirect; return painter; - } else - return &layers.top()->painter; + } + return &layers.top()->painter; } bool antiAliasingForRectsAndLines; @@ -256,8 +256,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) setPaintingDisabled(!context); if (context) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } } @@ -411,46 +411,25 @@ void GraphicsContext::drawRect(const IntRect& rect) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (getShadow(shadowSize, shadowBlur, shadowColor)) { + IntRect shadowRect = rect; + shadowRect.move(shadowSize.width(), shadowSize.height()); + shadowRect.inflate(static_cast<int>(p->pen().widthF())); + p->fillRect(shadowRect, QColor(shadowColor)); + } + p->drawRect(rect); p->setRenderHint(QPainter::Antialiasing, antiAlias); } -// FIXME: Now that this is refactored, it should be shared by all contexts. -static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, - const StrokeStyle& penStyle) -{ - // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic - // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., - // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave - // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. - if (penStyle == DottedStroke || penStyle == DashedStroke) { - if (p1.x() == p2.x()) { - p1.setY(p1.y() + strokeWidth); - p2.setY(p2.y() - strokeWidth); - } else { - p1.setX(p1.x() + strokeWidth); - p2.setX(p2.x() - strokeWidth); - } - } - - if (((int) strokeWidth) % 2) { - if (p1.x() == p2.x()) { - // We're a vertical line. Adjust our x. - p1.setX(p1.x() + 0.5); - p2.setX(p2.x() + 0.5); - } else { - // We're a horizontal line. Adjust our y. - p1.setY(p1.y() + 0.5); - p2.setY(p2.y() + 0.5); - } - } -} - // This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { @@ -468,7 +447,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) FloatPoint p2 = point2; bool isVerticalLine = (p1.x() == p2.x()); - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); adjustLineToPixelBoundaries(p1, p2, width, style); @@ -479,22 +458,22 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (textDrawingMode() == cTextFill && getShadow(shadowSize, shadowBlur, shadowColor)) { p->save(); p->translate(shadowSize.width(), shadowSize.height()); - p->setPen(QColor(shadowColor)); + p->setPen(shadowColor); p->drawLine(p1, p2); p->restore(); } int patWidth = 0; switch (style) { - case NoStroke: - case SolidStroke: - break; - case DottedStroke: - patWidth = (int)width; - break; - case DashedStroke: - patWidth = 3 * (int)width; - break; + case NoStroke: + case SolidStroke: + break; + case DottedStroke: + patWidth = static_cast<int>(width); + break; + case DashedStroke: + patWidth = 3 * static_cast<int>(width); + break; } if (patWidth) { @@ -523,7 +502,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth == 1) patternOffset = 1.0f; else { - bool evenNumberOfSegments = numSegments % 2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { @@ -571,11 +550,25 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, true); - p->drawArc(rect, startAngle * 16, angleSpan * 16); + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + startAngle *= 16; + angleSpan *= 16; + if (getShadow(shadowSize, shadowBlur, shadowColor)) { + p->save(); + p->translate(shadowSize.width(), shadowSize.height()); + QPen pen(p->pen()); + pen.setColor(shadowColor); + p->setPen(pen); + p->drawArc(rect, startAngle, angleSpan); + p->restore(); + } + p->drawArc(rect, startAngle, angleSpan); p->setRenderHint(QPainter::Antialiasing, antiAlias); } @@ -593,9 +586,25 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points for (size_t i = 0; i < npoints; i++) polygon[i] = points[i]; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); p->save(); p->setRenderHint(QPainter::Antialiasing, shouldAntialias); + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (getShadow(shadowSize, shadowBlur, shadowColor)) { + p->save(); + p->translate(shadowSize.width(), shadowSize.height()); + if (p->brush().style() != Qt::NoBrush) + p->setBrush(QBrush(shadowColor)); + QPen pen(p->pen()); + if (pen.style() != Qt::NoPen) { + pen.setColor(shadowColor); + p->setPen(pen); + } + p->drawConvexPolygon(polygon); + p->restore(); + } p->drawConvexPolygon(polygon); p->restore(); } @@ -605,34 +614,44 @@ QPen GraphicsContext::pen() if (paintingDisabled()) return QPen(); - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); return p->pen(); } +static void inline drawFilledShadowPath(GraphicsContext* context, QPainter* p, const QPainterPath *path) +{ + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { + p->translate(shadowSize.width(), shadowSize.height()); + p->fillPath(*path, QBrush(shadowColor)); + p->translate(-shadowSize.width(), -shadowSize.height()); + } +} + void GraphicsContext::fillPath() { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPainterPath path = m_data->currentPath; path.setFillRule(toQtFillRule(fillRule())); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - if (fillColor().alpha()) - p->fillPath(path, p->brush()); - break; - case PatternColorSpace: { - TransformationMatrix affine; - p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - break; - } - case GradientColorSpace: - QBrush brush(*m_common->state.fillGradient->platformGradient()); - brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); - p->fillPath(path, brush); - break; + if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) { + drawFilledShadowPath(this, p, &path); + if (m_common->state.fillPattern) { + TransformationMatrix affine; + p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); + } else if (m_common->state.fillGradient) { + QBrush brush(*m_common->state.fillGradient->platformGradient()); + brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); + p->fillPath(path, brush); + } else { + if (fillColor().alpha()) + p->fillPath(path, p->brush()); + } } m_data->currentPath = QPainterPath(); } @@ -642,77 +661,97 @@ void GraphicsContext::strokePath() if (paintingDisabled()) return; - QPainter *p = m_data->p(); - QPen pen = p->pen(); + QPainter* p = m_data->p(); + QPen pen(p->pen()); QPainterPath path = m_data->currentPath; path.setFillRule(toQtFillRule(fillRule())); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - if (strokeColor().alpha()) + if (m_common->state.strokePattern || m_common->state.strokeGradient || strokeColor().alpha()) { + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (getShadow(shadowSize, shadowBlur, shadowColor)) { + QTransform t(p->worldTransform()); + p->translate(shadowSize.width(), shadowSize.height()); + QPen shadowPen(pen); + shadowPen.setColor(shadowColor); + p->strokePath(path, shadowPen); + p->setWorldTransform(t); + } + if (m_common->state.strokePattern) { + TransformationMatrix affine; + pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine))); + p->setPen(pen); p->strokePath(path, pen); - break; - case PatternColorSpace: { - TransformationMatrix affine; - pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine))); - p->setPen(pen); - p->strokePath(path, pen); - break; - } - case GradientColorSpace: { - QBrush brush(*m_common->state.strokeGradient->platformGradient()); - brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform()); - pen.setBrush(brush); - p->setPen(pen); - p->strokePath(path, pen); - break; - } + } else if (m_common->state.strokeGradient) { + QBrush brush(*m_common->state.strokeGradient->platformGradient()); + brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform()); + pen.setBrush(brush); + p->setPen(pen); + p->strokePath(path, pen); + } else { + if (strokeColor().alpha()) + p->strokePath(path, pen); + } } m_data->currentPath = QPainterPath(); } +static inline void drawBorderlessRectShadow(GraphicsContext* context, QPainter* p, const FloatRect& rect) +{ + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { + FloatRect shadowRect(rect); + shadowRect.move(shadowSize.width(), shadowSize.height()); + p->fillRect(shadowRect, QColor(shadowColor)); + } +} + void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - if (fillColor().alpha()) - p->fillRect(rect, p->brush()); - break; - case PatternColorSpace: { - TransformationMatrix affine; - p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - break; - } - case GradientColorSpace: - QBrush brush(*m_common->state.fillGradient->platformGradient()); - brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); - p->fillRect(rect, brush); - break; + if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) { + drawBorderlessRectShadow(this, p, rect); + if (m_common->state.fillPattern) { + TransformationMatrix affine; + p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); + } else if (m_common->state.fillGradient) { + QBrush brush(*m_common->state.fillGradient->platformGradient()); + brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); + p->fillRect(rect, brush); + } else { + if (fillColor().alpha()) + p->fillRect(rect, p->brush()); + } } - m_data->currentPath = QPainterPath(); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& c, ColorSpace colorSpace) { if (paintingDisabled()) return; - m_data->solidColor.setColor(QColor(c)); - m_data->p()->fillRect(rect, m_data->solidColor); + m_data->solidColor.setColor(c); + QPainter* p = m_data->p(); + drawBorderlessRectShadow(this, p, rect); + p->fillRect(rect, m_data->solidColor); } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled() || !color.alpha()) return; Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight); - m_data->p()->fillPath(*path.platformPath(), QColor(color)); + QPainter* p = m_data->p(); + drawFilledShadowPath(this, p, path.platformPath()); + p->fillPath(*path.platformPath(), QColor(color)); } void GraphicsContext::beginPath() @@ -750,7 +789,7 @@ void GraphicsContext::clipPath(WindRule clipRule) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPainterPath newPath = m_data->currentPath; newPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); p->setClipPath(newPath); @@ -769,10 +808,10 @@ void GraphicsContext::drawFocusRing(const Color& color) const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); - if (rects.size() == 0) + if (!rects.size()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); @@ -793,7 +832,7 @@ void GraphicsContext::drawFocusRing(const Color& color) QPainterPath newPath = stroker.createStroke(path); p->strokePath(newPath, nPen); #else - for (int i = 0; i < rectCount; ++i) + for (unsigned i = 0; i < rectCount; ++i) p->drawRect(QRectF(rects[i])); #endif p->setPen(oldPen); @@ -802,7 +841,7 @@ void GraphicsContext::drawFocusRing(const Color& color) p->setRenderHint(QPainter::Antialiasing, antiAlias); } -void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool) { if (paintingDisabled()) return; @@ -811,8 +850,7 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool pr drawLine(origin, endPoint); } -void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, - int width, bool grammar) +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int, bool) { if (paintingDisabled()) return; @@ -829,10 +867,16 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) return FloatRect(QRectF(result)); } -void GraphicsContext::setPlatformShadow(const IntSize& pos, int blur, const Color &color) +void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&, ColorSpace) { // Qt doesn't support shadows natively, they are drawn manually in the draw* // functions + + if (m_common->state.shadowsIgnoreTransforms) { + // Meaning that this graphics context is associated with a CanvasRenderingContext + // We flip the height since CG and HTML5 Canvas have opposite Y axis + m_common->state.shadowSize = IntSize(size.width(), -size.height()); + } } void GraphicsContext::clearPlatformShadow() @@ -848,8 +892,8 @@ void GraphicsContext::beginTransparencyLayer(float opacity) int x, y, w, h; x = y = 0; - QPainter *p = m_data->p(); - const QPaintDevice *device = p->device(); + QPainter* p = m_data->p(); + const QPaintDevice* device = p->device(); w = device->width(); h = device->height(); @@ -871,10 +915,10 @@ void GraphicsContext::endTransparencyLayer() if (paintingDisabled()) return; - TransparencyLayer *layer = m_data->layers.pop(); + TransparencyLayer* layer = m_data->layers.pop(); layer->painter.end(); - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); p->save(); p->resetTransform(); p->setOpacity(layer->opacity); @@ -889,7 +933,7 @@ void GraphicsContext::clearRect(const FloatRect& rect) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPainter::CompositionMode currentCompositionMode = p->compositionMode(); if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) p->setCompositionMode(QPainter::CompositionMode_Source); @@ -916,7 +960,7 @@ void GraphicsContext::setLineCap(LineCap lc) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen nPen = p->pen(); nPen.setCapStyle(toQtLineCap(lc)); p->setPen(nPen); @@ -948,7 +992,7 @@ void GraphicsContext::setLineJoin(LineJoin lj) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen nPen = p->pen(); nPen.setJoinStyle(toQtLineJoin(lj)); p->setPen(nPen); @@ -959,7 +1003,7 @@ void GraphicsContext::setMiterLimit(float limit) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen nPen = p->pen(); nPen.setMiterLimit(limit); p->setPen(nPen); @@ -969,7 +1013,7 @@ void GraphicsContext::setAlpha(float opacity) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); p->setOpacity(opacity); } @@ -990,20 +1034,29 @@ void GraphicsContext::clip(const Path& path) m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); - QRectF clipBounds = p->clipPath().boundingRect(); + QPainter* p = m_data->p(); QPainterPath clippedOut = *path.platformPath(); QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); - newClip.addRect(clipBounds); - newClip.addPath(clippedOut); - - p->setClipPath(newClip, Qt::IntersectClip); + if (p->hasClipping()) { + newClip.addRect(p->clipPath().boundingRect()); + newClip.addPath(clippedOut); + p->setClipPath(newClip, Qt::IntersectClip); + } else { + newClip.addRect(p->window()); + newClip.addPath(clippedOut & newClip); + p->setClipPath(newClip); + } } void GraphicsContext::translate(float x, float y) @@ -1061,14 +1114,21 @@ void GraphicsContext::clipOut(const IntRect& rect) if (paintingDisabled()) return; - QPainter *p = m_data->p(); - QRectF clipBounds = p->clipPath().boundingRect(); + QPainter* p = m_data->p(); QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); - newClip.addRect(clipBounds); - newClip.addRect(QRect(rect)); - - p->setClipPath(newClip, Qt::IntersectClip); + if (p->hasClipping()) { + newClip.addRect(p->clipPath().boundingRect()); + newClip.addRect(QRect(rect)); + p->setClipPath(newClip, Qt::IntersectClip); + } else { + QRect clipOutRect(rect); + QRect window(p->window()); + clipOutRect &= window; + newClip.addRect(window); + newClip.addRect(clipOutRect); + p->setClipPath(newClip); + } } void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) @@ -1076,14 +1136,21 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) if (paintingDisabled()) return; - QPainter *p = m_data->p(); - QRectF clipBounds = p->clipPath().boundingRect(); + QPainter* p = m_data->p(); QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); - newClip.addRect(clipBounds); - newClip.addEllipse(QRect(rect)); - - p->setClipPath(newClip, Qt::IntersectClip); + if (p->hasClipping()) { + newClip.addRect(p->clipPath().boundingRect()); + newClip.addEllipse(QRect(rect)); + p->setClipPath(newClip, Qt::IntersectClip); + } else { + QRect clipOutRect(rect); + QRect window(p->window()); + clipOutRect &= window; + newClip.addRect(window); + newClip.addEllipse(clipOutRect); + p->setClipPath(newClip); + } } void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) @@ -1109,7 +1176,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, path.setFillRule(Qt::OddEvenFill); - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, true); @@ -1134,16 +1201,16 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform) } } -void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +void GraphicsContext::setURLForRect(const KURL&, const IntRect&) { notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen newPen(p->pen()); newPen.setColor(color); p->setPen(newPen); @@ -1153,7 +1220,7 @@ void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen newPen(p->pen()); newPen.setStyle(toQPenStyle(strokeStyle)); p->setPen(newPen); @@ -1163,13 +1230,13 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen newPen(p->pen()); newPen.setWidthF(thickness); p->setPen(newPen); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1184,7 +1251,6 @@ void GraphicsContext::setPlatformShouldAntialias(bool enable) } #ifdef Q_WS_WIN -#include <windows.h> HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp index 34c3c47..a9870fc 100644 --- a/WebCore/platform/graphics/qt/IconQt.cpp +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -40,15 +40,17 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) -{ - RefPtr<Icon> i = adoptRef(new Icon); - i->m_icon = QIcon(filename); - return i.release(); -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { + if (filenames.isEmpty()) + return 0; + + if (filenames.size() == 1) { + RefPtr<Icon> i = adoptRef(new Icon); + i->m_icon = QIcon(filenames[0]); + return i.release(); + } + //FIXME: Implement this return 0; } diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index 22a5a43..5255428 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -68,7 +68,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) painter->setCompositionMode(QPainter::CompositionMode_SourceOver); } -ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace, bool& success) : m_data(size) , m_size(size) { @@ -125,12 +125,13 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) m_data.m_painter->begin(&m_data.m_pixmap); } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +template <Multiply multiplied> +PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size) { PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* data = result->data()->data()->data(); - if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height()) + if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) memset(data, 0, result->data()->length()); int originx = rect.x(); @@ -140,8 +141,8 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originx = 0; } int endx = rect.x() + rect.width(); - if (endx > m_size.width()) - endx = m_size.width(); + if (endx > size.width()) + endx = size.width(); int numColumns = endx - originx; int originy = rect.y(); @@ -151,11 +152,16 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originy = 0; } int endy = rect.y() + rect.height(); - if (endy > m_size.height()) - endy = m_size.height(); + if (endy > size.height()) + endy = size.height(); int numRows = endy - originy; - QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32); + QImage image = imageData.m_pixmap.toImage(); + if (multiplied == Unmultiplied) + image = image.convertToFormat(QImage::Format_ARGB32); + else + image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + ASSERT(!image.isNull()); unsigned destBytesPerRow = 4 * rect.width(); @@ -176,7 +182,18 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData<Unmultiplied>(rect, m_data, m_size); +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<Premultiplied>(rect, m_data, m_size); +} + +template <Multiply multiplied> +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -184,49 +201,65 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); - ASSERT(destx < m_size.width()); + ASSERT(destx < size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.right()); int endx = destPoint.x() + sourceRect.right(); - ASSERT(endx <= m_size.width()); + ASSERT(endx <= size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); - ASSERT(desty < m_size.height()); + ASSERT(desty < size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.bottom()); int endy = destPoint.y() + sourceRect.bottom(); - ASSERT(endy <= m_size.height()); + ASSERT(endy <= size.height()); int numRows = endy - desty; unsigned srcBytesPerRow = 4 * source->width(); - bool isPainting = m_data.m_painter->isActive(); + bool isPainting = data.m_painter->isActive(); if (isPainting) - m_data.m_painter->end(); + data.m_painter->end(); - QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32); + QImage image = data.m_pixmap.toImage(); + if (multiplied == Unmultiplied) + image = image.convertToFormat(QImage::Format_ARGB32); + else + image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; for (int y = 0; y < numRows; ++y) { quint32* scanLine = reinterpret_cast<quint32*>(image.scanLine(y + desty)); for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - scanLine[x + destx] = reinterpret_cast<quint32*>(srcRows + basex)[0]; + // ImageData stores the pixels in RGBA while QImage is ARGB + quint32 pixel = reinterpret_cast<quint32*>(srcRows + 4 * x)[0]; + pixel = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00); + scanLine[x + destx] = pixel; } srcRows += srcBytesPerRow; } - m_data.m_pixmap = QPixmap::fromImage(image); + data.m_pixmap = QPixmap::fromImage(image); if (isPainting) - m_data.m_painter->begin(&m_data.m_pixmap); + data.m_painter->begin(&data.m_pixmap); +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size); } // We get a mimeType here but QImageWriter does not support mimetypes but diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 7bbdcc0..b6823dd 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -35,303 +35,205 @@ #include <QtGui/QImageReader> #include <qdebug.h> -namespace { - const QImage::Format DesiredFormat = QImage::Format_ARGB32; - const bool debugImageDecoderQt = false; -} - namespace WebCore { -ImageDecoderQt::ImageData::ImageData(const QImage& image, ImageState imageState, int duration) : - m_image(image), m_imageState(imageState), m_duration(duration) -{ -} - -// Context, maintains IODevice on a data buffer. -class ImageDecoderQt::ReadContext { -public: - enum LoadMode { - // Load images incrementally. This is still experimental and - // will cause the image plugins to report errors. - // Also note that as of Qt 4.2.2, the JPEG loader does not return error codes - // on "preliminary end of data". - LoadIncrementally, - // Load images only if all data have been received - LoadComplete }; - - ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target); - - enum ReadResult { ReadEOF, ReadFailed, ReadPartial, ReadComplete }; +ImageDecoder* ImageDecoder::create(const SharedBuffer& data) +{ + // We need at least 4 bytes to figure out what kind of image we're dealing with. + if (data.size() < 4) + return 0; - // Append data and read out all images. Returns the result - // of the last read operation, so, even if ReadPartial is returned, - // a few images might have been read. - ReadResult read(bool allDataReceived); + return new ImageDecoderQt; +} - QImageReader *reader() { return &m_reader; } +ImageDecoderQt::ImageDecoderQt() + : m_buffer(0) + , m_reader(0) + , m_repetitionCount(cAnimationNone) +{ +} -private: - enum IncrementalReadResult { IncrementalReadFailed, IncrementalReadPartial, IncrementalReadComplete }; - // Incrementally read an image - IncrementalReadResult readImageLines(ImageData &); +ImageDecoderQt::~ImageDecoderQt() +{ + delete m_reader; + delete m_buffer; +} - const LoadMode m_loadMode; +void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) +{ + if (m_failed) + return; - QByteArray m_data; - QBuffer m_buffer; - QImageReader m_reader; + // No progressive loading possible + if (!allDataReceived) + return; - ImageList &m_target; + // Cache our own new data. + ImageDecoder::setData(data, allDataReceived); - // Detected data format of the stream - enum QImage::Format m_dataFormat; - QSize m_size; + // We expect to be only called once with allDataReceived + ASSERT(!m_buffer); + ASSERT(!m_reader); -}; + // Attempt to load the data + QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size()); + m_buffer = new QBuffer; + m_buffer->setData(imageData); + m_buffer->open(QBuffer::ReadOnly); + m_reader = new QImageReader(m_buffer, m_format); +} -ImageDecoderQt::ReadContext::ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target) - : m_loadMode(loadMode) - , m_data(data.data(), data.size()) - , m_buffer(&m_data) - , m_reader(&m_buffer) - , m_target(target) - , m_dataFormat(QImage::Format_Invalid) +bool ImageDecoderQt::isSizeAvailable() { - m_buffer.open(QIODevice::ReadOnly); -} + if (!ImageDecoder::isSizeAvailable() && m_reader) + internalDecodeSize(); + return ImageDecoder::isSizeAvailable(); +} -ImageDecoderQt::ReadContext::ReadResult - ImageDecoderQt::ReadContext::read(bool allDataReceived) +size_t ImageDecoderQt::frameCount() { - // Complete mode: Read only all all data received - if (m_loadMode == LoadComplete && !allDataReceived) - return ReadPartial; - - // Attempt to read out all images - while (true) { - if (m_target.empty() || m_target.back().m_imageState == ImageComplete) { - // Start a new image. - if (!m_reader.canRead()) - return ReadEOF; - - // Attempt to construct an empty image of the matching size and format - // for efficient reading - QImage newImage = m_dataFormat != QImage::Format_Invalid ? - QImage(m_size, m_dataFormat) : QImage(); - m_target.push_back(ImageData(newImage)); - } + if (m_frameBufferCache.isEmpty() && m_reader) { + if (m_reader->supportsAnimation()) { + int imageCount = m_reader->imageCount(); - // read chunks - switch (readImageLines(m_target.back())) { - case IncrementalReadFailed: - m_target.pop_back(); - return ReadFailed; - case IncrementalReadPartial: - return ReadPartial; - case IncrementalReadComplete: - m_target.back().m_imageState = ImageComplete; - //store for next - m_dataFormat = m_target.back().m_image.format(); - m_size = m_target.back().m_image.size(); - const bool supportsAnimation = m_reader.supportsAnimation(); - - if (debugImageDecoderQt) - qDebug() << "readImage(): #" << m_target.size() << " complete, " << m_size - << " format " << m_dataFormat << " supportsAnimation=" << supportsAnimation; - // No point in readinfg further - if (!supportsAnimation) - return ReadComplete; - - break; + // Fixup for Qt decoders... imageCount() is wrong + // and jumpToNextImage does not work either... so + // we will have to parse everything... + if (imageCount == 0) + forceLoadEverything(); + else + m_frameBufferCache.resize(imageCount); + } else { + m_frameBufferCache.resize(1); } } - return ReadComplete; + + return m_frameBufferCache.size(); } +int ImageDecoderQt::repetitionCount() const +{ + if (m_reader && m_reader->supportsAnimation()) + m_repetitionCount = qMax(0, m_reader->loopCount()); + return m_repetitionCount; +} -ImageDecoderQt::ReadContext::IncrementalReadResult - ImageDecoderQt::ReadContext::readImageLines(ImageData &imageData) +String ImageDecoderQt::filenameExtension() const { - // TODO: Implement incremental reading here, - // set state to reflect complete header, etc. - // For now, we read the whole image. - - const qint64 startPos = m_buffer.pos(); - // Oops, failed. Rewind. - if (!m_reader.read(&imageData.m_image)) { - m_buffer.seek(startPos); - const bool gotHeader = imageData.m_image.size().width(); - - if (debugImageDecoderQt) - qDebug() << "readImageLines(): read() failed: " << m_reader.errorString() - << " got header=" << gotHeader; - // [Experimental] Did we manage to read the header? - if (gotHeader) { - imageData.m_imageState = ImageHeaderValid; - return IncrementalReadPartial; - } - return IncrementalReadFailed; - } - imageData.m_duration = m_reader.nextImageDelay(); - return IncrementalReadComplete; -} + return String(m_format.constData(), m_format.length()); +}; -ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data) +RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) { - // We need at least 4 bytes to figure out what kind of image we're dealing with. - if (data.size() < 4) - return 0; + // In case the ImageDecoderQt got recreated we don't know + // yet how many images we are going to have and need to + // find that out now. + int count = m_frameBufferCache.size(); + if (!m_failed && count == 0) { + internalDecodeSize(); + count = frameCount(); + } - QByteArray bytes = QByteArray::fromRawData(data.data(), data.size()); - QBuffer buffer(&bytes); - if (!buffer.open(QBuffer::ReadOnly)) + if (index >= static_cast<size_t>(count)) return 0; - QString imageFormat = QString::fromLatin1(QImageReader::imageFormat(&buffer).toLower()); - if (imageFormat.isEmpty()) - return 0; // Image format not supported - - return new ImageDecoderQt(imageFormat); + RGBA32Buffer& frame = m_frameBufferCache[index]; + if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) + internalReadImage(index); + return &frame; } -ImageDecoderQt::ImageDecoderQt(const QString &imageFormat) - : m_hasAlphaChannel(false) - , m_imageFormat(imageFormat) +void ImageDecoderQt::clearFrameBufferCache(size_t /*index*/) { } -ImageDecoderQt::~ImageDecoderQt() +void ImageDecoderQt::internalDecodeSize() { -} + ASSERT(m_reader); -bool ImageDecoderQt::hasFirstImageHeader() const -{ - return !m_imageList.empty() && m_imageList[0].m_imageState >= ImageHeaderValid; -} + // If we have a QSize() something failed + QSize size = m_reader->size(); + if (size.isEmpty()) + return failRead(); -void ImageDecoderQt::reset() -{ - m_hasAlphaChannel = false; - m_failed = false; - m_imageList.clear(); - m_pixmapCache.clear(); - m_loopCount = cAnimationNone; + m_format = m_reader->format(); + setSize(size.width(), size.height()); } -void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) +void ImageDecoderQt::internalReadImage(size_t frameIndex) { - reset(); - ReadContext readContext(data, ReadContext::LoadComplete, m_imageList); - - if (debugImageDecoderQt) - qDebug() << " setData " << data.size() << " image bytes, complete=" << allDataReceived; - - const ReadContext::ReadResult readResult = readContext.read(allDataReceived); - - if (hasFirstImageHeader()) - m_hasAlphaChannel = m_imageList[0].m_image.hasAlphaChannel(); - - if (debugImageDecoderQt) - qDebug() << " read returns " << readResult; - - switch (readResult) { - case ReadContext::ReadFailed: - m_failed = true; - break; - case ReadContext::ReadEOF: - case ReadContext::ReadPartial: - case ReadContext::ReadComplete: - // Did we read anything - try to set the size. - if (hasFirstImageHeader()) { - QSize imgSize = m_imageList[0].m_image.size(); - setSize(imgSize.width(), imgSize.height()); - - if (readContext.reader()->supportsAnimation()) { - if (readContext.reader()->loopCount() != -1) - m_loopCount = readContext.reader()->loopCount(); - else - m_loopCount = 0; //loop forever - } - } - break; - } -} + ASSERT(m_reader); + if (m_reader->supportsAnimation()) + m_reader->jumpToImage(frameIndex); + else if (frameIndex != 0) + return failRead(); -bool ImageDecoderQt::isSizeAvailable() -{ - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << ImageDecoder::isSizeAvailable(); - return ImageDecoder::isSizeAvailable(); -} + internalHandleCurrentImage(frameIndex); -size_t ImageDecoderQt::frameCount() const -{ - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::frameCount() returns" << m_imageList.size(); - return m_imageList.size(); -} + // Attempt to return some memory + for (int i = 0; i < m_frameBufferCache.size(); ++i) + if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete) + return; -int ImageDecoderQt::repetitionCount() const -{ - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::repetitionCount() returns" << m_loopCount; - return m_loopCount; + delete m_reader; + delete m_buffer; + m_buffer = 0; + m_reader = 0; } -bool ImageDecoderQt::supportsAlpha() const +void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) { - return m_hasAlphaChannel; -} + // Now get the QImage from Qt and place it in the RGBA32Buffer + QImage img; + if (!m_reader->read(&img)) + return failRead(); -int ImageDecoderQt::duration(size_t index) const -{ - if (index >= m_imageList.size()) - return 0; - return m_imageList[index].m_duration; + // now into the RGBA32Buffer - even if the image is not + QSize imageSize = img.size(); + RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex]; + buffer->setRect(m_reader->currentImageRect()); + buffer->setStatus(RGBA32Buffer::FrameComplete); + buffer->setDuration(m_reader->nextImageDelay()); + buffer->setDecodedImage(img); } -String ImageDecoderQt::filenameExtension() const -{ - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::filenameExtension() returns" << m_imageFormat; - return m_imageFormat; -}; +// The QImageIOHandler is not able to tell us how many frames +// we have and we need to parse every image. We do this by +// increasing the m_frameBufferCache by one and try to parse +// the image. We stop when QImage::read fails and then need +// to resize the m_frameBufferCache to the final size and update +// the m_failed. In case we failed to decode the first image +// we want to keep m_failed set to true. -RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) -{ - Q_ASSERT("use imageAtIndex instead"); - return 0; -} - -QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const +// TODO: Do not increment the m_frameBufferCache.size() by one but more than one +void ImageDecoderQt::forceLoadEverything() { - if (debugImageDecoderQt) - qDebug() << "ImageDecoderQt::imageAtIndex(" << index << ')'; + int imageCount = 0; - if (index >= m_imageList.size()) - return 0; - - if (!m_pixmapCache.contains(index)) { - m_pixmapCache.insert(index, - QPixmap::fromImage(m_imageList[index].m_image)); + do { + m_frameBufferCache.resize(++imageCount); + internalHandleCurrentImage(imageCount - 1); + } while(!m_failed); - // store null image since the converted pixmap is already in pixmap cache - Q_ASSERT(m_imageList[index].m_imageState == ImageComplete); - m_imageList[index].m_image = QImage(); - } - return &m_pixmapCache[index]; + // If we failed decoding the first image we actually + // have no images and need to keep m_failed set to + // true otherwise we want to reset it and forget about + // the last attempt to decode a image. + m_frameBufferCache.resize(imageCount - 1); + m_failed = imageCount == 1; } -void ImageDecoderQt::clearFrame(size_t index) +void ImageDecoderQt::failRead() { - if (m_imageList.size() < (int)index) - m_imageList[index].m_image = QImage(); - m_pixmapCache.take(index); + setFailed(); + delete m_reader; + delete m_buffer; + m_reader = 0; + m_buffer = 0; } - } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index fc52479..d11b938 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -28,10 +28,11 @@ #define ImageDecoderQt_h #include "ImageDecoder.h" -#include <QtGui/QImage> +#include <QtGui/QImageReader> #include <QtGui/QPixmap> #include <QtCore/QList> #include <QtCore/QHash> +#include <QtCore/QBuffer> namespace WebCore { @@ -39,54 +40,35 @@ namespace WebCore { class ImageDecoderQt : public ImageDecoder { public: - static ImageDecoderQt* create(const SharedBuffer& data); + ImageDecoderQt(); ~ImageDecoderQt(); - typedef Vector<char> IncomingData; - - virtual void setData(const IncomingData& data, bool allDataReceived); + virtual void setData(SharedBuffer* data, bool allDataReceived); virtual bool isSizeAvailable(); - virtual size_t frameCount() const; + virtual size_t frameCount(); virtual int repetitionCount() const; virtual RGBA32Buffer* frameBufferAtIndex(size_t index); - QPixmap* imageAtIndex(size_t index) const; - virtual bool supportsAlpha() const; - int duration(size_t index) const; virtual String filenameExtension() const; - void clearFrame(size_t index); + virtual void clearFrameBufferCache(size_t clearBeforeFrame); private: - ImageDecoderQt(const QString &imageFormat); ImageDecoderQt(const ImageDecoderQt&); ImageDecoderQt &operator=(const ImageDecoderQt&); - class ReadContext; - void reset(); - bool hasFirstImageHeader() const; - - enum ImageState { - // Started image reading - ImagePartial, - // Header (size / alpha) are known - ImageHeaderValid, - // Image is complete - ImageComplete }; - - struct ImageData { - ImageData(const QImage& image, ImageState imageState = ImagePartial, int duration=0); - QImage m_image; - ImageState m_imageState; - int m_duration; - }; - - bool m_hasAlphaChannel; - typedef QList<ImageData> ImageList; - mutable ImageList m_imageList; - mutable QHash<int, QPixmap> m_pixmapCache; - int m_loopCount; - QString m_imageFormat; +private: + void internalDecodeSize(); + void internalReadImage(size_t); + void internalHandleCurrentImage(size_t); + void forceLoadEverything(); + void failRead(); + +private: + QByteArray m_format; + QBuffer* m_buffer; + QImageReader* m_reader; + mutable int m_repetitionCount; }; diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index 5d40e26..9a82911 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -44,9 +44,7 @@ #include <QPainter> #include <QImage> #include <QImageReader> -#if QT_VERSION >= 0x040300 #include <QTransform> -#endif #include <QDebug> @@ -64,6 +62,8 @@ static QPixmap loadResourcePixmap(const char *name) pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic); else if (qstrcmp(name, "textAreaResizeCorner") == 0) pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic); + else if (qstrcmp(name, "deleteButton") == 0) + pixmap = QWebSettings::webGraphic(QWebSettings::DeleteButtonGraphic); return pixmap; } @@ -76,6 +76,7 @@ bool FrameData::clear(bool clearMetadata) m_haveMetadata = false; if (m_frame) { + delete m_frame; m_frame = 0; return true; } @@ -93,7 +94,7 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name) } void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect) { QPixmap* framePixmap = nativeImageForCurrentFrame(); if (!framePixmap) // If it's too early we won't have an image yet. @@ -119,6 +120,38 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const imageObserver()->didDraw(this); } +BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer) + : Image(observer) + , m_currentFrame(0) + , m_frames(0) + , m_frameTimer(0) + , m_repetitionCount(cAnimationNone) + , m_repetitionCountStatus(Unknown) + , m_repetitionsComplete(0) + , m_isSolidColor(false) + , m_checkedForSolidColor(false) + , m_animationFinished(true) + , m_allDataReceived(true) + , m_haveSize(true) + , m_sizeAvailable(true) + , m_decodedSize(0) + , m_haveFrameCount(true) + , m_frameCount(1) +{ + initPlatformData(); + + int width = pixmap->width(); + int height = pixmap->height(); + m_decodedSize = width * height * 4; + m_size = IntSize(width, height); + + m_frames.grow(1); + m_frames[0].m_frame = pixmap; + m_frames[0].m_hasAlpha = pixmap->hasAlpha(); + m_frames[0].m_haveMetadata = true; + checkForSolidColor(); +} + void BitmapImage::initPlatformData() { } @@ -129,7 +162,7 @@ void BitmapImage::invalidatePlatformData() // Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, - const FloatRect& src, CompositeOperator op) + const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { startAnimation(); @@ -138,7 +171,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), op); + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } @@ -180,6 +213,13 @@ void BitmapImage::checkForSolidColor() m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0)); } +#if PLATFORM(WIN_OS) +PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) +{ + return BitmapImage::create(new QPixmap(QPixmap::fromWinHBITMAP(hBitmap))); +} +#endif + } diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp deleted file mode 100644 index 8ae449c..0000000 --- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - * - * 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 "ImageSource.h" -#include "ImageDecoderQt.h" -#include "SharedBuffer.h" - -#include <QBuffer> -#include <QImage> -#include <QImageReader> - -namespace WebCore { - -ImageSource::ImageSource() - : m_decoder(0) -{ -} - -ImageSource::~ImageSource() -{ - clear(true); -} - -bool ImageSource::initialized() const -{ - return m_decoder; -} - -void ImageSource::setData(SharedBuffer* data, bool allDataReceived) -{ - // Make the decoder by sniffing the bytes. - // This method will examine the data and instantiate an instance of the appropriate decoder plugin. - // If insufficient bytes are available to determine the image type, no decoder plugin will be - // made. - if (!m_decoder) - m_decoder = ImageDecoderQt::create(*data); - - if (!m_decoder) - return; - - m_decoder->setData(data->buffer(), allDataReceived); -} - -String ImageSource::filenameExtension() const -{ - if (!m_decoder) - return String(); - - return m_decoder->filenameExtension(); -} - -bool ImageSource::isSizeAvailable() -{ - if (!m_decoder) - return false; - - return m_decoder->isSizeAvailable(); -} - -IntSize ImageSource::size() const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->size(); -} - -IntSize ImageSource::frameSizeAtIndex(size_t index) const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->frameSizeAtIndex(index); -} - -int ImageSource::repetitionCount() -{ - if (!m_decoder) - return cAnimationNone; - - return m_decoder->repetitionCount(); -} - -size_t ImageSource::frameCount() const -{ - if (!m_decoder) - return 0; - - return m_decoder->frameCount(); -} - -NativeImagePtr ImageSource::createFrameAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - return m_decoder->imageAtIndex(index); -} - -float ImageSource::frameDurationAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - // Many annoying ads specify a 0 duration to make an image flash as quickly - // as possible. We follow WinIE's behavior and use a duration of 100 ms - // for any frames that specify a duration of <= 50 ms. See - // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for - // more. - const float duration = m_decoder->duration(index) / 1000.0f; - return (duration < 0.051f) ? 0.100f : duration; -} - -bool ImageSource::frameHasAlphaAtIndex(size_t index) -{ - if (!m_decoder || !m_decoder->supportsAlpha()) - return false; - - const QPixmap* source = m_decoder->imageAtIndex(index); - if (!source) - return false; - - return source->hasAlphaChannel(); -} - -bool ImageSource::frameIsCompleteAtIndex(size_t index) -{ - return (m_decoder && m_decoder->imageAtIndex(index)); -} - -void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) -{ - if (!destroyAll) { - if (m_decoder) - m_decoder->clearFrameBufferCache(clearBeforeFrame); - return; - } - - delete m_decoder; - m_decoder = 0; - if (data) - setData(data, allDataReceived); -} - -} - -// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index 76b1494..f446755 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -27,6 +27,7 @@ #include "FrameView.h" #include "GraphicsContext.h" #include "NotImplemented.h" +#include "TimeRanges.h" #include "Widget.h" #include <wtf/HashSet.h> @@ -37,9 +38,9 @@ #include <QUrl> #include <QEvent> -#include <Phonon/AudioOutput> -#include <Phonon/MediaObject> -#include <Phonon/VideoWidget> +#include <audiooutput.h> +#include <mediaobject.h> +#include <videowidget.h> using namespace Phonon; @@ -100,15 +101,15 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) foreach (QWidget* widget, qFindChildren<QWidget*>(m_videoWidget)) widget->installEventFilter(this); - connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), - this, SLOT(stateChanged(Phonon::State, Phonon::State))); + connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this, SLOT(stateChanged(Phonon::State,Phonon::State))); connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool))); connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool))); connect(m_mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int))); connect(m_mediaObject, SIGNAL(finished()), this, SLOT(finished())); - connect(m_mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)), - this, SLOT(currentSourceChanged(const Phonon::MediaSource&))); + connect(m_mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)), + this, SLOT(currentSourceChanged(Phonon::MediaSource))); connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64))); } @@ -146,7 +147,7 @@ void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&) notImplemented(); } -MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) +MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String&, const String&) { // FIXME: do the real thing notImplemented(); @@ -160,6 +161,14 @@ bool MediaPlayerPrivate::hasVideo() const return hasVideo; } +bool MediaPlayerPrivate::hasAudio() const +{ + // FIXME: Phonon::MediaObject does not have such a hasAudio() function + bool hasAudio = true; + LOG(Media, "MediaPlayerPrivatePhonon::hasAudio() -> %s", hasAudio ? "true" : "false"); + return hasAudio; +} + void MediaPlayerPrivate::load(const String& url) { LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data()); @@ -247,15 +256,15 @@ float MediaPlayerPrivate::currentTime() const return currentTime; } -void MediaPlayerPrivate::setEndTime(float endTime) +void MediaPlayerPrivate::setEndTime(float) { notImplemented(); } -float MediaPlayerPrivate::maxTimeBuffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { notImplemented(); - return 0.0f; + return TimeRanges::create(); } float MediaPlayerPrivate::maxTimeSeekable() const diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h index 9572d61..e1193b6 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h @@ -80,6 +80,7 @@ namespace WebCore { IntSize naturalSize() const; bool hasVideo() const; + bool hasAudio() const; void load(const String &url); void cancelLoad(); @@ -104,7 +105,7 @@ namespace WebCore { MediaPlayer::NetworkState networkState() const; MediaPlayer::ReadyState readyState() const; - float maxTimeBuffered() const; + PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; bool totalBytesKnown() const; diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index f823f84..f093d7d 100644 --- a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -33,7 +33,7 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = m_platformData.font().fixedPitch(); } -bool SimpleFontData::containsCharacters(const UChar*, int length) const +bool SimpleFontData::containsCharacters(const UChar*, int) const { return true; } diff --git a/WebCore/platform/graphics/qt/StillImageQt.cpp b/WebCore/platform/graphics/qt/StillImageQt.cpp index 95b3bc8..1db04a7 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.cpp +++ b/WebCore/platform/graphics/qt/StillImageQt.cpp @@ -50,7 +50,7 @@ NativeImagePtr StillImage::nativeImageForCurrentFrame() } void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst, - const FloatRect& src, CompositeOperator op) + const FloatRect& src, ColorSpace, CompositeOperator op) { if (m_pixmap.isNull()) return; diff --git a/WebCore/platform/graphics/qt/StillImageQt.h b/WebCore/platform/graphics/qt/StillImageQt.h index 2b2c1f7..7be9136 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.h +++ b/WebCore/platform/graphics/qt/StillImageQt.h @@ -41,12 +41,12 @@ namespace WebCore { // FIXME: StillImages are underreporting decoded sizes and will be unable // to prune because these functions are not implemented yet. - virtual void destroyDecodedData(bool destroyAll = true) { } + virtual void destroyDecodedData(bool destroyAll = true) { Q_UNUSED(destroyAll); } virtual unsigned decodedSize() const { return 0; } virtual IntSize size() const; virtual NativeImagePtr nativeImageForCurrentFrame(); - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); private: StillImage(const QPixmap& pixmap); diff --git a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h index 5d85652..9fb6a8b 100644 --- a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h +++ b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h @@ -72,7 +72,7 @@ public: } protected: - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); private: NativeImageSkia m_nativeImage; diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp index 3bdddb2..268b17e 100644 --- a/WebCore/platform/graphics/skia/GradientSkia.cpp +++ b/WebCore/platform/graphics/skia/GradientSkia.cpp @@ -152,19 +152,21 @@ SkShader* Gradient::platformGradient() } if (m_radial) { - // FIXME: CSS radial Gradients allow an offset focal point (the - // "start circle"), but skia doesn't seem to support that, so this just - // ignores m_p0/m_r0 and draws the gradient centered in the "end - // circle" (m_p1/m_r1). - // See http://webkit.org/blog/175/introducing-css-gradients/ for a - // description of the expected behavior. - - // The radius we give to Skia must be positive (and non-zero). If - // we're given a zero radius, just ask for a very small radius so - // Skia will still return an object. - SkScalar radius = m_r1 > 0 ? WebCoreFloatToSkScalar(m_r1) : SK_ScalarMin; - m_gradient = SkGradientShader::CreateRadial(m_p1, - radius, colors, pos, static_cast<int>(countUsed), tile); + // Since the two-point radial gradient is slower than the plain radial, + // only use it if we have to. + if (m_p0 != m_p1) { + // The radii we give to Skia must be positive. If we're given a + // negative radius, ask for zero instead. + SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0; + SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0; + m_gradient = SkGradientShader::CreateTwoPointRadial(m_p0, radius0, m_p1, radius1, colors, pos, static_cast<int>(countUsed), tile); + } else { + // The radius we give to Skia must be positive (and non-zero). If + // we're given a zero radius, just ask for a very small radius so + // Skia will still return an object. + SkScalar radius = m_r1 > 0 ? WebCoreFloatToSkScalar(m_r1) : SK_ScalarMin; + m_gradient = SkGradientShader::CreateRadial(m_p1, radius, colors, pos, static_cast<int>(countUsed), tile); + } } else { SkPoint pts[2] = { m_p0, m_p1 }; m_gradient = SkGradientShader::CreateLinear(pts, colors, pos, diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index bbb42c9..f1536a6 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -31,11 +31,11 @@ #include "config.h" #include "GraphicsContext.h" -#include "GraphicsContextPlatformPrivate.h" -#include "GraphicsContextPrivate.h" #include "Color.h" #include "FloatRect.h" #include "Gradient.h" +#include "GraphicsContextPlatformPrivate.h" +#include "GraphicsContextPrivate.h" #include "ImageBuffer.h" #include "IntRect.h" #include "NativeImageSkia.h" @@ -46,9 +46,9 @@ #include "SkBitmap.h" #include "SkBlurDrawLooper.h" #include "SkCornerPathEffect.h" -#include "skia/ext/platform_canvas.h" -#include "SkiaUtils.h" #include "SkShader.h" +#include "SkiaUtils.h" +#include "skia/ext/platform_canvas.h" #include <math.h> #include <wtf/Assertions.h> @@ -60,6 +60,23 @@ namespace WebCore { namespace { +inline int fastMod(int value, int max) +{ + int sign = SkExtractSign(value); + + value = SkApplySign(value, sign); + if (value >= max) + value %= max; + return SkApplySign(value, sign); +} + +inline float square(float n) +{ + return n * n; +} + +} // namespace + // "Seatbelt" functions ------------------------------------------------------ // // These functions check certain graphics primitives for being "safe". @@ -195,23 +212,6 @@ void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int sta path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false); } -inline int fastMod(int value, int max) -{ - int sign = SkExtractSign(value); - - value = SkApplySign(value, sign); - if (value >= max) - value %= max; - return SkApplySign(value, sign); -} - -inline float square(float n) -{ - return n * n; -} - -} // namespace - // ----------------------------------------------------------------------------- // This may be called with a NULL pointer to create a graphics context that has @@ -293,10 +293,13 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness path.addOval(r, SkPath::kCW_Direction); // only perform the inset if we won't invert r if (2 * thickness < rect.width() && 2 * thickness < rect.height()) { - r.inset(SkIntToScalar(thickness) ,SkIntToScalar(thickness)); + // Adding one to the thickness doesn't make the border too thick as + // it's painted over afterwards. But without this adjustment the + // border appears a little anemic after anti-aliasing. + r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1)); path.addOval(r, SkPath::kCCW_Direction); } - platformContext()->canvas()->clipPath(path); + platformContext()->clipPathAntiAliased(path); } void GraphicsContext::addPath(const Path& path) @@ -356,6 +359,18 @@ void GraphicsContext::clip(const Path& path) if (!isPathSkiaSafe(getCTM(), p)) return; + platformContext()->clipPathAntiAliased(p); +} + +void GraphicsContext::canvasClip(const Path& path) +{ + if (paintingDisabled()) + return; + + const SkPath& p = *path.platformPath(); + if (!isPathSkiaSafe(getCTM(), p)) + return; + platformContext()->canvas()->clipPath(p); } @@ -403,8 +418,11 @@ void GraphicsContext::clipPath(WindRule clipRule) return; SkPath path = platformContext()->currentPathInLocalCoordinates(); + if (!isPathSkiaSafe(getCTM(), path)) + return; + path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); - platformContext()->canvas()->clipPath(path); + platformContext()->clipPathAntiAliased(path); } void GraphicsContext::clipToImageBuffer(const FloatRect& rect, @@ -487,7 +505,7 @@ void GraphicsContext::drawFocusRing(const Color& color) const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); - if (0 == rectCount) + if (!rectCount) return; SkRegion focusRingRegion; @@ -521,26 +539,28 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) return; SkPaint paint; - SkPoint pts[2] = { (SkPoint)point1, (SkPoint)point2 }; - if (!isPointSkiaSafe(getCTM(), pts[0]) || !isPointSkiaSafe(getCTM(), pts[1])) + if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2)) return; + FloatPoint p1 = point1; + FloatPoint p2 = point2; + bool isVerticalLine = (p1.x() == p2.x()); + int width = roundf(strokeThickness()); + // We know these are vertical or horizontal lines, so the length will just // be the sum of the displacement component vectors give or take 1 - // probably worth the speed up of no square root, which also won't be exact. - SkPoint disp = pts[1] - pts[0]; - int length = SkScalarRound(disp.fX + disp.fY); + FloatSize disp = p2 - p1; + int length = SkScalarRound(disp.width() + disp.height()); platformContext()->setupPaintForStroking(&paint, 0, length); - int width = roundf(strokeThickness()); - bool isVerticalLine = pts[0].fX == pts[1].fX; if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. SkRect r1, r2; - r1.set(pts[0].fX, pts[0].fY, pts[0].fX + width, pts[0].fY + width); - r2.set(pts[1].fX, pts[1].fY, pts[1].fX + width, pts[1].fY + width); + r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width); + r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width); if (isVerticalLine) { r1.offset(-width / 2, 0); @@ -553,35 +573,11 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) fillPaint.setColor(paint.getColor()); platformContext()->canvas()->drawRect(r1, fillPaint); platformContext()->canvas()->drawRect(r2, fillPaint); - - // Since we've already rendered the endcaps, adjust the endpoints to - // exclude them from the line itself. - if (isVerticalLine) { - pts[0].fY += width; - pts[1].fY -= width; - } else { - pts[0].fX += width; - pts[1].fX -= width; - } } - // "Borrowed" this comment and idea from GraphicsContextCG.cpp - // - // For odd widths, we add in 0.5 to the appropriate x/y so that the float - // arithmetic works out. For example, with a border width of 3, KHTML will - // pass us (y1+y2)/2, e.g., (50+53)/2 = 103/2 = 51 when we want 51.5. It is - // always true that an even width gave us a perfect position, but an odd - // width gave us a position that is off by exactly 0.5. + adjustLineToPixelBoundaries(p1, p2, width, penStyle); + SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 }; - if (width & 1) { // Odd. - if (isVerticalLine) { - pts[0].fX = pts[0].fX + SK_ScalarHalf; - pts[1].fX = pts[0].fX; - } else { // Horizontal line - pts[0].fY = pts[0].fY + SK_ScalarHalf; - pts[1].fY = pts[0].fY; - } - } platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); } @@ -711,8 +707,6 @@ void GraphicsContext::fillPath() return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.fillColorSpace; - path.setFillType(state.fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); @@ -734,14 +728,13 @@ void GraphicsContext::fillRect(const FloatRect& rect) } const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.fillColorSpace; SkPaint paint; platformContext()->setupPaintForFilling(&paint); platformContext()->canvas()->drawRect(r, paint); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -772,7 +765,8 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, - const Color& color) + const Color& color, + ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -789,7 +783,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, // Not all the radii fit, return a rect. This matches the behavior of // Path::createRoundedRectangle. Without this we attempt to draw a round // shadow for a square box. - fillRect(rect, color); + fillRect(rect, color, colorSpace); return; } @@ -844,9 +838,9 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) deviceLowerRight.setY(roundf(deviceLowerRight.y())); // Don't let the height or width round to 0 unless either was originally 0 - if (deviceOrigin.y() == deviceLowerRight.y() && rect.height() != 0) + if (deviceOrigin.y() == deviceLowerRight.y() && rect.height()) deviceLowerRight.move(0, 1); - if (deviceOrigin.x() == deviceLowerRight.x() && rect.width() != 0) + if (deviceOrigin.x() == deviceLowerRight.x() && rect.width()) deviceLowerRight.move(1, 0); FloatPoint roundedOrigin(deviceOrigin.x() / deviceScaleX, @@ -919,7 +913,7 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) return; } - size_t count = (dashLength % 2) == 0 ? dashLength : dashLength * 2; + size_t count = !(dashLength % 2) ? dashLength : dashLength * 2; SkScalar* intervals = new SkScalar[count]; for (unsigned int i = 0; i < count; i++) @@ -957,7 +951,7 @@ void GraphicsContext::setMiterLimit(float limit) platformContext()->setMiterLimit(limit); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -984,14 +978,15 @@ void GraphicsContext::setPlatformFillPattern(Pattern* pattern) void GraphicsContext::setPlatformShadow(const IntSize& size, int blurInt, - const Color& color) + const Color& color, + ColorSpace colorSpace) { if (paintingDisabled()) return; // Detect when there's no effective shadow and clear the looper. - if (size.width() == 0 && size.height() == 0 && blurInt == 0) { - platformContext()->setDrawLooper(NULL); + if (!size.width() && !size.height() && !blurInt) { + platformContext()->setDrawLooper(0); return; } @@ -1026,7 +1021,7 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, dl->unref(); } -void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor) +void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1125,7 +1120,6 @@ void GraphicsContext::strokePath() return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.strokeColorSpace; SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); @@ -1142,7 +1136,6 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.strokeColorSpace; SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 7935ff1..c36f1ce 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -39,6 +39,7 @@ #include "ImageData.h" #include "PlatformContextSkia.h" #include "PNGImageEncoder.h" +#include "SkColorPriv.h" #include "SkiaUtils.h" using namespace std; @@ -104,13 +105,16 @@ Image* ImageBuffer::image() const void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) { const SkBitmap& bitmap = *context()->platformContext()->bitmap(); + if (bitmap.isNull()) + return; + ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); SkAutoLockPixels bitmapLock(bitmap); for (int y = 0; y < m_size.height(); ++y) { uint32_t* srcRow = bitmap.getAddr32(0, y); for (int x = 0; x < m_size.width(); ++x) { SkColor color = SkPMColorToColor(srcRow[x]); - srcRow[x] = SkPreMultiplyARGB(lookUpTable[SkColorGetA(color)], + srcRow[x] = SkPreMultiplyARGB(SkColorGetA(color), lookUpTable[SkColorGetR(color)], lookUpTable[SkColorGetG(color)], lookUpTable[SkColorGetB(color)]); @@ -118,16 +122,16 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) } } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +template <Multiply multiplied> +PassRefPtr<ImageData> getImageData(const IntRect& rect, const SkBitmap& bitmap, + const IntSize& size) { - ASSERT(context()); - RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* data = result->data()->data()->data(); if (rect.x() < 0 || rect.y() < 0 || - (rect.x() + rect.width()) > m_size.width() || - (rect.y() + rect.height()) > m_size.height()) + (rect.x() + rect.width()) > size.width() || + (rect.y() + rect.height()) > size.height()) memset(data, 0, result->data()->length()); int originX = rect.x(); @@ -137,8 +141,8 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originX = 0; } int endX = rect.x() + rect.width(); - if (endX > m_size.width()) - endX = m_size.width(); + if (endX > size.width()) + endX = size.width(); int numColumns = endX - originX; int originY = rect.y(); @@ -148,11 +152,10 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originY = 0; } int endY = rect.y() + rect.height(); - if (endY > m_size.height()) - endY = m_size.height(); + if (endY > size.height()) + endY = size.height(); int numRows = endY - originY; - const SkBitmap& bitmap = *context()->platformContext()->bitmap(); ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); SkAutoLockPixels bitmapLock(bitmap); @@ -162,12 +165,22 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const for (int y = 0; y < numRows; ++y) { uint32_t* srcRow = bitmap.getAddr32(originX, originY + y); for (int x = 0; x < numColumns; ++x) { - SkColor color = SkPMColorToColor(srcRow[x]); unsigned char* destPixel = &destRow[x * 4]; - destPixel[0] = SkColorGetR(color); - destPixel[1] = SkColorGetG(color); - destPixel[2] = SkColorGetB(color); - destPixel[3] = SkColorGetA(color); + if (multiplied == Unmultiplied) { + SkColor color = srcRow[x]; + unsigned a = SkColorGetA(color); + destPixel[0] = a ? SkColorGetR(color) * 255 / a : 0; + destPixel[1] = a ? SkColorGetG(color) * 255 / a : 0; + destPixel[2] = a ? SkColorGetB(color) * 255 / a : 0; + destPixel[3] = a; + } else { + // Input and output are both pre-multiplied, we just need to re-arrange the + // bytes from the bitmap format to RGBA. + destPixel[0] = SkGetPackedR32(srcRow[x]); + destPixel[1] = SkGetPackedG32(srcRow[x]); + destPixel[2] = SkGetPackedB32(srcRow[x]); + destPixel[3] = SkGetPackedA32(srcRow[x]); + } } destRow += destBytesPerRow; } @@ -175,8 +188,19 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, - const IntPoint& destPoint) +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData<Unmultiplied>(rect, *context()->platformContext()->bitmap(), m_size); +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<Premultiplied>(rect, *context()->platformContext()->bitmap(), m_size); +} + +template <Multiply multiplied> +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, + const SkBitmap& bitmap, const IntSize& size) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -184,27 +208,26 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, int originX = sourceRect.x(); int destX = destPoint.x() + sourceRect.x(); ASSERT(destX >= 0); - ASSERT(destX < m_size.width()); + ASSERT(destX < size.width()); ASSERT(originX >= 0); ASSERT(originX < sourceRect.right()); int endX = destPoint.x() + sourceRect.right(); - ASSERT(endX <= m_size.width()); + ASSERT(endX <= size.width()); int numColumns = endX - destX; int originY = sourceRect.y(); int destY = destPoint.y() + sourceRect.y(); ASSERT(destY >= 0); - ASSERT(destY < m_size.height()); + ASSERT(destY < size.height()); ASSERT(originY >= 0); ASSERT(originY < sourceRect.bottom()); int endY = destPoint.y() + sourceRect.bottom(); - ASSERT(endY <= m_size.height()); + ASSERT(endY <= size.height()); int numRows = endY - destY; - const SkBitmap& bitmap = *context()->platformContext()->bitmap(); ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); SkAutoLockPixels bitmapLock(bitmap); @@ -216,13 +239,27 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, uint32_t* destRow = bitmap.getAddr32(destX, destY + y); for (int x = 0; x < numColumns; ++x) { const unsigned char* srcPixel = &srcRow[x * 4]; - destRow[x] = SkPreMultiplyARGB(srcPixel[3], srcPixel[0], - srcPixel[1], srcPixel[2]); + if (multiplied == Unmultiplied) + destRow[x] = SkPreMultiplyARGB(srcPixel[3], srcPixel[0], + srcPixel[1], srcPixel[2]); + else + destRow[x] = SkPackARGB32(srcPixel[3], srcPixel[0], + srcPixel[1], srcPixel[2]); } srcRow += srcBytesPerRow; } } +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Unmultiplied>(source, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Premultiplied>(source, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size); +} + String ImageBuffer::toDataURL(const String&) const { // Encode the image into a vector. diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index 45c3dcd..6d8ed22 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -41,6 +41,7 @@ #include "PlatformContextSkia.h" #include "PlatformString.h" #include "SkiaUtils.h" +#include "SkRect.h" #include "SkShader.h" #include "TransformationMatrix.h" @@ -158,8 +159,8 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm // We will always draw in integer sizes, so round the destination rect. SkIRect destRectRounded; destRect.round(&destRectRounded); - SkIRect resizedImageRect; // Represents the size of the resized image. - resizedImageRect.set(0, 0, destRectRounded.width(), destRectRounded.height()); + SkIRect resizedImageRect = // Represents the size of the resized image. + { 0, 0, destRectRounded.width(), destRectRounded.height() }; if (srcIsFull && bitmap.hasResizedBitmap(destRectRounded.width(), destRectRounded.height())) { // Yay, this bitmap frame already has a resized version. @@ -196,25 +197,19 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm } else { // We should only resize the exposed part of the bitmap to do the // minimal possible work. - gfx::Rect destBitmapSubset(destBitmapSubsetSkI.fLeft, - destBitmapSubsetSkI.fTop, - destBitmapSubsetSkI.width(), - destBitmapSubsetSkI.height()); // Resample the needed part of the image. SkBitmap resampled = skia::ImageOperations::Resize(subset, skia::ImageOperations::RESIZE_LANCZOS3, destRectRounded.width(), destRectRounded.height(), - destBitmapSubset); + destBitmapSubsetSkI); // Compute where the new bitmap should be drawn. Since our new bitmap // may be smaller than the original, we have to shift it over by the // same amount that we cut off the top and left. - SkRect offsetDestRect = { - destBitmapSubset.x() + destRect.fLeft, - destBitmapSubset.y() + destRect.fTop, - destBitmapSubset.right() + destRect.fLeft, - destBitmapSubset.bottom() + destRect.fTop }; + destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop); + SkRect offsetDestRect; + offsetDestRect.set(destBitmapSubsetSkI); canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint); } @@ -307,6 +302,7 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& floatSrcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, + ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { @@ -410,7 +406,7 @@ void BitmapImage::checkForSolidColor() } void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, - const FloatRect& srcRect, CompositeOperator compositeOp) + const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp) { if (!m_source.initialized()) return; @@ -442,6 +438,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, + ColorSpace styleColorSpace, CompositeOperator compositeOp) { FloatRect normDstRect = normalizeRect(dstRect); diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp deleted file mode 100644 index 1647b86..0000000 --- a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2008, Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "config.h" -#include "ImageSource.h" -#include "SharedBuffer.h" - -#include "GIFImageDecoder.h" -#include "ICOImageDecoder.h" -#include "JPEGImageDecoder.h" -#include "PNGImageDecoder.h" -#include "BMPImageDecoder.h" -#include "XBMImageDecoder.h" - -#include "SkBitmap.h" - -namespace WebCore { - -ImageDecoder* createDecoder(const Vector<char>& data) -{ - // We need at least 4 bytes to figure out what kind of image we're dealing with. - int length = data.size(); - if (length < 4) - return 0; - - const unsigned char* uContents = (const unsigned char*)data.data(); - const char* contents = data.data(); - - // GIFs begin with GIF8(7 or 9). - if (strncmp(contents, "GIF8", 4) == 0) - return new GIFImageDecoder(); - - // Test for PNG. - if (uContents[0]==0x89 && - uContents[1]==0x50 && - uContents[2]==0x4E && - uContents[3]==0x47) - return new PNGImageDecoder(); - - // JPEG - if (uContents[0]==0xFF && - uContents[1]==0xD8 && - uContents[2]==0xFF) - return new JPEGImageDecoder(); - - // BMP - if (strncmp(contents, "BM", 2) == 0) - return new BMPImageDecoder(); - - // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. - // CURs begin with 2-byte 0 followed by 2-byte 2. - if (!memcmp(contents, "\000\000\001\000", 4) || - !memcmp(contents, "\000\000\002\000", 4)) - return new ICOImageDecoder(); - - // XBMs require 8 bytes of info. - if (length >= 8 && strncmp(contents, "#define ", 8) == 0) - return new XBMImageDecoder(); - - // Give up. We don't know what the heck this is. - return 0; -} - -ImageSource::ImageSource() - : m_decoder(0) -{} - -ImageSource::~ImageSource() -{ - clear(true); -} - -void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) -{ - if (!destroyAll) { - if (m_decoder) - m_decoder->clearFrameBufferCache(clearBeforeFrame); - return; - } - - delete m_decoder; - m_decoder = 0; - if (data) - setData(data, allDataReceived); -} - -bool ImageSource::initialized() const -{ - return m_decoder; -} - -void ImageSource::setData(SharedBuffer* data, bool allDataReceived) -{ - // Make the decoder by sniffing the bytes. - // This method will examine the data and instantiate an instance of the appropriate decoder plugin. - // If insufficient bytes are available to determine the image type, no decoder plugin will be - // made. - if (!m_decoder) - m_decoder = createDecoder(data->buffer()); - - // CreateDecoder will return NULL if the decoder could not be created. Plus, - // we should not send more data to a decoder which has already decided it - // has failed. - if (!m_decoder || m_decoder->failed()) - return; - m_decoder->setData(data, allDataReceived); -} - -bool ImageSource::isSizeAvailable() -{ - if (!m_decoder) - return false; - - return m_decoder->isSizeAvailable(); -} - -IntSize ImageSource::size() const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->size(); -} - -IntSize ImageSource::frameSizeAtIndex(size_t index) const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->frameSizeAtIndex(index); -} - -int ImageSource::repetitionCount() -{ - if (!m_decoder) - return cAnimationNone; - - return m_decoder->repetitionCount(); -} - -size_t ImageSource::frameCount() const -{ - if (!m_decoder) - return 0; - return m_decoder->failed() ? 0 : m_decoder->frameCount(); -} - -NativeImagePtr ImageSource::createFrameAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - // Note that the buffer can have NULL bytes even when it is marked as - // non-empty. It seems "FrameEmpty" is only set before the frame has been - // initialized. If it is decoded and it happens to be empty, it will be - // marked as "FrameComplete" but will still have NULL bytes. - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return 0; - - // Copy the bitmap. The pixel data is refcounted internally by SkBitmap, so - // this doesn't cost much. - return buffer->asNewNativeImage(); -} - -bool ImageSource::frameIsCompleteAtIndex(size_t index) -{ - if (!m_decoder) - return false; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - return buffer && buffer->status() == RGBA32Buffer::FrameComplete; -} - -float ImageSource::frameDurationAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return 0; - - // Many annoying ads specify a 0 duration to make an image flash as quickly - // as possible. We follow WinIE's behavior and use a duration of 100 ms - // for any frames that specify a duration of <= 50 ms. See - // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for - // more. - const float duration = buffer->duration() / 1000.0f; - return (duration < 0.051f) ? 0.100f : duration; -} - -bool ImageSource::frameHasAlphaAtIndex(size_t index) -{ - if (!m_decoder || !m_decoder->supportsAlpha()) - return false; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return false; - - return buffer->hasAlpha(); -} - -String ImageSource::filenameExtension() const -{ - return m_decoder ? m_decoder->filenameExtension() : String(); -} - -} diff --git a/WebCore/platform/graphics/skia/NativeImageSkia.cpp b/WebCore/platform/graphics/skia/NativeImageSkia.cpp index 477be05..2411897 100644 --- a/WebCore/platform/graphics/skia/NativeImageSkia.cpp +++ b/WebCore/platform/graphics/skia/NativeImageSkia.cpp @@ -30,7 +30,7 @@ #include "config.h" -#if PLATFORM(SKIA) +#if !PLATFORM(ANDROID) #include "skia/ext/image_operations.h" #endif @@ -65,10 +65,11 @@ bool NativeImageSkia::hasResizedBitmap(int w, int h) const SkBitmap NativeImageSkia::resizedBitmap(int w, int h) const { -#if PLATFORM(SKIA) +#if !PLATFORM(ANDROID) if (m_resizedImage.width() != w || m_resizedImage.height() != h) m_resizedImage = skia::ImageOperations::Resize(*this, skia::ImageOperations::RESIZE_LANCZOS3, w, h); #endif + return m_resizedImage; } diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp index 5ac14b9..2cbb759 100644 --- a/WebCore/platform/graphics/skia/PathSkia.cpp +++ b/WebCore/platform/graphics/skia/PathSkia.cpp @@ -123,26 +123,31 @@ void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlo SkScalar cx = WebCoreFloatToSkScalar(p.x()); SkScalar cy = WebCoreFloatToSkScalar(p.y()); SkScalar radius = WebCoreFloatToSkScalar(r); + SkScalar s360 = SkIntToScalar(360); SkRect oval; oval.set(cx - radius, cy - radius, cx + radius, cy + radius); float sweep = ea - sa; - // check for a circle - if (sweep >= 2 * piFloat || sweep <= -2 * piFloat) + SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat); + SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat); + // Check for a circle. + if (sweepDegrees >= s360 || sweepDegrees <= -s360) { + // Move to the start position (0 sweep means we add a single point). + m_path->arcTo(oval, startDegrees, 0, false); + // Draw the circle. m_path->addOval(oval); - else { - SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat); - SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat); - + // Force a moveTo the end position. + m_path->arcTo(oval, startDegrees + sweepDegrees, 0, true); + } else { // Counterclockwise arcs should be drawn with negative sweeps, while // clockwise arcs should be drawn with positive sweeps. Check to see // if the situation is reversed and correct it by adding or subtracting // a full circle if (anticlockwise && sweepDegrees > 0) { - sweepDegrees -= SkIntToScalar(360); + sweepDegrees -= s360; } else if (!anticlockwise && sweepDegrees < 0) { - sweepDegrees += SkIntToScalar(360); + sweepDegrees += s360; } m_path->arcTo(oval, startDegrees, sweepDegrees, false); diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index e0a292c..dfffa0d 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -45,6 +45,12 @@ #include "SkDashPathEffect.h" #include <wtf/MathExtras.h> +#include <wtf/Vector.h> + +namespace WebCore +{ +extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path); +} // State ----------------------------------------------------------------------- @@ -90,6 +96,10 @@ struct PlatformContextSkia::State { WebCore::FloatRect m_clip; #endif + // This is a list of clipping paths which are currently active, in the + // order in which they were pushed. + WTF::Vector<SkPath> m_antiAliasClipPaths; + private: // Not supported. void operator=(const State&); @@ -105,8 +115,8 @@ PlatformContextSkia::State::State() , m_fillShader(0) , m_strokeStyle(WebCore::SolidStroke) , m_strokeColor(WebCore::Color::black) - , m_strokeThickness(0) , m_strokeShader(0) + , m_strokeThickness(0) , m_dashRatio(3) , m_miterLimit(4) , m_lineCap(SkPaint::kDefault_Cap) @@ -125,8 +135,8 @@ PlatformContextSkia::State::State(const State& other) , m_fillShader(other.m_fillShader) , m_strokeStyle(other.m_strokeStyle) , m_strokeColor(other.m_strokeColor) - , m_strokeThickness(other.m_strokeThickness) , m_strokeShader(other.m_strokeShader) + , m_strokeThickness(other.m_strokeThickness) , m_dashRatio(other.m_dashRatio) , m_miterLimit(other.m_miterLimit) , m_lineCap(other.m_lineCap) @@ -244,6 +254,21 @@ void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rec } #endif +void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath) +{ + // If we are currently tracking any anti-alias clip paths, then we already + // have a layer in place and don't need to add another. + bool haveLayerOutstanding = m_state->m_antiAliasClipPaths.size(); + + // See comments in applyAntiAliasedClipPaths about how this works. + m_state->m_antiAliasClipPaths.append(clipPath); + + if (!haveLayerOutstanding) { + SkRect bounds = clipPath.getBounds(); + canvas()->saveLayerAlpha(&bounds, 255, static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag)); + } +} + void PlatformContextSkia::restore() { #if defined(__linux__) || PLATFORM(WIN_OS) @@ -253,6 +278,9 @@ void PlatformContextSkia::restore() } #endif + if (!m_state->m_antiAliasClipPaths.isEmpty()) + applyAntiAliasedClipPaths(m_state->m_antiAliasClipPaths); + m_stateStack.removeLast(); m_state = &m_stateStack.last(); @@ -278,6 +306,7 @@ void PlatformContextSkia::drawRect(SkRect rect) SkShader* oldFillShader = m_state->m_fillShader; oldFillShader->safeRef(); setFillColor(m_state->m_strokeColor); + paint.reset(); setupPaintForFilling(&paint); SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 }; canvas()->drawRect(topBorder, paint); @@ -295,7 +324,7 @@ void PlatformContextSkia::drawRect(SkRect rect) void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const { -#ifdef SK_DEBUGx +#if defined(SK_DEBUG) { SkPaint defaultPaint; SkASSERT(*paint == defaultPaint); @@ -314,6 +343,15 @@ void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const paint->setShader(m_state->m_fillShader); } +static SkScalar scalarBound(SkScalar v, SkScalar min, SkScalar max) +{ + if (v < min) + return min; + if (v > max) + return max; + return v; +} + float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const { setupPaintCommon(paint); @@ -322,10 +360,13 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i paint->setColor(m_state->applyAlpha(m_state->m_strokeColor)); paint->setShader(m_state->m_strokeShader); paint->setStyle(SkPaint::kStroke_Style); - paint->setStrokeWidth(SkFloatToScalar(width)); + // The limits here (512 and 256) were made up but are hopefully large + // enough to be reasonable. They are, empirically, small enough not to + // cause overflows in Skia. + paint->setStrokeWidth(scalarBound(SkFloatToScalar(width), 0, 512)); paint->setStrokeCap(m_state->m_lineCap); paint->setStrokeJoin(m_state->m_lineJoin); - paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit)); + paint->setStrokeMiter(scalarBound(SkFloatToScalar(m_state->m_miterLimit), 0, 256)); if (m_state->m_dash) paint->setPathEffect(m_state->m_dash); @@ -543,3 +584,40 @@ void PlatformContextSkia::applyClipFromImage(const WebCore::FloatRect& rect, con m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint); } #endif + +void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths) +{ + // Anti-aliased clipping: + // + // Skia's clipping is 1-bit only. Consider what would happen if it were 8-bit: + // We have a square canvas, filled with white and we declare a circular + // clipping path. Then we fill twice with a black rectangle. The fractional + // pixels would first get the correct color (white * alpha + black * (1 - + // alpha)), but the second fill would apply the alpha to the already + // modified color and the result would be too dark. + // + // This, anti-aliased clipping needs to be performed after the drawing has + // been done. In order to do this, we create a new layer of the canvas in + // clipPathAntiAliased and store the clipping path. All drawing is done to + // the layer's bitmap while it's in effect. When WebKit calls restore() to + // undo the clipping, this function is called. + // + // Here, we walk the list of clipping paths backwards and, for each, we + // clear outside of the clipping path. We only need a single extra layer + // for any number of clipping paths. + // + // When we call restore on the SkCanvas, the layer's bitmap is composed + // into the layer below and we end up with correct, anti-aliased clipping. + + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kClear_Mode); + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kFill_Style); + + for (size_t i = paths.size() - 1; i < paths.size(); --i) { + paths[i].setFillType(SkPath::kInverseWinding_FillType); + m_canvas->drawPath(paths[i], paint); + } + + m_canvas->restore(); +} diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h index 0c87fc2..53590bf 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -92,6 +92,7 @@ public: void beginLayerClippedToImage(const WebCore::FloatRect&, const WebCore::ImageBuffer*); #endif + void clipPathAntiAliased(const SkPath&); // Sets up the common flags on a paint for antialiasing, effects, etc. // This is implicitly called by setupPaintFill and setupPaintStroke, but @@ -172,6 +173,7 @@ private: // m_canvas that are also in imageBuffer. void applyClipFromImage(const WebCore::FloatRect&, const SkBitmap&); #endif + void applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths); // Defines drawing style. struct State; diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp index 662ea5c..377ca06 100644 --- a/WebCore/platform/graphics/skia/SkiaUtils.cpp +++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp @@ -131,10 +131,10 @@ SkColor SkPMColorToColor(SkPMColor pm) { if (0 == pm) return 0; - + unsigned a = SkGetPackedA32(pm); uint32_t scale = (255 << 16) / a; - + return SkColorSetARGB(a, InvScaleByte(SkGetPackedR32(pm), scale), InvScaleByte(SkGetPackedG32(pm), scale), @@ -200,8 +200,13 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath:: SkRect bounds = originalPath->getBounds(); - // We can immediately return false if the point is outside the bounding rect - if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) + // We can immediately return false if the point is outside the bounding + // rect. We don't use bounds.contains() here, since it would exclude + // points on the right and bottom edges of the bounding rect, and we want + // to include them. + SkScalar fX = SkFloatToScalar(point.x()); + SkScalar fY = SkFloatToScalar(point.y()); + if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; originalPath->setFillType(ft); @@ -225,7 +230,7 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath:: int x = static_cast<int>(floorf(point.x() / scale)); int y = static_cast<int>(floorf(point.y() / scale)); - clip.setRect(x, y, x + 1, y + 1); + clip.setRect(x - 1, y - 1, x + 1, y + 1); bool contains = rgn.setPath(*path, clip); diff --git a/WebCore/platform/graphics/transforms/TransformOperations.h b/WebCore/platform/graphics/transforms/TransformOperations.h index dd56408..08efd23 100644 --- a/WebCore/platform/graphics/transforms/TransformOperations.h +++ b/WebCore/platform/graphics/transforms/TransformOperations.h @@ -31,7 +31,7 @@ namespace WebCore { -class TransformOperations { +class TransformOperations : public FastAllocBase { public: TransformOperations(bool makeIdentity = false); diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h index a7fbb3d..802ad3c 100644 --- a/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -29,6 +29,7 @@ #include "FloatPoint.h" #include "IntPoint.h" #include <string.h> //for memcpy +#include <wtf/FastAllocBase.h> #if PLATFORM(CG) #include <CoreGraphics/CGAffineTransform.h> @@ -36,7 +37,7 @@ #include <cairo.h> #elif PLATFORM(QT) #include <QTransform> -#elif PLATFORM(SKIA) || PLATFORM(SGL) +#elif PLATFORM(SKIA) #include <SkMatrix.h> #elif PLATFORM(WX) && USE(WXGC) #include <wx/graphics.h> @@ -49,7 +50,7 @@ class FloatPoint3D; class FloatRect; class FloatQuad; -class TransformationMatrix { +class TransformationMatrix : public FastAllocBase { public: typedef double Matrix4[4][4]; @@ -300,7 +301,7 @@ public: operator cairo_matrix_t() const; #elif PLATFORM(QT) operator QTransform() const; -#elif PLATFORM(SKIA) || PLATFORM(SGL) +#elif PLATFORM(SKIA) operator SkMatrix() const; #elif PLATFORM(WX) && USE(WXGC) operator wxGraphicsMatrix() const; diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index 803f5db..e901669 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -297,6 +297,30 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo CGContextRef cgContext = graphicsContext->platformContext(); bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); + switch(fontDescription().fontSmoothing()) { + case Antialiased: { + graphicsContext->setShouldAntialias(true); + shouldUseFontSmoothing = false; + break; + } + case SubpixelAntialiased: { + graphicsContext->setShouldAntialias(true); + shouldUseFontSmoothing = true; + break; + } + case NoSmoothing: { + graphicsContext->setShouldAntialias(false); + shouldUseFontSmoothing = false; + break; + } + case AutoSmoothing: { + // For the AutoSmooth case, don't do anything! Keep the default settings. + break; + } + default: + ASSERT_NOT_REACHED(); + } + if (font->platformData().useGDI()) { if (!shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) { drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); @@ -338,14 +362,14 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo graphicsContext->clearShadow(); Color fillColor = graphicsContext->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - graphicsContext->setFillColor(shadowFillColor); + graphicsContext->setFillColor(shadowFillColor, DeviceColorSpace); CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } - graphicsContext->setFillColor(fillColor); + graphicsContext->setFillColor(fillColor, DeviceColorSpace); } CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); @@ -356,7 +380,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo } if (hasSimpleShadow) - graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); + graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); } diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp index 887bf79..8663623 100644 --- a/WebCore/platform/graphics/win/FontCacheWin.cpp +++ b/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -33,8 +33,9 @@ #include "SimpleFontData.h" #include "StringHash.h" #include "UnicodeRange.h" -#include <windows.h> #include <mlang.h> +#include <windows.h> +#include <wtf/StdLibExtras.h> #if PLATFORM(CG) #include <ApplicationServices/ApplicationServices.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> @@ -305,7 +306,17 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fo // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick // the default that the user would get without changing any prefs. static AtomicString timesStr("Times New Roman"); - return getCachedFontPlatformData(fontDescription, timesStr); + if (FontPlatformData* platformFont = getCachedFontPlatformData(fontDescription, timesStr)) + return platformFont; + + DEFINE_STATIC_LOCAL(String, defaultGUIFontFamily, ()); + if (defaultGUIFontFamily.isEmpty()) { + HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT)); + LOGFONT logFont; + GetObject(defaultGUIFont, sizeof(logFont), &logFont); + defaultGUIFontFamily = String(logFont.lfFaceName, wcsnlen(logFont.lfFaceName, LF_FACESIZE)); + } + return getCachedFontPlatformData(fontDescription, defaultGUIFontFamily); } static LONG toGDIFontWeight(FontWeight fontWeight) diff --git a/WebCore/platform/graphics/win/FontDatabase.cpp b/WebCore/platform/graphics/win/FontDatabase.cpp index 1308ff0..d0773ea 100644 --- a/WebCore/platform/graphics/win/FontDatabase.cpp +++ b/WebCore/platform/graphics/win/FontDatabase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -99,17 +99,12 @@ static RetainPtr<CFPropertyListRef> readFontPlist() return plist; } -static bool populateFontDatabaseFromPlist() +static bool populateFontDatabaseFromPlist(CFPropertyListRef plist) { - RetainPtr<CFPropertyListRef> plist = readFontPlist(); if (!plist) return false; - RetainPtr<CFDataRef> data(AdoptCF, CFPropertyListCreateXMLData(0, plist.get())); - if (!data) - return false; - - wkAddFontsFromPlistRepresentation(data.get()); + wkAddFontsFromPlist(plist); return true; } @@ -123,15 +118,69 @@ static bool populateFontDatabaseFromFileSystem() return true; } -static void writeFontDatabaseToPlist() +static CFStringRef fontFilenamesFromRegistryKey() +{ + static CFStringRef key = CFSTR("WebKitFontFilenamesFromRegistry"); + return key; +} + +static void writeFontDatabaseToPlist(CFPropertyListRef cgFontDBPropertyList, CFPropertyListRef filenamesFromRegistry) { - RetainPtr<CFDataRef> data(AdoptCF, wkCreateFontsPlistRepresentation()); + if (!cgFontDBPropertyList) + return; + + RetainPtr<CFDataRef> data; + + if (!filenamesFromRegistry || CFGetTypeID(cgFontDBPropertyList) != CFDictionaryGetTypeID()) + data.adoptCF(CFPropertyListCreateXMLData(kCFAllocatorDefault, cgFontDBPropertyList)); + else { + RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF, CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 2, static_cast<CFDictionaryRef>(cgFontDBPropertyList))); + CFDictionarySetValue(dictionary.get(), fontFilenamesFromRegistryKey(), filenamesFromRegistry); + data.adoptCF(CFPropertyListCreateXMLData(kCFAllocatorDefault, dictionary.get())); + } + if (!data) return; safeCreateFile(fontsPlistPath(), data.get()); } +static RetainPtr<CFArrayRef> fontFilenamesFromRegistry() +{ + RetainPtr<CFMutableArrayRef> filenames(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); + + HKEY key; + if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), 0, KEY_READ, &key))) + return filenames; + + DWORD valueCount; + DWORD maxNameLength; + DWORD maxValueLength; + if (FAILED(RegQueryInfoKey(key, 0, 0, 0, 0, 0, 0, &valueCount, &maxNameLength, &maxValueLength, 0, 0))) { + RegCloseKey(key); + return filenames; + } + + Vector<TCHAR> name(maxNameLength + 1); + Vector<BYTE> value(maxValueLength + 1); + + for (size_t i = 0; i < valueCount; ++i) { + DWORD nameLength = name.size(); + DWORD valueLength = value.size(); + DWORD type; + if (FAILED(RegEnumValue(key, i, name.data(), &nameLength, 0, &type, value.data(), &valueLength))) + continue; + if (type != REG_SZ) + continue; + + RetainPtr<CFDataRef> filename(AdoptCF, CFDataCreate(kCFAllocatorDefault, value.data(), valueLength)); + CFArrayAppendValue(filenames.get(), filename.get()); + } + + RegCloseKey(key); + return filenames; +} + void populateFontDatabase() { static bool initialized; @@ -139,12 +188,27 @@ void populateFontDatabase() return; initialized = true; - if (!systemHasFontsNewerThanFontsPlist()) - if (populateFontDatabaseFromPlist()) + RetainPtr<CFPropertyListRef> propertyList = readFontPlist(); + RetainPtr<CFArrayRef> lastFilenamesFromRegistry; + if (propertyList && CFGetTypeID(propertyList.get()) == CFDictionaryGetTypeID()) { + CFDictionaryRef dictionary = static_cast<CFDictionaryRef>(propertyList.get()); + CFArrayRef array = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, fontFilenamesFromRegistryKey())); + if (array && CFGetTypeID(array) == CFArrayGetTypeID()) + lastFilenamesFromRegistry = array; + } + RetainPtr<CFArrayRef> currentFilenamesFromRegistry = fontFilenamesFromRegistry(); + bool registryChanged = !lastFilenamesFromRegistry || !CFEqual(lastFilenamesFromRegistry.get(), currentFilenamesFromRegistry.get()); + + if (!registryChanged && !systemHasFontsNewerThanFontsPlist()) { + if (populateFontDatabaseFromPlist(propertyList.get())) return; + } - if (populateFontDatabaseFromFileSystem()) - writeFontDatabaseToPlist(); + if (populateFontDatabaseFromFileSystem()) { + wkAddFontsFromRegistry(); + RetainPtr<CFPropertyListRef> cgFontDBPropertyList(AdoptCF, wkCreateFontsPlist()); + writeFontDatabaseToPlist(cgFontDBPropertyList.get(), currentFilenamesFromRegistry.get()); + } } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h index 0660d90..5084469 100644 --- a/WebCore/platform/graphics/win/FontPlatformData.h +++ b/WebCore/platform/graphics/win/FontPlatformData.h @@ -78,7 +78,6 @@ public: #if PLATFORM(CG) CGFontRef cgFont() const { return m_cgFont.get(); } #elif PLATFORM(CAIRO) - void setFont(cairo_t* ft) const; cairo_font_face_t* fontFace() const { return m_fontFace; } cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } #endif diff --git a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp index b56a71c..9fce68a 100644 --- a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp @@ -96,12 +96,6 @@ FontPlatformData::FontPlatformData(const FontPlatformData& source) m_scaledFont = cairo_scaled_font_reference(source.m_scaledFont); } -void FontPlatformData::setFont(cairo_t* cr) const -{ - ASSERT(m_scaledFont); - - cairo_set_scaled_font(cr, m_scaledFont); -} FontPlatformData::~FontPlatformData() { diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index 9eaf54b..137b914 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -65,13 +65,13 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha))) { - CGContextRelease(m_data->m_cgContext); + CGContextRelease(m_data->m_cgContext.get()); m_data->m_hdc = hdc; setPaintingDisabled(!m_data->m_cgContext); if (m_data->m_cgContext) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } } @@ -98,7 +98,7 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo CGColorSpaceRelease(deviceRGB); CGImageRef image = CGBitmapContextCreateImage(bitmapContext); - CGContextDrawImage(m_data->m_cgContext, dstRect, image); + CGContextDrawImage(m_data->m_cgContext.get(), dstRect, image); // Delete all our junk. CGImageRelease(image); @@ -121,7 +121,7 @@ void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& po RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(imageData.get())); RetainPtr<CGImageRef> cgImage(AdoptCF, CGImageCreate(image->size().width(), image->size().height(), 8, 32, image->bytesPerRow(), deviceRGB.get(), kCGBitmapByteOrder32Little | kCGImageAlphaFirst, dataProvider.get(), 0, true, kCGRenderingIntentDefault)); - CGContextDrawImage(m_data->m_cgContext, CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get()); + CGContextDrawImage(m_data->m_cgContext.get(), CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get()); } void GraphicsContext::drawFocusRing(const Color& color) @@ -243,7 +243,7 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, void GraphicsContextPlatformPrivate::flush() { - CGContextFlush(m_cgContext); + CGContextFlush(m_cgContext.get()); } } diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 2489e02..61ae76c 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -74,8 +74,8 @@ GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) if (m_data->cr) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), fillColorSpace()); + setPlatformStrokeColor(strokeColor(), strokeColorSpace()); } } diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp new file mode 100644 index 0000000..22faeb8 --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayerCACF.h" + +#include "CString.h" +#include "FloatConversion.h" +#include "FloatRect.h" +#include "Image.h" +#include "PlatformString.h" +#include "SystemTime.h" +#include "WKCACFLayer.h" +#include <wtf/CurrentTime.h> +#include <wtf/StringExtras.h> + +using namespace std; + +namespace WebCore { + +static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t) +{ + toT3D.m11 = narrowPrecisionToFloat(t.m11()); + toT3D.m12 = narrowPrecisionToFloat(t.m12()); + toT3D.m13 = narrowPrecisionToFloat(t.m13()); + toT3D.m14 = narrowPrecisionToFloat(t.m14()); + toT3D.m21 = narrowPrecisionToFloat(t.m21()); + toT3D.m22 = narrowPrecisionToFloat(t.m22()); + toT3D.m23 = narrowPrecisionToFloat(t.m23()); + toT3D.m24 = narrowPrecisionToFloat(t.m24()); + toT3D.m31 = narrowPrecisionToFloat(t.m31()); + toT3D.m32 = narrowPrecisionToFloat(t.m32()); + toT3D.m33 = narrowPrecisionToFloat(t.m33()); + toT3D.m34 = narrowPrecisionToFloat(t.m34()); + toT3D.m41 = narrowPrecisionToFloat(t.m41()); + toT3D.m42 = narrowPrecisionToFloat(t.m42()); + toT3D.m43 = narrowPrecisionToFloat(t.m43()); + toT3D.m44 = narrowPrecisionToFloat(t.m44()); +} + +TransformationMatrix CAToTransform3D(const CATransform3D& fromT3D) +{ + return TransformationMatrix( + fromT3D.m11, + fromT3D.m12, + fromT3D.m13, + fromT3D.m14, + fromT3D.m21, + fromT3D.m22, + fromT3D.m23, + fromT3D.m24, + fromT3D.m31, + fromT3D.m32, + fromT3D.m33, + fromT3D.m34, + fromT3D.m41, + fromT3D.m42, + fromT3D.m43, + fromT3D.m44); +} + +static void setLayerBorderColor(WKCACFLayer* layer, const Color& color) +{ + CGColorRef borderColor = createCGColor(color); + layer->setBorderColor(borderColor); + CGColorRelease(borderColor); +} + +static void clearBorderColor(WKCACFLayer* layer) +{ + layer->setBorderColor(0); +} + +static void setLayerBackgroundColor(WKCACFLayer* layer, const Color& color) +{ + CGColorRef bgColor = createCGColor(color); + layer->setBackgroundColor(bgColor); + CGColorRelease(bgColor); +} + +static void clearLayerBackgroundColor(WKCACFLayer* layer) +{ + layer->setBackgroundColor(0); +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation() +{ + return CompositingCoordinatesBottomUp; +} + +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) +{ + return new GraphicsLayerCACF(client); +} + +GraphicsLayerCACF::GraphicsLayerCACF(GraphicsLayerClient* client) + : GraphicsLayer(client) + , m_contentsLayerPurpose(NoContentsLayer) + , m_contentsLayerHasBackgroundColor(false) +{ + m_layer = WKCACFLayer::create(kCACFLayer, this); + + updateDebugIndicators(); +} + +GraphicsLayerCACF::~GraphicsLayerCACF() +{ + // clean up the WK layer + if (m_layer) + m_layer->removeFromSuperlayer(); + + if (m_transformLayer) + m_transformLayer->removeFromSuperlayer(); +} + +void GraphicsLayerCACF::setName(const String& inName) +{ + String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + inName; + GraphicsLayer::setName(name); + + m_layer->setName(inName); +} + +NativeLayer GraphicsLayerCACF::nativeLayer() const +{ + return m_layer.get(); +} + +bool GraphicsLayerCACF::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + // FIXME: GraphicsLayer::setChildren calls addChild() for each sublayer, which + // will end up calling updateSublayerList() N times. + if (childrenChanged) + updateSublayerList(); + + return childrenChanged; +} + +void GraphicsLayerCACF::addChild(GraphicsLayer* childLayer) +{ + GraphicsLayer::addChild(childLayer); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildAtIndex(GraphicsLayer* childLayer, int index) +{ + GraphicsLayer::addChildAtIndex(childLayer, index); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildBelow(childLayer, sibling); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer *sibling) +{ + GraphicsLayer::addChildAbove(childLayer, sibling); + updateSublayerList(); +} + +bool GraphicsLayerCACF::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + if (GraphicsLayer::replaceChild(oldChild, newChild)) { + updateSublayerList(); + return true; + } + return false; +} + +void GraphicsLayerCACF::removeFromParent() +{ + GraphicsLayer::removeFromParent(); + layerForSuperlayer()->removeFromSuperlayer(); +} + +void GraphicsLayerCACF::setPosition(const FloatPoint& point) +{ + GraphicsLayer::setPosition(point); + updateLayerPosition(); +} + +void GraphicsLayerCACF::setAnchorPoint(const FloatPoint3D& point) +{ + if (point == m_anchorPoint) + return; + + GraphicsLayer::setAnchorPoint(point); + updateAnchorPoint(); +} + +void GraphicsLayerCACF::setSize(const FloatSize& size) +{ + if (size == m_size) + return; + + GraphicsLayer::setSize(size); + updateLayerSize(); +} + +void GraphicsLayerCACF::setTransform(const TransformationMatrix& t) +{ + if (t == m_transform) + return; + + GraphicsLayer::setTransform(t); + updateTransform(); +} + +void GraphicsLayerCACF::setChildrenTransform(const TransformationMatrix& t) +{ + if (t == m_childrenTransform) + return; + + GraphicsLayer::setChildrenTransform(t); + updateChildrenTransform(); +} + +void GraphicsLayerCACF::setPreserves3D(bool preserves3D) +{ + if (preserves3D == m_preserves3D) + return; + + GraphicsLayer::setPreserves3D(preserves3D); + updateLayerPreserves3D(); +} + +void GraphicsLayerCACF::setMasksToBounds(bool masksToBounds) +{ + if (masksToBounds == m_masksToBounds) + return; + + GraphicsLayer::setMasksToBounds(masksToBounds); + updateMasksToBounds(); +} + +void GraphicsLayerCACF::setDrawsContent(bool drawsContent) +{ + if (drawsContent == m_drawsContent) + return; + + GraphicsLayer::setDrawsContent(drawsContent); + updateLayerDrawsContent(); +} + +void GraphicsLayerCACF::setBackgroundColor(const Color& color) +{ + if (m_backgroundColorSet && m_backgroundColor == color) + return; + + GraphicsLayer::setBackgroundColor(color); + + m_contentsLayerHasBackgroundColor = true; + updateLayerBackgroundColor(); +} + +void GraphicsLayerCACF::clearBackgroundColor() +{ + if (!m_backgroundColorSet) + return; + + GraphicsLayer::clearBackgroundColor(); + clearLayerBackgroundColor(m_contentsLayer.get()); +} + +void GraphicsLayerCACF::setContentsOpaque(bool opaque) +{ + if (m_contentsOpaque == opaque) + return; + + GraphicsLayer::setContentsOpaque(opaque); + updateContentsOpaque(); +} + +void GraphicsLayerCACF::setBackfaceVisibility(bool visible) +{ + if (m_backfaceVisibility == visible) + return; + + GraphicsLayer::setBackfaceVisibility(visible); + updateBackfaceVisibility(); +} + +void GraphicsLayerCACF::setOpacity(float opacity) +{ + float clampedOpacity = max(min(opacity, 1.0f), 0.0f); + + if (m_opacity == clampedOpacity) + return; + + GraphicsLayer::setOpacity(clampedOpacity); + primaryLayer()->setOpacity(opacity); +} + +void GraphicsLayerCACF::setNeedsDisplay() +{ + if (drawsContent()) + m_layer->setNeedsDisplay(); +} + +void GraphicsLayerCACF::setNeedsDisplayInRect(const FloatRect& rect) +{ + if (drawsContent()) + m_layer->setNeedsDisplay(rect); +} + +void GraphicsLayerCACF::setContentsRect(const IntRect& rect) +{ + if (rect == m_contentsRect) + return; + + GraphicsLayer::setContentsRect(rect); + updateContentsRect(); +} + +void GraphicsLayerCACF::setContentsToImage(Image* image) +{ + bool childrenChanged = false; + + if (image) { + m_pendingContentsImage = image->nativeImageForCurrentFrame(); + m_contentsLayerPurpose = ContentsLayerForImage; + if (!m_contentsLayer) + childrenChanged = true; + } else { + m_pendingContentsImage = 0; + m_contentsLayerPurpose = NoContentsLayer; + if (m_contentsLayer) + childrenChanged = true; + } + + updateContentsImage(); + + // This has to happen after updateContentsImage + if (childrenChanged) + updateSublayerList(); +} + +void GraphicsLayerCACF::setContentsToVideo(PlatformLayer* videoLayer) +{ + bool childrenChanged = false; + + if (videoLayer != m_contentsLayer.get()) + childrenChanged = true; + + m_contentsLayer = videoLayer; + m_contentsLayerPurpose = videoLayer ? ContentsLayerForVideo : NoContentsLayer; + + updateContentsVideo(); + + // This has to happen after updateContentsVideo + if (childrenChanged) + updateSublayerList(); +} + +void GraphicsLayerCACF::setGeometryOrientation(CompositingCoordinatesOrientation orientation) +{ + if (orientation == m_geometryOrientation) + return; + + GraphicsLayer::setGeometryOrientation(orientation); + updateGeometryOrientation(); +} + +PlatformLayer* GraphicsLayerCACF::hostLayerForSublayers() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerCACF::layerForSuperlayer() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerCACF::platformLayer() const +{ + return primaryLayer(); +} + +void GraphicsLayerCACF::setDebugBackgroundColor(const Color& color) +{ + if (color.isValid()) + setLayerBackgroundColor(m_layer.get(), color); + else + clearLayerBackgroundColor(m_layer.get()); +} + +void GraphicsLayerCACF::setDebugBorder(const Color& color, float borderWidth) +{ + if (color.isValid()) { + setLayerBorderColor(m_layer.get(), color); + m_layer->setBorderWidth(borderWidth); + } else { + clearBorderColor(m_layer.get()); + m_layer->setBorderWidth(0); + } +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCACF::defaultContentsOrientation() const +{ + return CompositingCoordinatesTopDown; +} + +void GraphicsLayerCACF::updateSublayerList() +{ + Vector<RefPtr<WKCACFLayer> > newSublayers; + + if (m_transformLayer) { + // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind. + newSublayers.append(m_layer.get()); + } else if (m_contentsLayer) { + // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. + newSublayers.append(m_contentsLayer.get()); + } + + const Vector<GraphicsLayer*>& childLayers = children(); + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCACF* curChild = static_cast<GraphicsLayerCACF*>(childLayers[i]); + + WKCACFLayer* childLayer = curChild->layerForSuperlayer(); + newSublayers.append(childLayer); + } + + for (int i = 0; i < newSublayers.size(); ++i) + newSublayers[i]->removeFromSuperlayer(); + + if (m_transformLayer) { + m_transformLayer->setSublayers(newSublayers); + + if (m_contentsLayer) { + // If we have a transform layer, then the contents layer is parented in the + // primary layer (which is itself a child of the transform layer). + m_layer->removeAllSublayers(); + m_layer->addSublayer(m_contentsLayer); + } + } else + m_layer->setSublayers(newSublayers); +} + +void GraphicsLayerCACF::updateLayerPosition() +{ + // Position is offset on the layer by the layer anchor point. + CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(), + m_position.y() + m_anchorPoint.y() * m_size.height()); + + primaryLayer()->setPosition(posPoint); +} + +void GraphicsLayerCACF::updateLayerSize() +{ + CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height()); + if (m_transformLayer) { + m_transformLayer->setBounds(rect); + // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative. + CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + m_layer->setPosition(centerPoint); + } + + m_layer->setBounds(rect); + + // Note that we don't resize m_contentsLayer. It's up the caller to do that. + + // if we've changed the bounds, we need to recalculate the position + // of the layer, taking anchor point into account. + updateLayerPosition(); +} + +void GraphicsLayerCACF::updateAnchorPoint() +{ + primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())); + primaryLayer()->setAnchorPointZ(m_anchorPoint.z()); + updateLayerPosition(); +} + +void GraphicsLayerCACF::updateTransform() +{ + CATransform3D transform; + copyTransform(transform, m_transform); + primaryLayer()->setTransform(transform); +} + +void GraphicsLayerCACF::updateChildrenTransform() +{ + CATransform3D transform; + copyTransform(transform, m_childrenTransform); + primaryLayer()->setSublayerTransform(transform); +} + +void GraphicsLayerCACF::updateMasksToBounds() +{ + m_layer->setMasksToBounds(m_masksToBounds); + updateDebugIndicators(); +} + +void GraphicsLayerCACF::updateContentsOpaque() +{ + m_layer->setOpaque(m_contentsOpaque); +} + +void GraphicsLayerCACF::updateBackfaceVisibility() +{ + m_layer->setDoubleSided(m_backfaceVisibility); +} + +void GraphicsLayerCACF::updateLayerPreserves3D() +{ + if (m_preserves3D && !m_transformLayer) { + // Create the transform layer. + m_transformLayer = WKCACFLayer::create(kCACFTransformLayer, this); + +#ifndef NDEBUG + m_transformLayer->setName(String().format("Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this)); +#endif + // Copy the position from this layer. + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + + CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + m_layer->setPosition(point); + + m_layer->setAnchorPoint(CGPointMake(0.5f, 0.5f)); + m_layer->setTransform(CATransform3DIdentity); + + // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer. + m_layer->setOpacity(1); + + // Move this layer to be a child of the transform layer. + if (m_layer->superlayer()) + m_layer->superlayer()->replaceSublayer(m_layer.get(), m_transformLayer.get()); + m_transformLayer->addSublayer(m_layer.get()); + + updateSublayerList(); + } else if (!m_preserves3D && m_transformLayer) { + // Relace the transformLayer in the parent with this layer. + m_layer->removeFromSuperlayer(); + m_transformLayer->superlayer()->replaceSublayer(m_transformLayer.get(), m_layer.get()); + + // Release the transform layer. + m_transformLayer = 0; + + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + + updateSublayerList(); + } + + updateOpacityOnLayer(); +} + +void GraphicsLayerCACF::updateLayerDrawsContent() +{ + if (m_drawsContent) + m_layer->setNeedsDisplay(); + else + m_layer->setContents(nil); + + updateDebugIndicators(); +} + +void GraphicsLayerCACF::updateLayerBackgroundColor() +{ + if (!m_contentsLayer) + return; + + // We never create the contents layer just for background color yet. + if (m_backgroundColorSet) + setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor); + else + clearLayerBackgroundColor(m_contentsLayer.get()); +} + +void GraphicsLayerCACF::updateContentsImage() +{ + if (m_pendingContentsImage) { + if (!m_contentsLayer.get()) { + RefPtr<WKCACFLayer> imageLayer = WKCACFLayer::create(kCACFLayer, this); +#ifndef NDEBUG + imageLayer->setName("Image Layer"); +#endif + setupContentsLayer(imageLayer.get()); + m_contentsLayer = imageLayer; + // m_contentsLayer will be parented by updateSublayerList + } + + // FIXME: maybe only do trilinear if the image is being scaled down, + // but then what if the layer size changes? + m_contentsLayer->setMinificationFilter(kCACFFilterTrilinear); + m_contentsLayer->setContents(m_pendingContentsImage.get()); + m_pendingContentsImage = 0; + + updateContentsRect(); + } else { + // No image. + // m_contentsLayer will be removed via updateSublayerList. + m_contentsLayer = 0; + } +} + +void GraphicsLayerCACF::updateContentsVideo() +{ + // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList(). + if (m_contentsLayer) { + setupContentsLayer(m_contentsLayer.get()); + updateContentsRect(); + } +} + +void GraphicsLayerCACF::updateContentsRect() +{ + if (!m_contentsLayer) + return; + + CGPoint point = CGPointMake(m_contentsRect.x(), + m_contentsRect.y()); + CGRect rect = CGRectMake(0.0f, + 0.0f, + m_contentsRect.width(), + m_contentsRect.height()); + + m_contentsLayer->setPosition(point); + m_contentsLayer->setBounds(rect); +} + +void GraphicsLayerCACF::updateGeometryOrientation() +{ + switch (geometryOrientation()) { + case CompositingCoordinatesTopDown: + m_layer->setGeometryFlipped(false); + break; + + case CompositingCoordinatesBottomUp: + m_layer->setGeometryFlipped(true); + break; + } + // Geometry orientation is mapped onto children transform in older QuartzCores, + // so is handled via setGeometryOrientation(). +} + +void GraphicsLayerCACF::setupContentsLayer(WKCACFLayer* contentsLayer) +{ + if (contentsLayer == m_contentsLayer) + return; + + if (m_contentsLayer) { + m_contentsLayer->removeFromSuperlayer(); + m_contentsLayer = 0; + } + + if (contentsLayer) { + m_contentsLayer = contentsLayer; + + if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) { + CATransform3D flipper = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + m_contentsLayer->setTransform(flipper); + m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 1.0f)); + } else + m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 0.0f)); + + // Insert the content layer first. Video elements require this, because they have + // shadow content that must display in front of the video. + m_layer->insertSublayer(m_contentsLayer.get(), 0); + + updateContentsRect(); + + if (showDebugBorders()) { + setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180)); + m_contentsLayer->setBorderWidth(1.0f); + } + } + updateDebugIndicators(); +} + +// This function simply mimics the operation of GraphicsLayerCA +void GraphicsLayerCACF::updateOpacityOnLayer() +{ + primaryLayer()->setOpacity(m_opacity); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.h b/WebCore/platform/graphics/win/GraphicsLayerCACF.h new file mode 100644 index 0000000..93ddf25 --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GraphicsLayerCACF_h_ +#define GraphicsLayerCACF_h_ + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayer.h" +#include "GraphicsContext.h" +#include <wtf/RetainPtr.h> + +namespace WebCore { + +class WKCACFLayer; + +class GraphicsLayerCACF : public GraphicsLayer { +public: + + GraphicsLayerCACF(GraphicsLayerClient*); + virtual ~GraphicsLayerCACF(); + + virtual void setName(const String& inName); + + // for hosting this GraphicsLayer in a native layer hierarchy + virtual NativeLayer nativeLayer() const; + + virtual bool setChildren(const Vector<GraphicsLayer*>&); + virtual void addChild(GraphicsLayer *layer); + virtual void addChildAtIndex(GraphicsLayer *layer, int index); + virtual void addChildAbove(GraphicsLayer *layer, GraphicsLayer *sibling); + virtual void addChildBelow(GraphicsLayer *layer, GraphicsLayer *sibling); + virtual bool replaceChild(GraphicsLayer *oldChild, GraphicsLayer *newChild); + + virtual void removeFromParent(); + + virtual void setPosition(const FloatPoint& inPoint); + virtual void setAnchorPoint(const FloatPoint3D& inPoint); + virtual void setSize(const FloatSize& inSize); + + virtual void setTransform(const TransformationMatrix&); + + virtual void setChildrenTransform(const TransformationMatrix&); + + virtual void setPreserves3D(bool); + virtual void setMasksToBounds(bool); + virtual void setDrawsContent(bool); + + virtual void setBackgroundColor(const Color&); + virtual void clearBackgroundColor(); + + virtual void setContentsOpaque(bool); + virtual void setBackfaceVisibility(bool); + + virtual void setOpacity(float opacity); + + virtual void setNeedsDisplay(); + virtual void setNeedsDisplayInRect(const FloatRect&); + + virtual void setContentsRect(const IntRect&); + + virtual void setContentsToImage(Image*); + virtual void setContentsToVideo(PlatformLayer*); + + virtual PlatformLayer* platformLayer() const; + + virtual void setDebugBackgroundColor(const Color&); + virtual void setDebugBorder(const Color&, float borderWidth); + + virtual void setGeometryOrientation(CompositingCoordinatesOrientation); + + void notifySyncRequired() { if (m_client) m_client->notifySyncRequired(this); } + +private: + void updateOpacityOnLayer(); + + WKCACFLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); } + WKCACFLayer* hostLayerForSublayers() const; + WKCACFLayer* layerForSuperlayer() const; + + CompositingCoordinatesOrientation defaultContentsOrientation() const; + void updateSublayerList(); + void updateLayerPosition(); + void updateLayerSize(); + void updateAnchorPoint(); + void updateTransform(); + void updateChildrenTransform(); + void updateMasksToBounds(); + void updateContentsOpaque(); + void updateBackfaceVisibility(); + void updateLayerPreserves3D(); + void updateLayerDrawsContent(); + void updateLayerBackgroundColor(); + + void updateContentsImage(); + void updateContentsVideo(); + void updateContentsRect(); + void updateGeometryOrientation(); + + void setupContentsLayer(WKCACFLayer*); + WKCACFLayer* contentsLayer() const { return m_contentsLayer.get(); } + + RefPtr<WKCACFLayer> m_layer; + RefPtr<WKCACFLayer> m_transformLayer; + RefPtr<WKCACFLayer> m_contentsLayer; + + enum ContentsLayerPurpose { + NoContentsLayer = 0, + ContentsLayerForImage, + ContentsLayerForVideo + }; + + ContentsLayerPurpose m_contentsLayerPurpose; + bool m_contentsLayerHasBackgroundColor : 1; + RetainPtr<CGImageRef> m_pendingContentsImage; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // GraphicsLayerCACF_h_ diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp index 61f1fd3..d71ca00 100644 --- a/WebCore/platform/graphics/win/IconWin.cpp +++ b/WebCore/platform/graphics/win/IconWin.cpp @@ -47,20 +47,22 @@ Icon::~Icon() DestroyIcon(m_hIcon); } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - SHFILEINFO sfi; - memset(&sfi, 0, sizeof(sfi)); - - String tmpFilename = filename; - if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + if (filenames.isEmpty()) return 0; - return adoptRef(new Icon(sfi.hIcon)); -} + if (filenames.size() == 1) { + SHFILEINFO sfi; + memset(&sfi, 0, sizeof(sfi)); + + String tmpFilename = filenames[0]; + if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + return 0; + + return adoptRef(new Icon(sfi.hIcon)); + } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) -{ #if PLATFORM(WINCE) return 0; #else diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp index 8a8e943..2c6d41d 100644 --- a/WebCore/platform/graphics/win/ImageCGWin.cpp +++ b/WebCore/platform/graphics/win/ImageCGWin.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "Image.h" #include "BitmapImage.h" +#include "BitmapInfo.h" #include "GraphicsContext.h" #include <ApplicationServices/ApplicationServices.h> @@ -34,6 +35,30 @@ namespace WebCore { +PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) +{ + DIBSECTION dibSection; + if (!GetObject(hBitmap, sizeof(DIBSECTION), &dibSection)) + return 0; + + ASSERT(dibSection.dsBm.bmBitsPixel == 32); + if (dibSection.dsBm.bmBitsPixel != 32) + return 0; + + ASSERT(dibSection.dsBm.bmBits); + if (!dibSection.dsBm.bmBits) + return 0; + + RetainPtr<CGColorSpaceRef> deviceRGB(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGContextRef> bitmapContext(AdoptCF, CGBitmapContextCreate(dibSection.dsBm.bmBits, dibSection.dsBm.bmWidth, dibSection.dsBm.bmHeight, 8, + dibSection.dsBm.bmWidthBytes, deviceRGB.get(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst)); + + // The BitmapImage takes ownership of this. + CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext.get()); + + return adoptRef(new BitmapImage(cgImage)); +} + bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) { ASSERT(bmp); @@ -52,9 +77,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) IntSize imageSize = BitmapImage::size(); if (size) - drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy); else - draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); // Do cleanup CGContextRelease(cgContext); @@ -63,7 +88,7 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) return true; } -void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp) { size_t frames = frameCount(); for (size_t i = 0; i < frames; ++i) { @@ -71,7 +96,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float if (CGImageGetHeight(image) == static_cast<size_t>(srcSize.height()) && CGImageGetWidth(image) == static_cast<size_t>(srcSize.width())) { size_t currentFrame = m_currentFrame; m_currentFrame = i; - draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), styleColorSpace, compositeOp); m_currentFrame = currentFrame; return; } @@ -79,7 +104,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float // No image of the correct size was found, fallback to drawing the current frame IntSize imageSize = BitmapImage::size(); - draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), styleColorSpace, compositeOp); } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp index 591375f..e3c5ea0 100644 --- a/WebCore/platform/graphics/win/ImageCairoWin.cpp +++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp @@ -28,12 +28,33 @@ #include "BitmapImage.h" #include "GraphicsContext.h" #include <cairo.h> +#include <cairo-win32.h> #include <windows.h> #include "PlatformString.h" namespace WebCore { +PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) +{ + DIBSECTION dibSection; + if (!GetObject(hBitmap, sizeof(DIBSECTION), &dibSection)) + return 0; + + ASSERT(dibSection.dsBm.bmBitsPixel == 32); + if (dibSection.dsBm.bmBitsPixel != 32) + return 0; + + ASSERT(dibSection.dsBm.bmBits); + if (!dibSection.dsBm.bmBits) + return 0; + + cairo_surface_t* image = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, dibSection.dsBm.bmWidth, dibSection.dsBm.bmHeight); + + // The BitmapImage object takes over ownership of the cairo_surface_t*, so no need to destroy here. + return adoptRef(new BitmapImage(image)); +} + bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) { ASSERT(bmp); @@ -61,9 +82,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) IntSize imageSize = BitmapImage::size(); if (size) - drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy); else - draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); // Do cleanup cairo_destroy(targetRef); @@ -71,7 +92,7 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) return true; } -void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp) { size_t frames = frameCount(); for (size_t i = 0; i < frames; ++i) { @@ -79,7 +100,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float if (cairo_image_surface_get_height(image) == static_cast<size_t>(srcSize.height()) && cairo_image_surface_get_width(image) == static_cast<size_t>(srcSize.width())) { size_t currentFrame = m_currentFrame; m_currentFrame = i; - draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), DeviceColorSpace, compositeOp); m_currentFrame = currentFrame; return; } @@ -87,7 +108,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float // No image of the correct size was found, fallback to drawing the current frame IntSize imageSize = BitmapImage::size(); - draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, compositeOp); } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/IntPointWin.cpp b/WebCore/platform/graphics/win/IntPointWin.cpp index a6ce0bb..73db199 100644 --- a/WebCore/platform/graphics/win/IntPointWin.cpp +++ b/WebCore/platform/graphics/win/IntPointWin.cpp @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntPoint.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/IntRectWin.cpp b/WebCore/platform/graphics/win/IntRectWin.cpp index 6228be8..fe25a7f 100644 --- a/WebCore/platform/graphics/win/IntRectWin.cpp +++ b/WebCore/platform/graphics/win/IntRectWin.cpp @@ -1,3 +1,4 @@ + /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * @@ -23,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntRect.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/IntSizeWin.cpp b/WebCore/platform/graphics/win/IntSizeWin.cpp index 8a27cdb..26e68da 100644 --- a/WebCore/platform/graphics/win/IntSizeWin.cpp +++ b/WebCore/platform/graphics/win/IntSizeWin.cpp @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntSize.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index eb7334e..a5beea1 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -33,6 +33,8 @@ #include "QTMovieWin.h" #include "ScrollView.h" #include "StringHash.h" +#include "TimeRanges.h" +#include "Timer.h" #include <wtf/HashSet.h> #include <wtf/MathExtras.h> #include <wtf/StdLibExtras.h> @@ -86,6 +88,50 @@ MediaPlayerPrivate::~MediaPlayerPrivate() { } +class TaskTimer : TimerBase { +public: + static void initialize(); + +private: + static void setTaskTimerDelay(double); + static void stopTaskTimer(); + + void fired(); + + static TaskTimer* s_timer; +}; + +TaskTimer* TaskTimer::s_timer = 0; + +void TaskTimer::initialize() +{ + if (s_timer) + return; + + s_timer = new TaskTimer; + + QTMovieWin::setTaskTimerFuncs(setTaskTimerDelay, stopTaskTimer); +} + +void TaskTimer::setTaskTimerDelay(double delayInSeconds) +{ + ASSERT(s_timer); + + s_timer->startOneShot(delayInSeconds); +} + +void TaskTimer::stopTaskTimer() +{ + ASSERT(s_timer); + + s_timer->stop(); +} + +void TaskTimer::fired() +{ + QTMovieWin::taskTimerFired(); +} + void MediaPlayerPrivate::load(const String& url) { if (!QTMovieWin::initializeQuickTime()) { @@ -95,6 +141,9 @@ void MediaPlayerPrivate::load(const String& url) return; } + // Initialize the task timer. + TaskTimer::initialize(); + if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; m_player->networkStateChanged(); @@ -241,6 +290,13 @@ bool MediaPlayerPrivate::hasVideo() const return m_qtMovie->hasVideo(); } +bool MediaPlayerPrivate::hasAudio() const +{ + if (!m_qtMovie) + return false; + return m_qtMovie->hasAudio(); +} + void MediaPlayerPrivate::setVolume(float volume) { if (!m_qtMovie) @@ -262,16 +318,34 @@ void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch) m_qtMovie->setPreservesPitch(preservesPitch); } +bool MediaPlayerPrivate::hasClosedCaptions() const +{ + if (!m_qtMovie) + return false; + return m_qtMovie->hasClosedCaptions(); +} + +void MediaPlayerPrivate::setClosedCaptionsVisible(bool visible) +{ + if (!m_qtMovie) + return; + m_qtMovie->setClosedCaptionsVisible(visible); +} + int MediaPlayerPrivate::dataRate() const { // This is not used at the moment return 0; } -float MediaPlayerPrivate::maxTimeBuffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { + RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + float loaded = maxTimeLoaded(); // rtsp streams are not buffered - return m_isStreaming ? 0 : maxTimeLoaded(); + if (!m_isStreaming && loaded > 0) + timeRanges->add(0, loaded); + return timeRanges.release(); } float MediaPlayerPrivate::maxTimeSeekable() const @@ -575,4 +649,3 @@ bool MediaPlayerPrivate::hasSingleSecurityOrigin() const } #endif - diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index f584148..2bccbbf 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -49,10 +49,14 @@ public: static void registerMediaEngine(MediaEngineRegistrar); ~MediaPlayerPrivate(); - + +private: + MediaPlayerPrivate(MediaPlayer*); + IntSize naturalSize() const; bool hasVideo() const; - + bool hasAudio() const; + void load(const String& url); void cancelLoad(); @@ -76,7 +80,7 @@ public: MediaPlayer::NetworkState networkState() const { return m_networkState; } MediaPlayer::ReadyState readyState() const { return m_readyState; } - float maxTimeBuffered() const; + PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; bool totalBytesKnown() const; @@ -92,8 +96,8 @@ public: bool hasSingleSecurityOrigin() const; -private: - MediaPlayerPrivate(MediaPlayer*); + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); void updateStates(); void doSeek(); diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp index aaa61f1..2d4c2ea 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -45,6 +45,12 @@ using namespace std; static const long minimumQuickTimeVersion = 0x07300000; // 7.3 +static const long closedCaptionTrackType = 'clcp'; +static const long subTitleTrackType = 'sbtl'; +static const long mpeg4ObjectDescriptionTrackType = 'odsm'; +static const long mpeg4SceneDescriptionTrackType = 'sdsm'; +static const long closedCaptionDisplayPropertyID = 'disp'; + // Resizing GWorlds is slow, give them a minimum size so size of small // videos can be animated smoothly static const int cGWorldMinWidth = 640; @@ -62,10 +68,13 @@ static HashSet<QTMovieWinPrivate*>* gTaskList; static Vector<CFStringRef>* gSupportedTypes = 0; static SInt32 quickTimeVersion = 0; +static QTMovieWin::SetTaskTimerDelayFunc gSetTaskTimerDelay = 0; +static QTMovieWin::StopTaskTimerFunc gStopTaskTimer = 0; + static void updateTaskTimer(int maxInterval = 1000) { if (!gTaskList->size()) { - stopSharedTimer(); + gStopTaskTimer(); return; } @@ -73,7 +82,7 @@ static void updateTaskTimer(int maxInterval = 1000) QTGetTimeUntilNextTask(&intervalInMS, 1000); if (intervalInMS > maxInterval) intervalInMS = maxInterval; - setSharedTimerFireDelay(static_cast<float>(intervalInMS) / 1000); + gSetTaskTimerDelay(static_cast<float>(intervalInMS) / 1000); } class QTMovieWinPrivate : public Noncopyable { @@ -166,7 +175,7 @@ QTMovieWinPrivate::~QTMovieWinPrivate() CFRelease(m_currentURL); } -static void taskTimerFired() +void QTMovieWin::taskTimerFired() { // The hash content might change during task() Vector<QTMovieWinPrivate*> tasks; @@ -754,10 +763,10 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& allowedTrackTypes->add(SoundMediaType); allowedTrackTypes->add(TextMediaType); allowedTrackTypes->add(BaseMediaType); - allowedTrackTypes->add('clcp'); // Closed caption - allowedTrackTypes->add('sbtl'); // Subtitle - allowedTrackTypes->add('odsm'); // MPEG-4 object descriptor stream - allowedTrackTypes->add('sdsm'); // MPEG-4 scene description stream + allowedTrackTypes->add(closedCaptionTrackType); + allowedTrackTypes->add(subTitleTrackType); + allowedTrackTypes->add(mpeg4ObjectDescriptionTrackType); + allowedTrackTypes->add(mpeg4SceneDescriptionTrackType); allowedTrackTypes->add(TimeCodeMediaType); allowedTrackTypes->add(TimeCode64MediaType); } @@ -867,6 +876,34 @@ bool QTMovieWin::hasVideo() const return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)); } +bool QTMovieWin::hasAudio() const +{ + if (!m_private->m_movie) + return false; + return (GetMovieIndTrackType(m_private->m_movie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)); +} + + +bool QTMovieWin::hasClosedCaptions() const +{ + if (!m_private->m_movie) + return false; + return GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType); +} + +void QTMovieWin::setClosedCaptionsVisible(bool visible) +{ + if (!m_private->m_movie) + return; + + Track ccTrack = GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType); + if (!ccTrack) + return; + + Boolean doDisplay = visible; + QTSetTrackProperty(ccTrack, closedCaptionTrackType, closedCaptionDisplayPropertyID, sizeof(doDisplay), &doDisplay); +} + pascal OSErr movieDrawingCompleteProc(Movie movie, long data) { UppParam param; @@ -990,6 +1027,12 @@ void QTMovieWin::getSupportedType(unsigned index, const UChar*& str, unsigned& l } +void QTMovieWin::setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer) +{ + gSetTaskTimerDelay = setTaskTimerDelay; + gStopTaskTimer = stopTaskTimer; +} + bool QTMovieWin::initializeQuickTime() { static bool initialized = false; @@ -1009,7 +1052,6 @@ bool QTMovieWin::initializeQuickTime() return false; } EnterMovies(); - setSharedTimerFiredFunction(taskTimerFired); gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc); initializationSucceeded = true; } @@ -1020,7 +1062,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: - setSharedTimerInstanceHandle(hinstDLL); return TRUE; case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h index f46efd3..778f9aa 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.h +++ b/WebCore/platform/graphics/win/QTMovieWin.h @@ -59,6 +59,11 @@ class QTMOVIEWIN_API QTMovieWin { public: static bool initializeQuickTime(); + typedef void (*SetTaskTimerDelayFunc)(double); + typedef void (*StopTaskTimerFunc)(); + static void setTaskTimerFuncs(SetTaskTimerDelayFunc, StopTaskTimerFunc); + static void taskTimerFired(); + QTMovieWin(QTMovieWinClient*); ~QTMovieWin(); @@ -91,6 +96,10 @@ public: void setDisabled(bool); bool hasVideo() const; + bool hasAudio() const; + + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); static unsigned countSupportedTypes(); static void getSupportedType(unsigned index, const UChar*& str, unsigned& len); diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp index 0343007..e845d85 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp @@ -34,11 +34,11 @@ #include "Font.h" #include "FontCache.h" #include "FontDescription.h" -#include "MathExtras.h" #include <cairo.h> #include <cairo-win32.h> #include <mlang.h> #include <tchar.h> +#include <wtf/MathExtras.h> namespace WebCore { @@ -119,10 +119,4 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const return width * metricsMultiplier; } -void SimpleFontData::setFont(cairo_t* cr) const -{ - ASSERT(cr); - m_platformData.setFont(cr); -} - } diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp new file mode 100644 index 0000000..e97b530 --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "WKCACFContextFlusher.h" + +#include <wtf/StdLibExtras.h> +#include <QuartzCore/CACFContext.h> + +namespace WebCore { + +WKCACFContextFlusher& WKCACFContextFlusher::shared() +{ + DEFINE_STATIC_LOCAL(WKCACFContextFlusher, flusher, ()); + return flusher; +} + +WKCACFContextFlusher::WKCACFContextFlusher() +{ +} + +WKCACFContextFlusher::~WKCACFContextFlusher() +{ +} + +void WKCACFContextFlusher::addContext(CACFContextRef context) +{ + ASSERT(context); + + m_contexts.add(context); + CFRetain(context); +} + +void WKCACFContextFlusher::removeContext(CACFContextRef context) +{ + ASSERT(context); + + ContextSet::iterator found = m_contexts.find(context); + if (found == m_contexts.end()) + return; + + CFRelease(*found); + m_contexts.remove(found); +} + +void WKCACFContextFlusher::flushAllContexts() +{ + // addContext might get called beneath CACFContextFlush, and we don't want m_contexts to change while + // we're iterating over it, so we move the contexts into a local ContextSet and iterate over that instead. + ContextSet contextsToFlush; + contextsToFlush.swap(m_contexts); + + ContextSet::const_iterator end = contextsToFlush.end(); + for (ContextSet::const_iterator it = contextsToFlush.begin(); it != end; ++it) { + CACFContextRef context = *it; + CACFContextFlush(context); + CFRelease(context); + } +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.h b/WebCore/platform/graphics/win/WKCACFContextFlusher.h new file mode 100644 index 0000000..9ce76aa --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WKCACFContextFlusher_h +#define WKCACFContextFlusher_h + +#if USE(ACCELERATED_COMPOSITING) + +#include <wtf/Noncopyable.h> + +#include <wtf/HashSet.h> + +typedef struct _CACFContext* CACFContextRef; + +namespace WebCore { + +class WKCACFContextFlusher : public Noncopyable { +public: + static WKCACFContextFlusher& shared(); + + void addContext(CACFContextRef); + void removeContext(CACFContextRef); + + void flushAllContexts(); + +private: + WKCACFContextFlusher(); + ~WKCACFContextFlusher(); + + typedef HashSet<CACFContextRef> ContextSet; + ContextSet m_contexts; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFContextFlusher_h diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp new file mode 100644 index 0000000..21e010d --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "WKCACFLayer.h" + +#include "WKCACFContextFlusher.h" + +#include <stdio.h> +#include <QuartzCore/CACFContext.h> +#include <QuartzCore/CARender.h> + +#pragma comment(lib, "QuartzCore")
+ +namespace WebCore { + +using namespace std; + +static void displayInContext(CACFLayerRef layer, CGContextRef context) +{ + ASSERT_ARG(layer, WKCACFLayer::layer(layer)); + WKCACFLayer::layer(layer)->display(context); +} + +// FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually +// get destroyed in debug builds. A static counter could accomplish this pretty easily. + +WKCACFLayer::WKCACFLayer(CFStringRef className, GraphicsLayerCACF* owner) + : m_layer(AdoptCF, CACFLayerCreate(className)) + , m_needsDisplayOnBoundsChange(false) + , m_owner(owner) +{ + CACFLayerSetUserData(layer(), this); + CACFLayerSetDisplayCallback(layer(), displayInContext); +} + +WKCACFLayer::~WKCACFLayer() +{ + // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer. + ASSERT(!superlayer()); + + CACFLayerSetUserData(layer(), 0); + CACFLayerSetDisplayCallback(layer(), 0); +} + +void WKCACFLayer::display(PlatformGraphicsContext* context) +{ + if (!m_owner) + return; + + CGContextSaveGState(context); + + CGRect layerBounds = bounds(); + if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -layerBounds.size.height); + } + + if (m_owner->client()) { + GraphicsContext graphicsContext(context); + + // It's important to get the clip from the context, because it may be significantly + // smaller than the layer bounds (e.g. tiled layers) + CGRect clipBounds = CGContextGetClipBoundingBox(context); + IntRect clip(enclosingIntRect(clipBounds)); + m_owner->paintGraphicsLayerContents(graphicsContext, clip); + } +#ifndef NDEBUG + else { + ASSERT_NOT_REACHED(); + + // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color, + // so CA never makes backing store for it (which is what -setNeedsDisplay will do above). + CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f); + CGContextFillRect(context, layerBounds); + } +#endif + + if (m_owner->showRepaintCounter()) { + char text[16]; // that's a lot of repaints + _snprintf(text, sizeof(text), "%d", m_owner->incrementRepaintCount()); + + CGContextSaveGState(context); + CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f); + + CGRect aBounds = layerBounds; + + aBounds.size.width = 10 + 12 * strlen(text); + aBounds.size.height = 25; + CGContextFillRect(context, aBounds); + + CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f); + + CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f)); + CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman); + CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text)); + + CGContextRestoreGState(context); + } + + CGContextRestoreGState(context); +} + +void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context) +{ + CACFContextSetLayer(context, layer()); + setNeedsCommit(); +} + +void WKCACFLayer::setNeedsCommit() +{ + CACFContextRef context = CACFLayerGetContext(rootLayer()->layer()); + + // The context might now be set yet. This happens if a property gets set + // before placing the layer in the tree. In this case we don't need to + // worry about remembering the context because we will when the layer is + // added to the tree. + if (context) + WKCACFContextFlusher::shared().addContext(context); + + // Call notifySyncRequired(), which in this implementation plumbs through to + // call setRootLayerNeedsDisplay() on the WebView, which causes the CACFRenderer + // to render a frame. + if (m_owner) + m_owner->notifySyncRequired(); +} + +void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer) +{ + insertSublayer(sublayer, numSublayers()); +} + +void WKCACFLayer::insertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index) +{ + index = min(index, numSublayers()); + CACFLayerInsertSublayer(layer(), sublayer->layer(), index); + setNeedsCommit(); +} + +void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference) +{ + if (!reference) { + insertSublayer(sublayer, 0); + return; + } + + int referenceIndex = indexOfSublayer(reference); + if (referenceIndex == -1) { + addSublayer(sublayer); + return; + } + + insertSublayer(sublayer, referenceIndex + 1); +} + +void WKCACFLayer::insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference) +{ + if (!reference) { + insertSublayer(sublayer, 0); + return; + } + + int referenceIndex = indexOfSublayer(reference); + if (referenceIndex == -1) { + addSublayer(sublayer); + return; + } + + insertSublayer(sublayer, referenceIndex); +} + +void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer> newLayer) +{ + ASSERT_ARG(reference, reference); + ASSERT_ARG(reference, reference->superlayer() == this); + + if (reference == newLayer) + return; + + if (!newLayer) { + removeSublayer(reference); + return; + } + + newLayer->removeFromSuperlayer(); + + int referenceIndex = indexOfSublayer(reference); + ASSERT(referenceIndex != -1); + if (referenceIndex == -1) + return; + + // FIXME: Can we make this more efficient? The current CACF API doesn't seem to give us a way to do so. + reference->removeFromSuperlayer(); + insertSublayer(newLayer, referenceIndex); +} + +void WKCACFLayer::removeFromSuperlayer() +{ + WKCACFLayer* superlayer = this->superlayer(); + if (!superlayer) + return; + + superlayer->removeSublayer(this); + CACFLayerRemoveFromSuperlayer(layer()); + superlayer->setNeedsCommit(); +} + +void WKCACFLayer::removeSublayer(const WKCACFLayer* sublayer) +{ + int foundIndex = indexOfSublayer(sublayer); + if (foundIndex == -1) + return; + + CACFLayerRemoveFromSuperlayer(sublayer->layer()); + setNeedsCommit(); +} + +int WKCACFLayer::indexOfSublayer(const WKCACFLayer* reference) +{ + CACFLayerRef ref = reference->layer(); + if (!ref) + return -1; + + CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + size_t n = CFArrayGetCount(sublayers); + + for (size_t i = 0; i < n; ++i) + if (CFArrayGetValueAtIndex(sublayers, i) == ref) + return i; + + return -1; +} + +WKCACFLayer* WKCACFLayer::ancestorOrSelfWithSuperlayer(WKCACFLayer* superlayer) const +{ + WKCACFLayer* layer = const_cast<WKCACFLayer*>(this); + for (WKCACFLayer* ancestor = this->superlayer(); ancestor; layer = ancestor, ancestor = ancestor->superlayer()) { + if (ancestor == superlayer) + return layer; + } + return 0; +} + +void WKCACFLayer::setBounds(const CGRect& rect) +{ + if (CGRectEqualToRect(rect, bounds())) + return; + + CACFLayerSetBounds(layer(), rect); + setNeedsCommit(); + + if (m_needsDisplayOnBoundsChange) + setNeedsDisplay(); +} + +void WKCACFLayer::setFrame(const CGRect& rect) +{ + CGRect oldFrame = frame(); + if (CGRectEqualToRect(rect, oldFrame)) + return; + + CACFLayerSetFrame(layer(), rect); + setNeedsCommit(); + + if (m_needsDisplayOnBoundsChange) + setNeedsDisplay(); +} + +WKCACFLayer* WKCACFLayer::rootLayer() const +{ + WKCACFLayer* layer = const_cast<WKCACFLayer*>(this); + for (WKCACFLayer* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { } + return layer; +} + +void WKCACFLayer::removeAllSublayers() +{ + CACFLayerSetSublayers(layer(), 0); + setNeedsCommit(); +} + +void WKCACFLayer::setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) +{ + if (sublayers.isEmpty()) + CACFLayerSetSublayers(layer(), 0); + else { + // Create a vector of CACFLayers. + Vector<const void*> layers; + for (size_t i = 0; i < sublayers.size(); i++) + layers.append(sublayers[i]->layer()); + + RetainPtr<CFArrayRef> layersArray(AdoptCF, CFArrayCreate(0, layers.data(), layers.size(), 0)); + CACFLayerSetSublayers(layer(), layersArray.get()); + } + + setNeedsCommit(); +} + +void WKCACFLayer::moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer) +{ + if (!fromLayer || !toLayer) + return; + + CACFLayerSetSublayers(toLayer->layer(), CACFLayerGetSublayers(fromLayer->layer())); + fromLayer->setNeedsCommit(); + toLayer->setNeedsCommit(); +} + +WKCACFLayer* WKCACFLayer::superlayer() const +{ + CACFLayerRef super = CACFLayerGetSuperlayer(layer()); + if (!super) + return 0; + return WKCACFLayer::layer(super); +} + +void WKCACFLayer::setNeedsDisplay(const CGRect& dirtyRect) +{ + if (m_owner) + CACFLayerSetNeedsDisplay(layer(), &dirtyRect); + setNeedsCommit(); +} + +void WKCACFLayer::setNeedsDisplay() +{ + if (m_owner) + CACFLayerSetNeedsDisplay(layer(), 0); + setNeedsCommit(); +} + + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h new file mode 100644 index 0000000..6655f7a --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayer.h @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WKCACFLayer_h +#define WKCACFLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "StringHash.h" + +#include <wtf/RefCounted.h> + +#include <QuartzCore/CACFLayer.h> +#include <QuartzCore/CACFVector.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> + +#include "GraphicsContext.h" +#include "GraphicsLayerCACF.h" +#include "PlatformString.h" +#include "TransformationMatrix.h" + +namespace WebCore { + +class WKCACFAnimation; +class WKCACFTimingFunction; + +class WKCACFLayer : public RefCounted<WKCACFLayer> { +public: + static PassRefPtr<WKCACFLayer> create(CFStringRef className, GraphicsLayerCACF* owner = 0) { return adoptRef(new WKCACFLayer(className, owner)); } + static WKCACFLayer* layer(CACFLayerRef layer) { return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer)); } + + ~WKCACFLayer(); + + // Makes this layer the root when the passed context is rendered + void becomeRootLayerForContext(CACFContextRef); + + static RetainPtr<CFTypeRef> cfValue(float value) { return RetainPtr<CFTypeRef>(AdoptCF, CFNumberCreate(0, kCFNumberFloat32Type, &value)); } + static RetainPtr<CFTypeRef> cfValue(const TransformationMatrix& value) + { + CATransform3D t; + t.m11 = value.m11(); + t.m12 = value.m12(); + t.m13 = value.m13(); + t.m14 = value.m14(); + t.m21 = value.m21(); + t.m22 = value.m22(); + t.m23 = value.m23(); + t.m24 = value.m24(); + t.m31 = value.m31(); + t.m32 = value.m32(); + t.m33 = value.m33(); + t.m34 = value.m34(); + t.m41 = value.m41(); + t.m42 = value.m42(); + t.m43 = value.m43(); + t.m44 = value.m44(); + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreateTransform(t)); + } + static RetainPtr<CFTypeRef> cfValue(const FloatPoint& value) + { + CGPoint p; + p.x = value.x(); p.y = value.y(); + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreatePoint(p)); + } + static RetainPtr<CFTypeRef> cfValue(const FloatRect& rect) + { + CGRect r; + r.origin.x = rect.x(); + r.origin.y = rect.y(); + r.size.width = rect.width(); + r.size.height = rect.height(); + CGFloat v[4] = { CGRectGetMinX(r), CGRectGetMinY(r), CGRectGetMaxX(r), CGRectGetMaxY(r) }; + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreate(4, v)); + } + static RetainPtr<CFTypeRef> cfValue(const Color& color) + { + return RetainPtr<CFTypeRef>(AdoptCF, CGColorCreateGenericRGB(color.red(), color.green(), color.blue(), color.alpha())); + } + + void display(PlatformGraphicsContext*); + + bool isTransformLayer() const { return CACFLayerGetClass(layer()) == kCACFTransformLayer; } + + void addSublayer(PassRefPtr<WKCACFLayer> sublayer); + void insertSublayer(PassRefPtr<WKCACFLayer>, size_t index); + void insertSublayerAboveLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); + void insertSublayerBelowLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); + void replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer>); + void removeFromSuperlayer(); + static void moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer); + + WKCACFLayer* ancestorOrSelfWithSuperlayer(WKCACFLayer*) const; + + void setAnchorPoint(const CGPoint& p) { CACFLayerSetAnchorPoint(layer(), p); setNeedsCommit(); } + CGPoint anchorPoint() const { return CACFLayerGetAnchorPoint(layer()); } + + void setAnchorPointZ(CGFloat z) { CACFLayerSetAnchorPointZ(layer(), z); setNeedsCommit(); } + CGFloat anchorPointZ() const { return CACFLayerGetAnchorPointZ(layer()); } + + void setBackgroundColor(CGColorRef color) { CACFLayerSetBackgroundColor(layer(), color); setNeedsCommit(); } + CGColorRef backgroundColor() const { return CACFLayerGetBackgroundColor(layer()); } + + void setBorderColor(CGColorRef color) { CACFLayerSetBorderColor(layer(), color); setNeedsCommit(); } + CGColorRef borderColor() const { return CACFLayerGetBorderColor(layer()); } + + void setBorderWidth(CGFloat width) { CACFLayerSetBorderWidth(layer(), width); setNeedsCommit(); } + CGFloat borderWidth() const { return CACFLayerGetBorderWidth(layer()); } + + void setBounds(const CGRect&); + CGRect bounds() const { return CACFLayerGetBounds(layer()); } + + void setClearsContext(bool clears) { CACFLayerSetClearsContext(layer(), clears); setNeedsCommit(); } + bool clearsContext() const { return CACFLayerGetClearsContext(layer()); } + + void setContents(CGImageRef contents) { CACFLayerSetContents(layer(), contents); setNeedsCommit(); } + CGImageRef contents() const { return static_cast<CGImageRef>(const_cast<void*>(CACFLayerGetContents(layer()))); } + + void setContentsRect(const CGRect& contentsRect) { CACFLayerSetContentsRect(layer(), contentsRect); setNeedsCommit(); } + CGRect contentsRect() const { return CACFLayerGetContentsRect(layer()); } + + void setContentsGravity(CFStringRef str) { CACFLayerSetContentsGravity(layer(), str); setNeedsCommit(); } + CFStringRef contentsGravity() const { return CACFLayerGetContentsGravity(layer()); } + + void setDoubleSided(bool b) { CACFLayerSetDoubleSided(layer(), b); setNeedsCommit(); } + bool doubleSided() const { return CACFLayerIsDoubleSided(layer()); } + + void setEdgeAntialiasingMask(uint32_t mask) { CACFLayerSetEdgeAntialiasingMask(layer(), mask); setNeedsCommit(); } + uint32_t edgeAntialiasingMask() const { return CACFLayerGetEdgeAntialiasingMask(layer()); } + + void setFilters(CFArrayRef filters) { CACFLayerSetFilters(layer(), filters); setNeedsCommit(); } + CFArrayRef filters() const { return CACFLayerGetFilters(layer()); } + + void setFrame(const CGRect&); + CGRect frame() const { return CACFLayerGetFrame(layer()); } + + void setHidden(bool hidden) { CACFLayerSetHidden(layer(), hidden); setNeedsCommit(); } + bool isHidden() const { return CACFLayerIsHidden(layer()); } + + void setMasksToBounds(bool b) { CACFLayerSetMasksToBounds(layer(), b); } + bool masksToBounds() const { return CACFLayerGetMasksToBounds(layer()); } + + void setMagnificationFilter(const String& string) { CACFLayerSetMagnificationFilter(layer(), RetainPtr<CFStringRef>(AdoptCF, string.createCFString()).get()); } + String magnificationFilter() const { return CACFLayerGetMagnificationFilter(layer()); } + + void setMinificationFilter(const String& string) { CACFLayerSetMinificationFilter(layer(), RetainPtr<CFStringRef>(AdoptCF, string.createCFString()).get()); } + String minificationFilter() const { return CACFLayerGetMinificationFilter(layer()); } + + void setMinificationFilterBias(float bias) { CACFLayerSetMinificationFilterBias(layer(), bias); } + float minificationFilterBias() const { return CACFLayerGetMinificationFilterBias(layer()); } + + void setName(const String& name) { CACFLayerSetName(layer(), RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get()); } + String name() const { return CACFLayerGetName(layer()); } + + void setNeedsDisplay(const CGRect& dirtyRect); + void setNeedsDisplay(); + + void setNeedsDisplayOnBoundsChange(bool needsDisplay) { m_needsDisplayOnBoundsChange = needsDisplay; } + + void setOpacity(float opacity) { CACFLayerSetOpacity(layer(), opacity); setNeedsCommit(); } + float opacity() const { return CACFLayerGetOpacity(layer()); } + + void setOpaque(bool b) { CACFLayerSetOpaque(layer(), b); setNeedsCommit(); } + bool opaque() const { return CACFLayerIsOpaque(layer()); } + + void setPosition(const CGPoint& position) { CACFLayerSetPosition(layer(), position); setNeedsCommit(); } + CGPoint position() const { return CACFLayerGetPosition(layer()); } + + void setZPosition(CGFloat position) { CACFLayerSetZPosition(layer(), position); setNeedsCommit(); } + CGFloat zPosition() const { return CACFLayerGetZPosition(layer()); } + + void setSpeed(float speed) { CACFLayerSetSpeed(layer(), speed); } + CFTimeInterval speed() const { CACFLayerGetSpeed(layer()); } + + void setTimeOffset(CFTimeInterval t) { CACFLayerSetTimeOffset(layer(), t); } + CFTimeInterval timeOffset() const { CACFLayerGetTimeOffset(layer()); } + + WKCACFLayer* rootLayer() const; + + void setSortsSublayers(bool sorts) { CACFLayerSetSortsSublayers(layer(), sorts); setNeedsCommit(); } + bool sortsSublayers() const { return CACFLayerGetSortsSublayers(layer()); } + + void removeAllSublayers(); + + void setSublayers(const Vector<RefPtr<WKCACFLayer> >&); + + void setSublayerTransform(const CATransform3D& transform) { CACFLayerSetSublayerTransform(layer(), transform); setNeedsCommit(); } + CATransform3D sublayerTransform() const { return CACFLayerGetSublayerTransform(layer()); } + + WKCACFLayer* superlayer() const; + + void setTransform(const CATransform3D& transform) { CACFLayerSetTransform(layer(), transform); setNeedsCommit(); } + CATransform3D transform() const { return CACFLayerGetTransform(layer()); } + + void setGeometryFlipped(bool flipped) { CACFLayerSetGeometryFlipped(layer(), flipped); setNeedsCommit(); } + bool geometryFlipped() const { return CACFLayerIsGeometryFlipped(layer()); } + + WKCACFLayer(CFStringRef className, GraphicsLayerCACF* owner); + +private: + void setNeedsCommit(); + CACFLayerRef layer() const { return m_layer.get(); } + size_t numSublayers() const + { + CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + return sublayers ? CFArrayGetCount(sublayers) : 0; + } + + // Returns the index of the passed layer in this layer's sublayers list + // or -1 if not found + int indexOfSublayer(const WKCACFLayer*); + + // This should only be called from removeFromSuperlayer. + void removeSublayer(const WKCACFLayer*); + + RetainPtr<CACFLayerRef> m_layer; + bool m_needsDisplayOnBoundsChange; + GraphicsLayerCACF* m_owner; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFLayer_h diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp new file mode 100644 index 0000000..9fbd0fc --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "WKCACFLayerRenderer.h" + +#include "WKCACFContextFlusher.h" +#include "WKCACFLayer.h" +#include <CoreGraphics/CGSRegion.h> +#include <QuartzCore/CACFContext.h> +#include <QuartzCore/CARenderOGL.h> +#include <wtf/HashMap.h> +#include <wtf/OwnArrayPtr.h> +#include <d3d9.h> +#include <d3dx9.h> +#include <dxerr9.h> + +#pragma comment(lib, "d3d9")
+#pragma comment(lib, "d3dx9")
+#pragma comment(lib, "QuartzCore")
+ +static IDirect3D9* s_d3d = 0; +static IDirect3D9* d3d() +{ + if (s_d3d) + return s_d3d; + + if (!LoadLibrary(TEXT("d3d9.dll"))) + return 0; + + s_d3d = Direct3DCreate9(D3D_SDK_VERSION); + + return s_d3d; +} + +inline static CGRect winRectToCGRect(RECT rc) +{ + return CGRectMake(rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top)); +} + +inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect) +{ + return CGRectMake(rc.left, (relativeToRect.bottom-rc.bottom), (rc.right - rc.left), (rc.bottom - rc.top)); +} + +namespace WebCore { + +typedef HashMap<CACFContextRef, WKCACFLayerRenderer*> ContextToWindowMap; + +static ContextToWindowMap& windowsForContexts() +{ + DEFINE_STATIC_LOCAL(ContextToWindowMap, map, ()); + return map; +} + +static D3DPRESENT_PARAMETERS initialPresentationParameters() +{ + D3DPRESENT_PARAMETERS parameters = {0}; + parameters.Windowed = TRUE; + parameters.SwapEffect = D3DSWAPEFFECT_COPY; + parameters.BackBufferCount = 1; + parameters.BackBufferFormat = D3DFMT_A8R8G8B8; + parameters.MultiSampleType = D3DMULTISAMPLE_NONE; + + return parameters; +} + +bool WKCACFLayerRenderer::acceleratedCompositingAvailable()
+{
+ static bool available;
+ static bool tested;
+
+ if (tested)
+ return available;
+
+ tested = true;
+ HMODULE library = LoadLibrary(TEXT("d3d9.dll"));
+ if (!library)
+ return false;
+
+ FreeLibrary(library);
+ library = LoadLibrary(TEXT("QuartzCore.dll"));
+ if (!library)
+ return false;
+
+ FreeLibrary(library);
+ available = true;
+ return available;
+}
+
+void WKCACFLayerRenderer::didFlushContext(CACFContextRef context) +{ + WKCACFLayerRenderer* window = windowsForContexts().get(context); + if (!window) + return; + + window->renderSoon(); +} + +PassOwnPtr<WKCACFLayerRenderer> WKCACFLayerRenderer::create() +{ + if (!acceleratedCompositingAvailable()) + return 0; + return new WKCACFLayerRenderer; +} + +WKCACFLayerRenderer::WKCACFLayerRenderer() + : m_triedToCreateD3DRenderer(false) + , m_renderContext(0) + , m_renderer(0) + , m_hostWindow(0) + , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired) + , m_scrollFrameWidth(1) // Default to 1 to avoid 0 size frames + , m_scrollFrameHeight(1) // Default to 1 to avoid 0 size frames +{ +} + +WKCACFLayerRenderer::~WKCACFLayerRenderer() +{ + destroyRenderer(); +} + +void WKCACFLayerRenderer::setScrollFrame(int width, int height, int scrollX, int scrollY) +{ + m_scrollFrameWidth = width; + m_scrollFrameHeight = height; + + CGRect contentsRect = CGRectMake(scrollX, scrollY, width, height); + m_scrollLayer->setFrame(contentsRect); + + if (m_rootChildLayer) { + contentsRect.origin.x = 0; + contentsRect.origin.y = 0; + m_rootChildLayer->setFrame(contentsRect); + } +} + +void WKCACFLayerRenderer::setRootContents(CGImageRef image) +{ + ASSERT(m_rootLayer); + m_rootLayer->setContents(image); + renderSoon(); +} + +void WKCACFLayerRenderer::setRootChildLayer(WebCore::PlatformLayer* layer) +{ + if (!m_scrollLayer) + return; + + m_scrollLayer->removeAllSublayers(); + if (layer) { + m_scrollLayer->addSublayer(layer); + + // Set the frame + layer->setFrame(CGRectMake(0, 0, m_scrollFrameWidth, m_scrollFrameHeight)); + } + + m_rootChildLayer = layer; + +} + +void WKCACFLayerRenderer::setNeedsDisplay() +{ + ASSERT(m_rootLayer); + m_rootLayer->setNeedsDisplay(); + renderSoon(); +} + +void WKCACFLayerRenderer::createRenderer() +{ + if (m_triedToCreateD3DRenderer) + return; + + m_triedToCreateD3DRenderer = true; + D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); + + if (!d3d() || !::IsWindow(m_hostWindow)) + return; + + // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the + // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero + // size eventually, and then the backbuffer size will get reset. + RECT rect; + GetClientRect(m_hostWindow, &rect); + + if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) { + parameters.BackBufferWidth = 1; + parameters.BackBufferHeight = 1; + } + + if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, ¶meters, &m_d3dDevice))) + return; + + D3DXMATRIXA16 projection; + D3DXMatrixOrthoOffCenterRH(&projection, rect.left, rect.right, rect.top, rect.bottom, -1.0f, 1.0f); + + m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); + + m_context.adoptCF(CACFContextCreate(0)); + windowsForContexts().set(m_context.get(), this); + + m_renderContext = static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get())); + m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0); + + // Create the root hierarchy + m_rootLayer = WKCACFLayer::create(kCACFLayer); + m_scrollLayer = WKCACFLayer::create(kCACFLayer); + + m_rootLayer->addSublayer(m_scrollLayer); + m_scrollLayer->setMasksToBounds(true); + +#ifndef NDEBUG + CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204)); + m_rootLayer->setBackgroundColor(debugColor); + CGColorRelease(debugColor); +#endif + + if (IsWindow(m_hostWindow)) { + m_rootLayer->setFrame(bounds()); + + // For now this will include the scroll bars. Later in the setScrollFrame + // we will fix it + m_scrollLayer->setFrame(bounds()); + } + + if (m_context) + m_rootLayer->becomeRootLayerForContext(m_context.get()); +} + +void WKCACFLayerRenderer::destroyRenderer() +{ + if (m_context) { + windowsForContexts().remove(m_context.get()); + WKCACFContextFlusher::shared().removeContext(m_context.get()); + } + + if (m_renderer) + CARenderOGLDestroy(m_renderer); + m_renderer = 0; + m_d3dDevice = 0; + if (s_d3d) + s_d3d->Release(); + + s_d3d = 0; + m_rootLayer = 0; + m_scrollLayer = 0; + m_rootChildLayer = 0; + + m_triedToCreateD3DRenderer = false; +} + +void WKCACFLayerRenderer::resize() +{ + if (!m_d3dDevice) + return; + + resetDevice(); + + if (m_rootLayer) { + m_rootLayer->setFrame(bounds()); + WKCACFContextFlusher::shared().flushAllContexts(); + } +} + +static void getDirtyRects(HWND window, Vector<CGRect>& outRects) +{ + ASSERT_ARG(outRects, outRects.isEmpty()); + + RECT clientRect; + if (!GetClientRect(window, &clientRect)) + return; + + HRGN region = CreateRectRgn(0, 0, 0, 0); + int regionType = GetUpdateRgn(window, region, false); + if (regionType != COMPLEXREGION) { + RECT dirtyRect; + if (GetUpdateRect(window, &dirtyRect, false)) + outRects.append(winRectToCGRect(dirtyRect, clientRect)); + return; + } + + DWORD dataSize = GetRegionData(region, 0, 0); + OwnArrayPtr<unsigned char> regionDataBuffer(new unsigned char[dataSize]); + RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get()); + if (!GetRegionData(region, dataSize, regionData)) + return; + + outRects.resize(regionData->rdh.nCount); + + RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer); + for (size_t i = 0; i < outRects.size(); ++i, ++rect) + outRects[i] = winRectToCGRect(*rect, clientRect); + + DeleteObject(region); +} + +void WKCACFLayerRenderer::renderTimerFired(Timer<WKCACFLayerRenderer>*) +{ + paint(); +} + +void WKCACFLayerRenderer::paint() +{ + if (!m_d3dDevice) + return; + + Vector<CGRect> dirtyRects; + getDirtyRects(m_hostWindow, dirtyRects); + render(dirtyRects); +} + +void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) +{ + ASSERT(m_d3dDevice); + + // Flush the root layer to the render tree. + WKCACFContextFlusher::shared().flushAllContexts(); + + CGRect bounds = this->bounds(); + + CFTimeInterval t = CACurrentMediaTime(); + + // Give the renderer some space to use. This needs to be valid until the + // CARenderUpdateFinish() call below. + char space[4096]; + CARenderUpdate* u = CARenderUpdateBegin(space, sizeof(space), t, 0, 0, &bounds); + if (!u) + return; + + CARenderContextLock(m_renderContext); + CARenderUpdateAddContext(u, m_renderContext); + CARenderContextUnlock(m_renderContext); + + for (size_t i = 0; i < dirtyRects.size(); ++i) + CARenderUpdateAddRect(u, &dirtyRects[i]); + + HRESULT err = S_OK; + do { + CGSRegionObj rgn = CARenderUpdateCopyRegion(u); + + if (!rgn) + break; + + // FIXME: don't need to clear dirty region if layer tree is opaque. + + Vector<D3DRECT, 64> rects; + CGSRegionEnumeratorObj e = CGSRegionEnumerator(rgn); + for (const CGRect* r = CGSNextRect(e); r; r = CGSNextRect(e)) { + D3DRECT rect; + rect.x1 = r->origin.x; + rect.x2 = rect.x1 + r->size.width; + rect.y1 = bounds.origin.y + bounds.size.height - (r->origin.y + r->size.height); + rect.y2 = rect.y1 + r->size.height; + + rects.append(rect); + } + CGSReleaseRegionEnumerator(e); + CGSReleaseRegion(rgn); + + if (rects.isEmpty()) + break; + + m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0); + + m_d3dDevice->BeginScene(); + CARenderOGLRender(m_renderer, u); + m_d3dDevice->EndScene(); + + err = m_d3dDevice->Present(0, 0, 0, 0); + + if (err == D3DERR_DEVICELOST) { + // Lost device situation. + CARenderOGLPurge(m_renderer); + resetDevice(); + CARenderUpdateAddRect(u, &bounds); + } + } while (err == D3DERR_DEVICELOST); + + CARenderUpdateFinish(u); +} + +void WKCACFLayerRenderer::renderSoon() +{ + if (!m_renderTimer.isActive()) + m_renderTimer.startOneShot(0); +} + +CGRect WKCACFLayerRenderer::bounds() const +{ + RECT clientRect; + GetClientRect(m_hostWindow, &clientRect); + + return winRectToCGRect(clientRect); +} + +void WKCACFLayerRenderer::initD3DGeometry() +{ + ASSERT(m_d3dDevice); + + CGRect bounds = this->bounds(); + + float x0 = bounds.origin.x; + float y0 = bounds.origin.y; + float x1 = x0 + bounds.size.width; + float y1 = y0 + bounds.size.height; + + D3DXMATRIXA16 projection; + D3DXMatrixOrthoOffCenterRH(&projection, x0, x1, y0, y1, -1.0f, 1.0f); + + m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); +} + +void WKCACFLayerRenderer::resetDevice() +{ + ASSERT(m_d3dDevice); + + D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); + m_d3dDevice->Reset(¶meters); + initD3DGeometry(); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h new file mode 100644 index 0000000..12cde48 --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WKCACFLayerRenderer_h +#define WKCACFLayerRenderer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "COMPtr.h" +#include "Timer.h" +#include "WKCACFLayer.h" + +#include <wtf/Noncopyable.h> + +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/RetainPtr.h> + +#include <CoreGraphics/CGGeometry.h> + +interface IDirect3DDevice9; +typedef struct _CACFContext* CACFContextRef; +typedef struct _CARenderContext CARenderContext; +typedef struct _CARenderOGLContext CARenderOGLContext; + +namespace WebCore { + +// FIXME: Currently there is a WKCACFLayerRenderer for each WebView and each +// has its own CARenderOGLContext and Direct3DDevice9, which is inefficient. +// (https://bugs.webkit.org/show_bug.cgi?id=31855) +class WKCACFLayerRenderer : public Noncopyable { +public: + static PassOwnPtr<WKCACFLayerRenderer> create(); + ~WKCACFLayerRenderer(); + + static bool acceleratedCompositingAvailable(); + static void didFlushContext(CACFContextRef); + + void setScrollFrame(int width, int height, int scrollX, int scrollY); + void setRootContents(CGImageRef); + void setRootChildLayer(WebCore::PlatformLayer* layer); + void setNeedsDisplay(); + void setHostWindow(HWND window) { m_hostWindow = window; createRenderer(); } + + void createRenderer(); + void destroyRenderer(); + void resize(); + void renderSoon(); + +protected: + WKCACFLayer* rootLayer() const { return m_rootLayer.get(); } + +private: + WKCACFLayerRenderer(); + + void renderTimerFired(Timer<WKCACFLayerRenderer>*); + + CGRect bounds() const; + + void initD3DGeometry(); + void resetDevice(); + + void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); + void paint(); + + bool m_triedToCreateD3DRenderer; + COMPtr<IDirect3DDevice9> m_d3dDevice; + RefPtr<WKCACFLayer> m_rootLayer; + RefPtr<WKCACFLayer> m_viewLayer; + RefPtr<WKCACFLayer> m_scrollLayer; + RefPtr<WKCACFLayer> m_rootChildLayer; + RetainPtr<CACFContextRef> m_context; + CARenderContext* m_renderContext; + CARenderOGLContext* m_renderer; + HWND m_hostWindow; + Timer<WKCACFLayerRenderer> m_renderTimer; + int m_scrollFrameWidth, m_scrollFrameHeight; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFLayerRenderer_h diff --git a/WebCore/platform/graphics/wince/ColorWince.cpp b/WebCore/platform/graphics/wince/ColorWince.cpp new file mode 100644 index 0000000..820b9d2 --- /dev/null +++ b/WebCore/platform/graphics/wince/ColorWince.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007-2008 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Color.h" + +#include "NotImplemented.h" + +namespace WebCore { + +Color focusRingColor() +{ + return Color(0, 0, 0); +} + +void setFocusRingColorChangeFunction(void (*)()) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp index 7c6853c..699ff25 100644 --- a/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp @@ -33,6 +33,11 @@ static CustomFontCache* g_customFontCache = 0; bool renameFont(SharedBuffer* fontData, const String& fontName); +void setCustomFontCache(CustomFontCache* cache) +{ + g_customFontCache = cache; +} + FontCustomPlatformData::~FontCustomPlatformData() { if (g_customFontCache && !m_name.isEmpty()) @@ -66,11 +71,12 @@ static String createUniqueFontName() return fontName.replace('/', '_'); } -FontCustomPlatformData* createFontCustomPlatformData(CachedFont* cachedFont) +FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer* buffer) { - if (g_customFontCache && cachedFont->CachedResource::data()) { + if (g_customFontCache) { String fontName = createUniqueFontName(); - if (renameFont(cachedFont->CachedResource::data(), fontName) && g_customFontCache->registerFont(fontName, cachedFont)) + RefPtr<SharedBuffer> localBuffer = SharedBuffer::create(buffer->data(), buffer->size()); + if (renameFont(localBuffer.get(), fontName) && g_customFontCache->registerFont(fontName, localBuffer.get())) return new FontCustomPlatformData(fontName); } return 0; diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.h b/WebCore/platform/graphics/wince/FontCustomPlatformData.h index b1f64a0..89d1fdd 100644 --- a/WebCore/platform/graphics/wince/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.h @@ -32,7 +32,7 @@ namespace WebCore { class CustomFontCache { public: - virtual bool registerFont(const String& fontName, CachedFont*) = 0; + virtual bool registerFont(const String& fontName, const SharedBuffer*) = 0; virtual void unregisterFont(const String& fontName) = 0; }; @@ -48,8 +48,8 @@ namespace WebCore { String m_name; }; - FontCustomPlatformData* createFontCustomPlatformData(CachedFont*); - + FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer*); + void setCustomFontCache(CustomFontCache*); } #endif diff --git a/WebCore/platform/graphics/wince/GradientWince.cpp b/WebCore/platform/graphics/wince/GradientWince.cpp new file mode 100644 index 0000000..49fa970 --- /dev/null +++ b/WebCore/platform/graphics/wince/GradientWince.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#include "config.h" +#include "Gradient.h" + +#include "GraphicsContext.h" + +namespace WebCore { + +void Gradient::platformDestroy() +{ +} + +static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b) +{ + return a.stop < b.stop; +} + +const Vector<Gradient::ColorStop>& Gradient::getStops() const +{ + if (!m_stopsSorted) { + if (m_stops.size()) + std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); + m_stopsSorted = true; + } + return m_stops; +} + +void Gradient::fill(GraphicsContext* c, const FloatRect& r) +{ + c->fillRect(r, this); +} + +} diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp index c114c0e..f22e6c9 100644 --- a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp +++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp @@ -947,7 +947,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points } } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled() || !m_data->m_opacity) return; @@ -1051,12 +1051,12 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int wi notImplemented(); } -void GraphicsContext::setPlatformFillColor(const Color& col) +void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) { notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& col) +void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) { notImplemented(); } @@ -1088,7 +1088,7 @@ void GraphicsContext::clearRect(const FloatRect& rect) return; } - fillRect(rect, Color(Color::white)); + fillRect(rect, Color(Color::white), DeviceColorSpace); } void GraphicsContext::strokeRect(const FloatRect& rect, float width) @@ -1219,6 +1219,11 @@ void GraphicsContext::clip(const Path& path) notImplemented(); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipOut(const Path&) { notImplemented(); @@ -1233,7 +1238,7 @@ static inline IntPoint rectCenterPoint(const RECT& rect) { return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2); } -void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c) +void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c, ColorSpace colorSpace) { ScopeDCProvider dcProvider(m_data); if (!m_data->m_dc) @@ -1350,7 +1355,7 @@ Color gradientAverageColor(const Gradient* gradient) void GraphicsContext::fillPath() { - Color c = m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient + Color c = m_common->state.fillGradient ? gradientAverageColor(m_common->state.fillGradient.get()) : fillColor(); @@ -1444,7 +1449,7 @@ void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient) if (numStops == 1) { const Gradient::ColorStop& stop = stops.first(); Color color(stop.red, stop.green, stop.blue, stop.alpha); - fillRect(r, color); + fillRect(r, color, DeviceColorSpace); return; } @@ -1534,13 +1539,13 @@ void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) void GraphicsContext::fillRect(const FloatRect& rect) { - if (m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient) + if (m_common->state.fillGradient) fillRect(rect, m_common->state.fillGradient.get()); else - fillRect(rect, fillColor()); + fillRect(rect, fillColor(), DeviceColorSpace); } -void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&) +void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&, ColorSpace) { notImplemented(); } diff --git a/WebCore/platform/graphics/wince/ImageBufferData.h b/WebCore/platform/graphics/wince/ImageBufferData.h new file mode 100644 index 0000000..01b7d06 --- /dev/null +++ b/WebCore/platform/graphics/wince/ImageBufferData.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef ImageBufferData_h +#define ImageBufferData_h + +namespace WebCore { + + class IntSize; + class ImageBufferData { + public: + ImageBufferData(const IntSize& size); + RefPtr<SharedBitmap> m_bitmap; + }; + +} // namespace WebCore + +#endif // ImageBufferData_h diff --git a/WebCore/platform/graphics/wince/ImageBufferWince.cpp b/WebCore/platform/graphics/wince/ImageBufferWince.cpp new file mode 100644 index 0000000..3417f5f --- /dev/null +++ b/WebCore/platform/graphics/wince/ImageBufferWince.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "ImageBuffer.h" + +#include "Base64.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "ImageData.h" +#include "JPEGEncoder.h" +#include "PNGEncoder.h" +#include "SharedBitmap.h" + +namespace WebCore { + +class BufferedImage: public Image { + +public: + BufferedImage(const ImageBufferData* data) + : m_data(data) + { + } + + virtual IntSize size() const { return IntSize(m_data->m_bitmap->width(), m_data->m_bitmap->height()); } + virtual void destroyDecodedData(bool destroyAll = true) {} + virtual unsigned decodedSize() const { return 0; } + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, + const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + + const ImageBufferData* m_data; +}; + +void BufferedImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp) +{ + IntRect intDstRect = enclosingIntRect(dstRect); + IntRect intSrcRect(srcRect); + m_data->m_bitmap->draw(ctxt, intDstRect, intSrcRect, compositeOp); +} + +void BufferedImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const TransformationMatrix& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) +{ + m_data->m_bitmap->drawPattern(ctxt, tileRectIn, patternTransform, phase, op, destRect, size()); +} + +ImageBufferData::ImageBufferData(const IntSize& size) +: m_bitmap(SharedBitmap::createInstance(false, size.width(), size.height(), false)) +{ + // http://www.w3.org/TR/2009/WD-html5-20090212/the-canvas-element.html#canvaspixelarray + // "When the canvas is initialized it must be set to fully transparent black." + m_bitmap->resetPixels(true); + m_bitmap->setHasAlpha(true); +} + +ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace colorSpace, bool& success) + : m_data(size) + , m_size(size) +{ + // FIXME: colorSpace is not used + UNUSED_PARAM(colorSpace); + + m_context.set(new GraphicsContext(0)); + m_context->setBitmap(m_data.m_bitmap); + success = true; +} + +ImageBuffer::~ImageBuffer() +{ +} + +GraphicsContext* ImageBuffer::context() const +{ + return m_context.get(); +} + +Image* ImageBuffer::image() const +{ + if (!m_image) + m_image = adoptRef(new BufferedImage(&m_data)); + + return m_image.get(); +} + +template <bool premultiplied> PassRefPtr<ImageData> +static getImageData(const IntRect& rect, const SharedBitmap* bitmap) +{ + PassRefPtr<ImageData> imageData = ImageData::create(rect.width(), rect.height()); + + const unsigned char* src = static_cast<const unsigned char*>(bitmap->bytes()); + if (!src) + return imageData; + + IntRect sourceRect(0, 0, bitmap->width(), bitmap->height()); + sourceRect.intersect(rect); + if (sourceRect.isEmpty()) + return imageData; + + unsigned char* dst = imageData->data()->data()->data(); + memset(dst, 0, imageData->data()->data()->length()); + src += (sourceRect.y() * bitmap->width() + sourceRect.x()) * 4; + dst += ((sourceRect.y() - rect.y()) * imageData->width() + sourceRect.x() - rect.x()) * 4; + int bytesToCopy = sourceRect.width() * 4; + int srcSkip = (bitmap->width() - sourceRect.width()) * 4; + int dstSkip = (imageData->width() - sourceRect.width()) * 4; + const unsigned char* dstEnd = dst + sourceRect.height() * imageData->width() * 4; + while (dst < dstEnd) { + const unsigned char* dstRowEnd = dst + bytesToCopy; + while (dst < dstRowEnd) { + // Convert ARGB little endian to RGBA big endian + int blue = *src++; + int green = *src++; + int red = *src++; + int alpha = *src++; + if (premultiplied) { + *dst++ = static_cast<unsigned char>((red * alpha + 254) / 255); + *dst++ = static_cast<unsigned char>((green * alpha + 254) / 255); + *dst++ = static_cast<unsigned char>((blue * alpha + 254) / 255); + *dst++ = static_cast<unsigned char>(alpha); + } else { + *dst++ = static_cast<unsigned char>(red); + *dst++ = static_cast<unsigned char>(green); + *dst++ = static_cast<unsigned char>(blue); + *dst++ = static_cast<unsigned char>(alpha); + ++src; + } + } + src += srcSkip; + dst += dstSkip; + } + + return imageData; +} + +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData<false>(rect, m_data.m_bitmap.get()); +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<true>(rect, m_data.m_bitmap.get()); +} + +template <bool premultiplied> +static void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint, SharedBitmap* bitmap) +{ + unsigned char* dst = (unsigned char*)bitmap->bytes(); + if (!dst) + return; + + IntRect destRect(destPoint, sourceRect.size()); + destRect.intersect(IntRect(0, 0, bitmap->width(), bitmap->height())); + + if (destRect.isEmpty()) + return; + + const unsigned char* src = source->data()->data()->data(); + dst += (destRect.y() * bitmap->width() + destRect.x()) * 4; + src += (sourceRect.y() * source->width() + sourceRect.x()) * 4; + int bytesToCopy = destRect.width() * 4; + int dstSkip = (bitmap->width() - destRect.width()) * 4; + int srcSkip = (source->width() - destRect.width()) * 4; + const unsigned char* dstEnd = dst + destRect.height() * bitmap->width() * 4; + while (dst < dstEnd) { + const unsigned char* dstRowEnd = dst + bytesToCopy; + while (dst < dstRowEnd) { + // Convert RGBA big endian to ARGB little endian + int red = *src++; + int green = *src++; + int blue = *src++; + int alpha = *src++; + if (premultiplied) { + *dst++ = static_cast<unsigned char>(blue * 255 / alpha); + *dst++ = static_cast<unsigned char>(green * 255 / alpha); + *dst++ = static_cast<unsigned char>(red * 255 / alpha); + *dst++ = static_cast<unsigned char>(alpha); + } else { + *dst++ = static_cast<unsigned char>(blue); + *dst++ = static_cast<unsigned char>(green); + *dst++ = static_cast<unsigned char>(red); + *dst++ = static_cast<unsigned char>(alpha); + } + } + src += srcSkip; + dst += dstSkip; + } +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<false>(source, sourceRect, destPoint, m_data.m_bitmap.get()); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<true>(source, sourceRect, destPoint, m_data.m_bitmap.get()); +} + +String ImageBuffer::toDataURL(const String& mimeType) const +{ + if (!m_data.m_bitmap->bytes()) + return "data:,"; + + Vector<char> output; + const char* header; + if (mimeType.lower() == "image/png") { + if (!compressBitmapToPng(m_data.m_bitmap.get(), output)) + return "data:,"; + header = "data:image/png;base64,"; + } else { + if (!compressBitmapToJpeg(m_data.m_bitmap.get(), output)) + return "data:,"; + header = "data:image/jpeg;base64,"; + } + + Vector<char> base64; + base64Encode(output, base64); + + output.clear(); + + Vector<char> url; + url.append(header, strlen(header)); + url.append(base64); + + return String(url.data(), url.size()); +} + +} diff --git a/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h b/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h new file mode 100644 index 0000000..2d6c358 --- /dev/null +++ b/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaPlayerPrivateWince_h +#define MediaPlayerPrivateWince_h + +#if ENABLE(VIDEO) + +#include "MediaPlayerPrivate.h" +#include "Timer.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + + class GraphicsContext; + class IntSize; + class IntRect; + class String; + + class MediaPlayerPrivate : public MediaPlayerPrivateInterface { + public: + static void registerMediaEngine(MediaEngineRegistrar); + + ~MediaPlayerPrivate(); + + IntSize naturalSize() const; + bool hasVideo() const; + + void load(const String& url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float time); + void setEndTime(float); + + void setRate(float); + void setVolume(float); + + int dataRate() const; + + MediaPlayer::NetworkState networkState() const { return m_networkState; } + MediaPlayer::ReadyState readyState() const { return m_readyState; } + + PassRefPtr<TimeRanges> buffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + bool totalBytesKnown() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setSize(const IntSize&); + + void loadStateChanged(); + void didEnd(); + + void paint(GraphicsContext*, const IntRect&); + + private: + MediaPlayerPrivate(MediaPlayer*); + + void updateStates(); + void doSeek(); + void cancelSeek(); + void seekTimerFired(Timer<MediaPlayerPrivate>*); + float maxTimeLoaded() const; + void sawUnsupportedTracks(); +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + void setMediaPlayerProxy(WebMediaPlayerProxy*); + void setPoster(const String& url); + void deliverNotification(MediaPlayerProxyNotificationType); +#endif + + // engine support + static MediaPlayerPrivateInterface* create(MediaPlayer*); + static void getSupportedTypes(HashSet<String>& types); + static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); + static bool isAvailable(); + + MediaPlayer* m_player; + float m_seekTo; + float m_endTime; + Timer<MediaPlayerPrivate> m_seekTimer; + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + unsigned m_enabledTrackCount; + unsigned m_totalTrackCount; + bool m_hasUnsupportedTracks; + bool m_startedPlaying; + bool m_isStreaming; +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + WebMediaPlayerProxy* m_proxy; +#endif + }; + +} + +#endif + +#endif diff --git a/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp b/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp new file mode 100644 index 0000000..ceb5a7c --- /dev/null +++ b/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#if ENABLE(VIDEO) + +#include "config.h" +#include "MediaPlayerProxy.h" + +#include "Bridge.h" +#include "DocumentLoader.h" +#include "HTMLPlugInElement.h" +#include "HTMLVideoElement.h" +#include "JSDOMBinding.h" +#include "JSPluginElementFunctions.h" +#include "MediaPlayer.h" +#include "Node.h" +#include "PlatformString.h" +#include "PluginView.h" +#include "RenderPartObject.h" +#include "RenderWidget.h" +#include "Widget.h" +#include "c_class.h" +#include "c_instance.h" +#include "c_runtime.h" +#include "npruntime_impl.h" +#include <runtime/Identifier.h> + +using namespace JSC; + +namespace WebCore { + +using namespace Bindings; +using namespace HTMLNames; + +WebMediaPlayerProxy::WebMediaPlayerProxy(MediaPlayer* player) + : m_mediaPlayer(player) + , m_init(false) + , m_hasSentResponseToPlugin(false) +{ + if (!m_init) + initEngine(); +} + +WebMediaPlayerProxy::~WebMediaPlayerProxy() +{ + m_instance.release(); +} + +ScriptInstance WebMediaPlayerProxy::pluginInstance() +{ + if (!m_instance) { + RenderObject* r = element()->renderer(); + if (!r || !r->isWidget()) + return 0; + + Frame* frame = element()->document()->frame(); + + RenderWidget* renderWidget = static_cast<RenderWidget*>(element()->renderer()); + if (renderWidget && renderWidget->widget()) + m_instance = frame->script()->createScriptInstanceForWidget(renderWidget->widget()); + } + + return m_instance; +} + +void WebMediaPlayerProxy::load(const String& url) +{ + if (!m_init) + initEngine(); + if (m_init) + invokeMethod("play"); +} + +void WebMediaPlayerProxy::initEngine() +{ + HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_mediaPlayer->mediaPlayerClient()); + String url = element->initialURL(); + + if (url.isEmpty()) + return; + + Frame* frame = element->document()->frame(); + Vector<String> paramNames; + Vector<String> paramValues; + String serviceType; + + // add all attributes set on the embed object + if (NamedNodeMap* attributes = element->attributes()) { + for (unsigned i = 0; i < attributes->length(); ++i) { + Attribute* it = attributes->attributeItem(i); + paramNames.append(it->name().localName().string()); + paramValues.append(it->value().string()); + } + } + serviceType = "application/x-mplayer2"; + frame->loader()->requestObject(static_cast<RenderPartObject*>(element->renderer()), url, nullAtom, serviceType, paramNames, paramValues); + m_init = true; + +} + +HTMLMediaElement* WebMediaPlayerProxy::element() +{ + return static_cast<HTMLMediaElement*>(m_mediaPlayer->mediaPlayerClient()); + +} + +void WebMediaPlayerProxy::invokeMethod(const String& methodName) +{ + Frame* frame = element()->document()->frame(); + RootObject *root = frame->script()->bindingRootObject(); + if (!root) + return; + ExecState *exec = root->globalObject()->globalExec(); + Instance* instance = pluginInstance().get(); + if (!instance) + return; + + instance->begin(); + Class *aClass = instance->getClass(); + Identifier iden(exec, methodName); + MethodList methodList = aClass->methodsNamed(iden, instance); + ArgList args; + instance->invokeMethod(exec, methodList , args); + instance->end(); +} + +} + +#endif diff --git a/WebCore/platform/graphics/wince/MediaPlayerProxy.h b/WebCore/platform/graphics/wince/MediaPlayerProxy.h new file mode 100644 index 0000000..05f9b21 --- /dev/null +++ b/WebCore/platform/graphics/wince/MediaPlayerProxy.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef MediaPlayerProxy_h +#define MediaPlayerProxy_h + +#if ENABLE(VIDEO) + +#include "ScriptInstance.h" + +namespace WebCore { + + class IntRect; + class IntSize; + class String; + class MediaPlayer; + class PluginView; + class HTMLMediaElement; + + enum MediaPlayerProxyNotificationType { + MediaPlayerNotificationPlayPauseButtonPressed, + Idle, + Loading, + Loaded, + FormatError, + NetworkError, + DecodeError + }; + + class WebMediaPlayerProxy { + public: + WebMediaPlayerProxy(MediaPlayer* player); + ~WebMediaPlayerProxy(); + + MediaPlayer* mediaPlayer() {return m_mediaPlayer;} + void initEngine(); + void load(const String& url); + HTMLMediaElement* element(); + void invokeMethod(const String& methodName); + ScriptInstance pluginInstance(); + + private: + MediaPlayer* m_mediaPlayer; + bool m_init; + WebCore::PluginView* m_pluginView; + bool m_hasSentResponseToPlugin; + ScriptInstance m_instance; + }; + +} +#endif // ENABLE(VIDEO) + +#endif diff --git a/WebCore/platform/graphics/wince/PathWince.cpp b/WebCore/platform/graphics/wince/PathWince.cpp new file mode 100644 index 0000000..7589ccb --- /dev/null +++ b/WebCore/platform/graphics/wince/PathWince.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Path.h" + +#include "FloatRect.h" +#include "NotImplemented.h" +#include "PlatformPathWince.h" +#include "PlatformString.h" +#include "TransformationMatrix.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +Path::Path() + : m_path(new PlatformPath()) +{ +} + +Path::Path(const Path& other) + : m_path(new PlatformPath(*other.m_path)) +{ +} + +Path::~Path() +{ + delete m_path; +} + +Path& Path::operator=(const Path& other) +{ + if (&other != this) { + delete m_path; + m_path = new PlatformPath(*other.m_path); + } + return *this; +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + return m_path->contains(point, rule); +} + +void Path::translate(const FloatSize& size) +{ + m_path->translate(size); +} + +FloatRect Path::boundingRect() const +{ + return m_path->boundingRect(); +} + +void Path::moveTo(const FloatPoint& point) +{ + m_path->moveTo(point); +} + +void Path::addLineTo(const FloatPoint& point) +{ + m_path->addLineTo(point); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + m_path->addQuadCurveTo(cp, p); +} + +void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + m_path->addBezierCurveTo(cp1, cp2, p); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + m_path->addArcTo(p1, p2, radius); +} + +void Path::closeSubpath() +{ + m_path->closeSubpath(); +} + +void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise) +{ + m_path->addEllipse(p, r, r, sar, ear, anticlockwise); +} + +void Path::addRect(const FloatRect& r) +{ + m_path->addRect(r); +} + +void Path::addEllipse(const FloatRect& r) +{ + m_path->addEllipse(r); +} + +void Path::clear() +{ + m_path->clear(); +} + +bool Path::isEmpty() const +{ + return m_path->isEmpty(); +} + +String Path::debugString() const +{ + return m_path->debugString(); +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + m_path->apply(info, function); +} + +void Path::transform(const TransformationMatrix& t) +{ + m_path->transform(t); +} + +FloatRect Path::strokeBoundingRect(StrokeStyleApplier *) +{ + notImplemented(); + return FloatRect(); +} + +bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const +{ + notImplemented(); + return false; +} + +bool Path::hasCurrentPoint() const +{ + // Not sure if this is correct. At the meantime, we do what other ports + // do. + // See https://bugs.webkit.org/show_bug.cgi?id=27266, + // https://bugs.webkit.org/show_bug.cgi?id=27187, and + // http://trac.webkit.org/changeset/45873 + return !isEmpty(); +} + +} diff --git a/WebCore/platform/graphics/wince/PlatformPathWince.cpp b/WebCore/platform/graphics/wince/PlatformPathWince.cpp new file mode 100644 index 0000000..66fad50 --- /dev/null +++ b/WebCore/platform/graphics/wince/PlatformPathWince.cpp @@ -0,0 +1,810 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "PlatformPathWince.h" + +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "Path.h" +#include "PlatformString.h" +#include "TransformationMatrix.h" +#include "WinceGraphicsExtras.h" +#include <wtf/MathExtras.h> +#include <wtf/OwnPtr.h> + +#include <windows.h> + +namespace WebCore { + +// Implemented in GraphicsContextWince.cpp +void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y); + +static void quadCurve(int segments, Vector<PathPoint>& pts, const PathPoint* control) +{ + const float step = 1.0 / segments; + register float tA = 0.0; + register float tB = 1.0; + + float c1x = control[0].x(); + float c1y = control[0].y(); + float c2x = control[1].x(); + float c2y = control[1].y(); + float c3x = control[2].x(); + float c3y = control[2].y(); + + const int offset = pts.size(); + pts.resize(offset + segments); + PathPoint pp; + pp.m_x = c1x; + pp.m_y = c1y; + + for (int i = 1; i < segments; ++i) { + tA += step; + tB -= step; + + const float a = tB * tB; + const float b = 2.0 * tA * tB; + const float c = tA * tA; + + pp.m_x = c1x * a + c2x * b + c3x * c; + pp.m_y = c1y * a + c2y * b + c3y * c; + + pts[offset + i - 1] = pp; + } + + pp.m_x = c3x; + pp.m_y = c3y; + pts[offset + segments - 1] = pp; +} + +static inline void bezier(int segments, Vector<PathPoint>& pts, const PathPoint* control) +{ + const float step = 1.0 / segments; + register float tA = 0.0; + register float tB = 1.0; + + float c1x = control[0].x(); + float c1y = control[0].y(); + float c2x = control[1].x(); + float c2y = control[1].y(); + float c3x = control[2].x(); + float c3y = control[2].y(); + float c4x = control[3].x(); + float c4y = control[3].y(); + + const int offset = pts.size(); + pts.resize(offset + segments); + PathPoint pp; + pp.m_x = c1x; + pp.m_y = c1y; + + for (int i = 1; i < segments; ++i) { + tA += step; + tB -= step; + const float tAsq = tA * tA; + const float tBsq = tB * tB; + + const float a = tBsq * tB; + const float b = 3.0 * tA * tBsq; + const float c = 3.0 * tB * tAsq; + const float d = tAsq * tA; + + pp.m_x = c1x * a + c2x * b + c3x * c + c4x * d; + pp.m_y = c1y * a + c2y * b + c3y * c + c4y * d; + + pts[offset + i - 1] = pp; + } + + pp.m_x = c4x; + pp.m_y = c4y; + pts[offset + segments - 1] = pp; +} + +static bool containsPoint(const FloatRect& r, const FloatPoint& p) +{ + return p.x() >= r.x() && p.y() >= r.y() && p.x() < r.right() && p.y() < r.bottom(); +} + +static void normalizeAngle(float& angle) +{ + angle = fmod(angle, 2 * piFloat); + if (angle < 0) + angle += 2 * piFloat; + if (angle < 0.00001f) + angle = 0; +} + +static void transformArcPoint(float& x, float& y, const FloatPoint& c) +{ + x += c.x(); + y += c.y(); +} + +static void inflateRectToContainPoint(FloatRect& r, float x, float y) +{ + if (r.isEmpty()) { + r.setX(x); + r.setY(y); + r.setSize(FloatSize(1, 1)); + return; + } + if (x < r.x()) { + r.setWidth(r.right() - x); + r.setX(x); + } else { + float w = x - r.x() + 1; + if (w > r.width()) + r.setWidth(w); + } + if (y < r.y()) { + r.setHeight(r.bottom() - y); + r.setY(y); + } else { + float h = y - r.y() + 1; + if (h > r.height()) + r.setHeight(h); + } +} + +// return 0-based value: 0 - first Quadrant ( 0 - 90 degree) +static inline int quadrant(const PathPoint& point, const PathPoint& origin) +{ + return point.m_x < origin.m_x ? + (point.m_y < origin.m_y ? 2 : 1) + : (point.m_y < origin.m_y ? 3 : 0); +} + +static inline bool isQuadrantOnLeft(int q) { return q == 1 || q == 2; } +static inline bool isQuadrantOnRight(int q) { return q == 0 || q == 3; } +static inline bool isQuadrantOnTop(int q) { return q == 2 || q == 3; } +static inline bool isQuadrantOnBottom(int q) { return q == 0 || q == 1; } + +static inline int nextQuadrant(int q) { return q == 3 ? 0 : q + 1; } +static inline int quadrantDiff(int q1, int q2) +{ + int d = q1 - q2; + while (d < 0) + d += 4; + return d; +} + +struct PathVector { + float m_x; + float m_y; + + PathVector() : m_x(0), m_y(0) {} + PathVector(float x, float y) : m_x(x), m_y(y) {} + double angle() const { return atan2(m_y, m_x); } + operator double () const { return angle(); } + double length() const { return _hypot(m_x, m_y); } +}; + +PathVector operator-(const PathPoint& p1, const PathPoint& p2) +{ + return PathVector(p1.m_x - p2.m_x, p1.m_y - p2.m_y); +} + +static void addArcPoint(PathPolygon& poly, const PathPoint& center, const PathPoint& radius, double angle) +{ + PathPoint p; + getEllipsePointByAngle(angle, radius.m_x, radius.m_y, p.m_x, p.m_y); + transformArcPoint(p.m_x, p.m_y, center); + if (poly.isEmpty() || poly.last() != p) + poly.append(p); +} + +static void addArcPoints(PathPolygon& poly, const PlatformPathElement::ArcTo& data) +{ + const PathPoint& startPoint = poly.last(); + double curAngle = startPoint - data.m_center; + double endAngle = data.m_end - data.m_center; + double angleStep = 2. / std::max(data.m_radius.m_x, data.m_radius.m_y); + if (data.m_clockwise) { + if (endAngle <= curAngle || startPoint == data.m_end) + endAngle += 2 * piDouble; + } else { + angleStep = -angleStep; + if (endAngle >= curAngle || startPoint == data.m_end) + endAngle -= 2 * piDouble; + } + + for (curAngle += angleStep; data.m_clockwise ? curAngle < endAngle : curAngle > endAngle; curAngle += angleStep) + addArcPoint(poly, data.m_center, data.m_radius, curAngle); + + if (poly.isEmpty() || poly.last() != data.m_end) + poly.append(data.m_end); +} + +static void drawPolygons(HDC dc, const Vector<PathPolygon>& polygons, bool fill, const TransformationMatrix* transformation) +{ + MemoryAllocationCanFail canFail; + for (Vector<PathPolygon>::const_iterator i = polygons.begin(); i != polygons.end(); ++i) { + int npoints = i->size(); + if (!npoints) + continue; + + POINT* winPoints = 0; + if (fill) { + if (npoints > 2) + winPoints = new POINT[npoints + 1]; + } else + winPoints = new POINT[npoints]; + + if (winPoints) { + if (transformation) { + for (int i2 = 0; i2 < npoints; ++i2) { + FloatPoint trPoint = transformation->mapPoint(i->at(i2)); + winPoints[i2].x = stableRound(trPoint.x()); + winPoints[i2].y = stableRound(trPoint.y()); + } + } else { + for (int i2 = 0; i2 < npoints; ++i2) { + winPoints[i2].x = stableRound(i->at(i2).x()); + winPoints[i2].y = stableRound(i->at(i2).y()); + } + } + + if (fill && winPoints[npoints - 1] != winPoints[0]) { + winPoints[npoints].x = winPoints[0].x; + winPoints[npoints].y = winPoints[0].y; + ++npoints; + } + + if (fill) + ::Polygon(dc, winPoints, npoints); + else + ::Polyline(dc, winPoints, npoints); + delete[] winPoints; + } + } +} + + +int PlatformPathElement::numControlPoints() const +{ + switch (m_type) { + case PathMoveTo: + case PathLineTo: + return 1; + case PathQuadCurveTo: + case PathArcTo: + return 2; + case PathBezierCurveTo: + return 3; + default: + ASSERT(m_type == PathCloseSubpath); + return 0; + } +} + +int PlatformPathElement::numPoints() const +{ + switch (m_type) { + case PathMoveTo: + case PathLineTo: + case PathArcTo: + return 1; + case PathQuadCurveTo: + return 2; + case PathBezierCurveTo: + return 3; + default: + ASSERT(m_type == PathCloseSubpath); + return 0; + } +} + +void PathPolygon::move(const FloatSize& offset) +{ + for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i) + i->move(offset); +} + +void PathPolygon::transform(const TransformationMatrix& t) +{ + for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i) + *i = t.mapPoint(*i); +} + +bool PathPolygon::contains(const FloatPoint& point) const +{ + if (size() < 3) + return false; + + // Test intersections between the polygon and the vertical line: x = point.x() + + int intersected = 0; + const PathPoint* point1 = &last(); + Vector<PathPoint>::const_iterator last = end(); + // wasNegative: -1 means unknown, 0 means false, 1 means true. + int wasNegative = -1; + for (Vector<PathPoint>::const_iterator i = begin(); i != last; ++i) { + const PathPoint& point2 = *i; + if (point1->x() != point.x()) { + if (point2.x() == point.x()) { + // We are getting on the vertical line + wasNegative = point1->x() < point.x() ? 1 : 0; + } else if (point2.x() < point.x() != point1->x() < point.x()) { + float y = (point2.y() - point1->y()) / (point2.x() - point1->x()) * (point.x() - point1->x()) + point1->y(); + if (y >= point.y()) + ++intersected; + } + } else { + // We were on the vertical line + + // handle special case + if (point1->y() == point.y()) + return true; + + if (point1->y() > point.y()) { + if (point2.x() == point.x()) { + // see if the point is on this segment + if (point2.y() <= point.y()) + return true; + + // We are still on the line + } else { + // We are leaving the line now. + // We have to get back to see which side we come from. If we come from + // the same side we are leaving, no intersection should be counted + if (wasNegative < 0) { + Vector<PathPoint>::const_iterator jLast = i; + Vector<PathPoint>::const_iterator j = i; + do { + if (j == begin()) + j = last; + else + --j; + if (j->x() != point.x()) { + if (j->x() > point.x()) + wasNegative = 0; + else + wasNegative = 1; + break; + } + } while (j != jLast); + + if (wasNegative < 0) + return false; + } + if (wasNegative ? point2.x() > point.x() : point2.x() < point.x()) + ++intersected; + } + } else if (point2.x() == point.x() && point2.y() >= point.y()) + return true; + } + point1 = &point2; + } + + return intersected & 1; +} + +void PlatformPathElement::move(const FloatSize& offset) +{ + int n = numControlPoints(); + for (int i = 0; i < n; ++i) + m_data.m_points[i].move(offset); +} + +void PlatformPathElement::transform(const TransformationMatrix& t) +{ + int n = numControlPoints(); + for (int i = 0; i < n; ++i) { + FloatPoint p = t.mapPoint(m_data.m_points[i]); + m_data.m_points[i].set(p.x(), p.y()); + } +} + +void PlatformPathElement::inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const +{ + if (m_type == PathArcTo) { + const ArcTo& data = m_data.m_arcToData; + PathPoint startPoint; + startPoint = lastPoint; + PathPoint endPoint = data.m_end; + if (!data.m_clockwise) + std::swap(startPoint, endPoint); + + int q0 = quadrant(startPoint, data.m_center); + int q1 = quadrant(endPoint, data.m_center); + bool containsExtremes[4] = { false }; // bottom, left, top, right + static const PathPoint extremeVectors[4] = { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } }; + if (q0 == q1) { + if (startPoint.m_x == endPoint.m_x || isQuadrantOnBottom(q0) != startPoint.m_x > endPoint.m_x) { + for (int i = 0; i < 4; ++i) + containsExtremes[i] = true; + } + } else { + int extreme = q0; + int diff = quadrantDiff(q1, q0); + for (int i = 0; i < diff; ++i) { + containsExtremes[extreme] = true; + extreme = nextQuadrant(extreme); + } + } + + inflateRectToContainPoint(r, startPoint.m_x, startPoint.m_y); + inflateRectToContainPoint(r, endPoint.m_x, endPoint.m_y); + for (int i = 0; i < 4; ++i) { + if (containsExtremes[i]) + inflateRectToContainPoint(r, data.m_center.m_x + data.m_radius.m_x * extremeVectors[i].m_x, data.m_center.m_y + data.m_radius.m_y * extremeVectors[i].m_y); + } + } else { + int n = numPoints(); + for (int i = 0; i < n; ++i) + inflateRectToContainPoint(r, m_data.m_points[i].m_x, m_data.m_points[i].m_y); + } +} + +PathElementType PlatformPathElement::type() const +{ + switch (m_type) { + case PathMoveTo: + return PathElementMoveToPoint; + case PathLineTo: + return PathElementAddLineToPoint; + case PathArcTo: + // FIXME: there's no arcTo type for PathElement + return PathElementAddLineToPoint; + // return PathElementAddQuadCurveToPoint; + case PathQuadCurveTo: + return PathElementAddQuadCurveToPoint; + case PathBezierCurveTo: + return PathElementAddCurveToPoint; + default: + ASSERT(m_type == PathCloseSubpath); + return PathElementCloseSubpath; + } +} + +PlatformPath::PlatformPath() + : m_penLifted(true) +{ + m_currentPoint.clear(); +} + +void PlatformPath::ensureSubpath() +{ + if (m_penLifted) { + m_penLifted = false; + m_subpaths.append(PathPolygon()); + m_subpaths.last().append(m_currentPoint); + } else + ASSERT(!m_subpaths.isEmpty()); +} + +void PlatformPath::addToSubpath(const PlatformPathElement& e) +{ + if (e.platformType() == PlatformPathElement::PathMoveTo) { + m_penLifted = true; + m_currentPoint = e.pointAt(0); + } else if (e.platformType() == PlatformPathElement::PathCloseSubpath) { + m_penLifted = true; + if (!m_subpaths.isEmpty()) { + if (m_currentPoint != m_subpaths.last()[0]) { + // According to W3C, we have to draw a line from current point to the initial point + m_subpaths.last().append(m_subpaths.last()[0]); + m_currentPoint = m_subpaths.last()[0]; + } + } else + m_currentPoint.clear(); + } else { + ensureSubpath(); + switch (e.platformType()) { + case PlatformPathElement::PathLineTo: + m_subpaths.last().append(e.pointAt(0)); + break; + case PlatformPathElement::PathArcTo: + addArcPoints(m_subpaths.last(), e.arcTo()); + break; + case PlatformPathElement::PathQuadCurveTo: + { + PathPoint control[] = { + m_currentPoint, + e.pointAt(0), + e.pointAt(1), + }; + // FIXME: magic number? + quadCurve(50, m_subpaths.last(), control); + } + break; + case PlatformPathElement::PathBezierCurveTo: + { + PathPoint control[] = { + m_currentPoint, + e.pointAt(0), + e.pointAt(1), + e.pointAt(2), + }; + // FIXME: magic number? + bezier(100, m_subpaths.last(), control); + } + break; + default: + ASSERT_NOT_REACHED(); + break; + } + m_currentPoint = m_subpaths.last().last(); + } +} + +void PlatformPath::append(const PlatformPathElement& e) +{ + e.inflateRectToContainMe(m_boundingRect, lastPoint()); + addToSubpath(e); + m_elements.append(e); +} + +void PlatformPath::append(const PlatformPath& p) +{ + const PlatformPathElements& e = p.elements(); + for (PlatformPathElements::const_iterator it(e.begin()); it != e.end(); ++it) { + addToSubpath(*it); + it->inflateRectToContainMe(m_boundingRect, lastPoint()); + m_elements.append(*it); + } +} + +void PlatformPath::clear() +{ + m_elements.clear(); + m_boundingRect = FloatRect(); + m_subpaths.clear(); + m_currentPoint.clear(); + m_penLifted = true; +} + +void PlatformPath::strokePath(HDC dc, const TransformationMatrix* transformation) const +{ + drawPolygons(dc, m_subpaths, false, transformation); +} + +void PlatformPath::fillPath(HDC dc, const TransformationMatrix* transformation) const +{ + HGDIOBJ oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); + drawPolygons(dc, m_subpaths, true, transformation); + SelectObject(dc, oldPen); +} + +void PlatformPath::translate(const FloatSize& size) +{ + for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) + it->move(size); + + m_boundingRect.move(size); + for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) + it->move(size); +} + +void PlatformPath::transform(const TransformationMatrix& t) +{ + for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) + it->transform(t); + + m_boundingRect = t.mapRect(m_boundingRect); + for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) + it->transform(t); +} + +bool PlatformPath::contains(const FloatPoint& point, WindRule rule) const +{ + // optimization: check the bounding rect first + if (!containsPoint(m_boundingRect, point)) + return false; + + for (Vector<PathPolygon>::const_iterator i = m_subpaths.begin(); i != m_subpaths.end(); ++i) { + if (i->contains(point)) + return true; + } + + return false; +} + +void PlatformPath::moveTo(const FloatPoint& point) +{ + PlatformPathElement::MoveTo data = { { point.x(), point.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addLineTo(const FloatPoint& point) +{ + PlatformPathElement::LineTo data = { { point.x(), point.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + PlatformPathElement::QuadCurveTo data = { { cp.x(), cp.y() }, { p.x(), p.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + PlatformPathElement::BezierCurveTo data = { { cp1.x(), cp1.y() }, { cp2.x(), cp2.y() }, { p.x(), p.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addArcTo(const FloatPoint& fp1, const FloatPoint& fp2, float radius) +{ + const PathPoint& p0 = m_currentPoint; + PathPoint p1; + p1 = fp1; + PathPoint p2; + p2 = fp2; + if (!radius || p0 == p1 || p1 == p2) { + addLineTo(p1); + return; + } + + PathVector v01 = p0 - p1; + PathVector v21 = p2 - p1; + + // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A) + double cross = v01.m_x * v21.m_y - v01.m_y * v21.m_x; + + if (fabs(cross) < 1E-10) { + // on one line + addLineTo(p1); + return; + } + + double d01 = v01.length(); + double d21 = v21.length(); + double angle = (piDouble - abs(asin(cross / (d01 * d21)))) * 0.5; + double span = radius * tan(angle); + double rate = span / d01; + PathPoint startPoint; + startPoint.m_x = p1.m_x + v01.m_x * rate; + startPoint.m_y = p1.m_y + v01.m_y * rate; + + addLineTo(startPoint); + + PathPoint endPoint; + rate = span / d21; + endPoint.m_x = p1.m_x + v21.m_x * rate; + endPoint.m_y = p1.m_y + v21.m_y * rate; + + PathPoint midPoint; + midPoint.m_x = (startPoint.m_x + endPoint.m_x) * 0.5; + midPoint.m_y = (startPoint.m_y + endPoint.m_y) * 0.5; + + PathVector vm1 = midPoint - p1; + double dm1 = vm1.length(); + double d = _hypot(radius, span); + + PathPoint centerPoint; + rate = d / dm1; + centerPoint.m_x = p1.m_x + vm1.m_x * rate; + centerPoint.m_y = p1.m_y + vm1.m_y * rate; + + PlatformPathElement::ArcTo data = { + endPoint, + centerPoint, + { radius, radius }, + cross < 0 + }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::closeSubpath() +{ + PlatformPathElement pe; + append(pe); +} + +// add a circular arc centred at p with radius r from start angle sar (radians) to end angle ear +void PlatformPath::addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise) +{ + float startX, startY, endX, endY; + + normalizeAngle(sar); + normalizeAngle(ear); + + getEllipsePointByAngle(sar, a, b, startX, startY); + getEllipsePointByAngle(ear, a, b, endX, endY); + + transformArcPoint(startX, startY, p); + transformArcPoint(endX, endY, p); + + FloatPoint start(startX, startY); + moveTo(start); + + PlatformPathElement::ArcTo data = { { endX, endY }, { p.x(), p.y() }, { a, b }, !anticlockwise }; + PlatformPathElement pe(data); + append(pe); +} + + +void PlatformPath::addRect(const FloatRect& r) +{ + moveTo(r.location()); + + float right = r.right() - 1; + float bottom = r.bottom() - 1; + addLineTo(FloatPoint(right, r.y())); + addLineTo(FloatPoint(right, bottom)); + addLineTo(FloatPoint(r.x(), bottom)); + addLineTo(r.location()); +} + +void PlatformPath::addEllipse(const FloatRect& r) +{ + FloatSize radius(r.width() * 0.5, r.height() * 0.5); + addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true); +} + +String PlatformPath::debugString() const +{ + String ret; + for (PlatformPathElements::const_iterator i(m_elements.begin()); i != m_elements.end(); ++i) { + switch (i->platformType()) { + case PlatformPathElement::PathMoveTo: + case PlatformPathElement::PathLineTo: + ret += String::format("M %f %f\n", i->pointAt(0).m_x, i->pointAt(0).m_y); + break; + case PlatformPathElement::PathArcTo: + ret += String::format("A %f %f %f %f %f %f %c\n" + , i->arcTo().m_end.m_x, i->arcTo().m_end.m_y + , i->arcTo().m_center.m_x, i->arcTo().m_center.m_y + , i->arcTo().m_radius.m_x, i->arcTo().m_radius.m_y + , i->arcTo().m_clockwise? 'Y' : 'N'); + break; + case PlatformPathElement::PathQuadCurveTo: + ret += String::format("Q %f %f %f %f\n" + , i->pointAt(0).m_x, i->pointAt(0).m_y + , i->pointAt(1).m_x, i->pointAt(1).m_y); + break; + case PlatformPathElement::PathBezierCurveTo: + ret += String::format("B %f %f %f %f %f %f\n" + , i->pointAt(0).m_x, i->pointAt(0).m_y + , i->pointAt(1).m_x, i->pointAt(1).m_y + , i->pointAt(2).m_x, i->pointAt(2).m_y); + break; + default: + ASSERT(i->platformType() == PlatformPathElement::PathCloseSubpath); + ret += "S\n"; + break; + } + } + + return ret; +} + +void PlatformPath::apply(void* info, PathApplierFunction function) const +{ + PathElement pelement; + FloatPoint points[3]; + pelement.points = points; + + for (PlatformPathElements::const_iterator it(m_elements.begin()); it != m_elements.end(); ++it) { + pelement.type = it->type(); + int n = it->numPoints(); + for (int i = 0; i < n; ++i) + points[i] = it->pointAt(i); + function(info, &pelement); + } +} + +} // namespace Webcore diff --git a/WebCore/platform/graphics/wince/PlatformPathWince.h b/WebCore/platform/graphics/wince/PlatformPathWince.h new file mode 100644 index 0000000..fca00a7 --- /dev/null +++ b/WebCore/platform/graphics/wince/PlatformPathWince.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PlatformPathWince_h +#define PlatformPathWince_h + +namespace WebCore { + + class GraphicsContext; + + struct PathPoint { + float m_x; + float m_y; + const float& x() const { return m_x; } + const float& y() const { return m_y; } + void set(float x, float y) + { + m_x = x; + m_y = y; + }; + operator FloatPoint() const { return FloatPoint(m_x, m_y); } + void move(const FloatSize& offset) + { + m_x += offset.width(); + m_y += offset.height(); + } + PathPoint& operator=(const FloatPoint& p) + { + m_x = p.x(); + m_y = p.y(); + return *this; + } + void clear() { m_x = m_y = 0; } + }; + + struct PathPolygon: public Vector<PathPoint> { + void move(const FloatSize& offset); + void transform(const TransformationMatrix& t); + bool contains(const FloatPoint& point) const; + }; + + class PlatformPathElement { + public: + enum PlaformPathElementType { + PathMoveTo, + PathLineTo, + PathArcTo, + PathQuadCurveTo, + PathBezierCurveTo, + PathCloseSubpath, + }; + + struct MoveTo { + PathPoint m_end; + }; + + struct LineTo { + PathPoint m_end; + }; + + struct ArcTo { + PathPoint m_end; + PathPoint m_center; + PathPoint m_radius; + bool m_clockwise; + }; + + struct QuadCurveTo { + PathPoint m_point0; + PathPoint m_point1; + }; + + struct BezierCurveTo { + PathPoint m_point0; + PathPoint m_point1; + PathPoint m_point2; + }; + + PlatformPathElement(): m_type(PathCloseSubpath) { m_data.m_points[0].set(0, 0); } + PlatformPathElement(const MoveTo& data): m_type(PathMoveTo) { m_data.m_moveToData = data; } + PlatformPathElement(const LineTo& data): m_type(PathLineTo) { m_data.m_lineToData = data; } + PlatformPathElement(const ArcTo& data): m_type(PathArcTo) { m_data.m_arcToData = data; } + PlatformPathElement(const QuadCurveTo& data): m_type(PathQuadCurveTo) { m_data.m_quadCurveToData = data; } + PlatformPathElement(const BezierCurveTo& data): m_type(PathBezierCurveTo) { m_data.m_bezierCurveToData = data; } + + const MoveTo& moveTo() const { return m_data.m_moveToData; } + const LineTo& lineTo() const { return m_data.m_lineToData; } + const ArcTo& arcTo() const { return m_data.m_arcToData; } + const QuadCurveTo& quadCurveTo() const { return m_data.m_quadCurveToData; } + const BezierCurveTo& bezierCurveTo() const { return m_data.m_bezierCurveToData; } + const PathPoint& lastPoint() const + { + int n = numPoints(); + return n > 1 ? m_data.m_points[n - 1] : m_data.m_points[0]; + } + const PathPoint& pointAt(int index) const { return m_data.m_points[index]; } + int numPoints() const; + int numControlPoints() const; + void move(const FloatSize& offset); + void transform(const TransformationMatrix& t); + PathElementType type() const; + PlaformPathElementType platformType() const { return m_type; } + void inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const; + + private: + PlaformPathElementType m_type; + union { + MoveTo m_moveToData; + LineTo m_lineToData; + ArcTo m_arcToData; + QuadCurveTo m_quadCurveToData; + BezierCurveTo m_bezierCurveToData; + PathPoint m_points[4]; + } m_data; + }; + + typedef Vector<PlatformPathElement> PlatformPathElements; + + class PlatformPath { + public: + PlatformPath(); + const PlatformPathElements& elements() const { return m_elements; } + void append(const PlatformPathElement& e); + void append(const PlatformPath& p); + void clear(); + bool isEmpty() const { return m_elements.isEmpty(); } + + void strokePath(HDC, const TransformationMatrix* tr) const; + void fillPath(HDC, const TransformationMatrix* tr) const; + FloatPoint lastPoint() const { return m_elements.isEmpty() ? FloatPoint(0, 0) : m_elements.last().lastPoint(); } + + const FloatRect& boundingRect() const { return m_boundingRect; } + bool contains(const FloatPoint& point, WindRule rule) const; + void translate(const FloatSize& size); + void transform(const TransformationMatrix& t); + + void moveTo(const FloatPoint&); + void addLineTo(const FloatPoint&); + void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point); + void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint&); + void addArcTo(const FloatPoint&, const FloatPoint&, float radius); + void closeSubpath(); + void addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise); + void addRect(const FloatRect& r); + void addEllipse(const FloatRect& r); + String debugString() const; + void apply(void* info, PathApplierFunction function) const; + + private: + void ensureSubpath(); + void addToSubpath(const PlatformPathElement& e); + + PlatformPathElements m_elements; + FloatRect m_boundingRect; + Vector<PathPolygon> m_subpaths; + PathPoint m_currentPoint; + bool m_penLifted; + }; + +} + +#endif // PlatformPathWince_h diff --git a/WebCore/platform/graphics/wince/WinceGraphicsExtras.h b/WebCore/platform/graphics/wince/WinceGraphicsExtras.h new file mode 100644 index 0000000..2a6fae1 --- /dev/null +++ b/WebCore/platform/graphics/wince/WinceGraphicsExtras.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef WinceGraphicsExtras_h +#define WinceGraphicsExtras_h + +// This file is used to contain small utilities used by WINCE graphics code. + +namespace WebCore { + // Always round to same direction. 0.5 is rounded to 1, + // and -0.5 (0.5 - 1) is rounded to 0 (1 - 1), so that it + // is consistent when transformation shifts. + static inline int stableRound(double d) + { + if (d > 0) + return static_cast<int>(d + 0.5); + + int i = static_cast<int>(d); + return i - d > 0.5 ? i - 1 : i; + } +} + +#endif WinceGraphicsExtras_h diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index de92fcd..fd3322f 100644 --- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -111,7 +111,7 @@ unsigned FontPlatformData::computeHash() const { // a font whose properties are equal should generate the same hash uintptr_t hashCodes[6] = { thisFont->GetPointSize(), thisFont->GetFamily(), thisFont->GetStyle(), thisFont->GetWeight(), thisFont->GetUnderlined(), - StringImpl::computeHash(thisFont->GetFaceName().mb_str(wxConvUTF8)) }; + StringImpl::computeHash(thisFont->GetFaceName().utf8_str()) }; return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); } diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 59e388e..9c05ce5 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -119,8 +119,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) setPaintingDisabled(!context); if (context) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } #if USE(WXGC) m_data->context = (wxGCDC*)context; @@ -252,7 +252,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points delete [] polygon; } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -262,7 +262,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height()); } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -344,6 +344,11 @@ void GraphicsContext::clip(const Path&) notImplemented(); } +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) { notImplemented(); @@ -433,7 +438,7 @@ void GraphicsContext::addPath(const Path& path) notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -452,7 +457,7 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -506,4 +511,127 @@ void GraphicsContext::fillRect(const FloatRect& rect) return; } +void GraphicsContext::setPlatformShadow(IntSize const&,int,Color const&, ColorSpace) +{ + notImplemented(); +} + +void GraphicsContext::clearPlatformShadow() +{ + notImplemented(); +} + +void GraphicsContext::beginTransparencyLayer(float) +{ + notImplemented(); +} + +void GraphicsContext::endTransparencyLayer() +{ + notImplemented(); +} + +void GraphicsContext::clearRect(const FloatRect&) +{ + notImplemented(); +} + +void GraphicsContext::strokeRect(const FloatRect&, float) +{ + notImplemented(); +} + +void GraphicsContext::setLineCap(LineCap) +{ + notImplemented(); +} + +void GraphicsContext::setLineJoin(LineJoin) +{ + notImplemented(); +} + +void GraphicsContext::setMiterLimit(float) +{ + notImplemented(); +} + +void GraphicsContext::setAlpha(float) +{ + notImplemented(); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + notImplemented(); +} + +#if PLATFORM(WIN_OS) +HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + if (dstRect.isEmpty()) + return 0; + + // Create a bitmap DC in which to draw. + BITMAPINFO bitmapInfo; + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = dstRect.width(); + bitmapInfo.bmiHeader.biHeight = dstRect.height(); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = 0; + bitmapInfo.bmiHeader.biXPelsPerMeter = 0; + bitmapInfo.bmiHeader.biYPelsPerMeter = 0; + bitmapInfo.bmiHeader.biClrUsed = 0; + bitmapInfo.bmiHeader.biClrImportant = 0; + + void* pixels = 0; + HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); + if (!bitmap) + return 0; + + HDC displayDC = ::GetDC(0); + HDC bitmapDC = ::CreateCompatibleDC(displayDC); + ::ReleaseDC(0, displayDC); + + ::SelectObject(bitmapDC, bitmap); + + // Fill our buffer with clear if we're going to alpha blend. + if (supportAlphaBlend) { + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + memset(bmpInfo.bmBits, 0, bufferSize); + } + return bitmapDC; +} + +void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + if (hdc) { + + if (!dstRect.isEmpty()) { + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + wxBitmap bmp; + bmp.SetHBITMAP(bitmap); +#if !wxCHECK_VERSION(2,9,0) + if (supportAlphaBlend) + bmp.UseAlpha(); +#endif + m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend); + + ::DeleteObject(bitmap); + } + + ::DeleteDC(hdc); + } +} +#endif + } diff --git a/WebCore/platform/graphics/wx/IconWx.cpp b/WebCore/platform/graphics/wx/IconWx.cpp new file mode 100644 index 0000000..d3cc961 --- /dev/null +++ b/WebCore/platform/graphics/wx/IconWx.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Icon.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "IntRect.h" +#include "NotImplemented.h" + +namespace WebCore { + +Icon::~Icon() +{ +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + notImplemented(); + return 0; +} + +void Icon::paint(GraphicsContext* ctx, const IntRect& rect) +{ + notImplemented(); +} + +} + diff --git a/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/WebCore/platform/graphics/wx/ImageBufferWx.cpp index e71dbde..49f3f3b 100644 --- a/WebCore/platform/graphics/wx/ImageBufferWx.cpp +++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp @@ -53,13 +53,24 @@ GraphicsContext* ImageBuffer::context() const return 0; } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { notImplemented(); return 0; } -void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&) +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + notImplemented(); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) { notImplemented(); } diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp deleted file mode 100644 index 06c165d..0000000 --- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Computer, Kevin Ollivier. 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 "ImageSource.h" - -#include "BMPImageDecoder.h" -#include "GIFImageDecoder.h" -#include "ICOImageDecoder.h" -#include "JPEGImageDecoder.h" -#include "NotImplemented.h" -#include "PNGImageDecoder.h" -#include "SharedBuffer.h" -#include "XBMImageDecoder.h" - -#include <wx/defs.h> -#include <wx/bitmap.h> -#if USE(WXGC) -#include <wx/graphics.h> -#endif -#include <wx/image.h> -#include <wx/rawbmp.h> - -namespace WebCore { - -ImageDecoder* createDecoder(const SharedBuffer& data) -{ - // We need at least 4 bytes to figure out what kind of image we're dealing with. - int length = data.size(); - if (length < 4) - return 0; - - const unsigned char* uContents = (const unsigned char*)data.data(); - const char* contents = data.data(); - - // GIFs begin with GIF8(7 or 9). - if (strncmp(contents, "GIF8", 4) == 0) - return new GIFImageDecoder(); - - // Test for PNG. - if (uContents[0]==0x89 && - uContents[1]==0x50 && - uContents[2]==0x4E && - uContents[3]==0x47) - return new PNGImageDecoder(); - - // JPEG - if (uContents[0]==0xFF && - uContents[1]==0xD8 && - uContents[2]==0xFF) - return new JPEGImageDecoder(); - - // BMP - if (strncmp(contents, "BM", 2) == 0) - return new BMPImageDecoder(); - - // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. - // CURs begin with 2-byte 0 followed by 2-byte 2. - if (!memcmp(contents, "\000\000\001\000", 4) || - !memcmp(contents, "\000\000\002\000", 4)) - return new ICOImageDecoder(); - - // XBMs require 8 bytes of info. - if (length >= 8 && strncmp(contents, "#define ", 8) == 0) - return new XBMImageDecoder(); - - // Give up. We don't know what the heck this is. - return 0; -} - -ImageSource::ImageSource() - : m_decoder(0) -{} - -ImageSource::~ImageSource() -{ - clear(true); -} - -bool ImageSource::initialized() const -{ - return m_decoder; -} - -void ImageSource::setData(SharedBuffer* data, bool allDataReceived) -{ - // Make the decoder by sniffing the bytes. - // This method will examine the data and instantiate an instance of the appropriate decoder plugin. - // If insufficient bytes are available to determine the image type, no decoder plugin will be - // made. - if (m_decoder) - delete m_decoder; - m_decoder = createDecoder(*data); - if (!m_decoder) - return; - m_decoder->setData(data, allDataReceived); -} - -bool ImageSource::isSizeAvailable() -{ - if (!m_decoder) - return false; - - return m_decoder->isSizeAvailable(); -} - -IntSize ImageSource::size() const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->size(); -} - -IntSize ImageSource::frameSizeAtIndex(size_t index) const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->frameSizeAtIndex(index); -} - -int ImageSource::repetitionCount() -{ - if (!m_decoder) - return cAnimationNone; - - return m_decoder->repetitionCount(); -} - -String ImageSource::filenameExtension() const -{ - notImplemented(); - return String(); -} - -size_t ImageSource::frameCount() const -{ - return m_decoder ? m_decoder->frameCount() : 0; -} - -bool ImageSource::frameIsCompleteAtIndex(size_t index) -{ - // FIXME: should we be testing the RGBA32Buffer's status as well? - return (m_decoder && m_decoder->frameBufferAtIndex(index) != 0); -} - -void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) -{ - if (!destroyAll) { - if (m_decoder) - m_decoder->clearFrameBufferCache(clearBeforeFrame); - return; - } - - delete m_decoder; - m_decoder = 0; - if (data) - setData(data, allDataReceived); -} - -NativeImagePtr ImageSource::createFrameAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return 0; - - return buffer->asNewNativeImage(); -} - -float ImageSource::frameDurationAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return 0; - - float duration = buffer->duration() / 1000.0f; - - // Follow other ports (and WinIE's) behavior to slow annoying ads that - // specify a 0 duration. - if (duration < 0.051f) - return 0.100f; - return duration; -} - -bool ImageSource::frameHasAlphaAtIndex(size_t index) -{ - if (!m_decoder || !m_decoder->supportsAlpha()) - return false; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return false; - - return buffer->hasAlpha(); -} - -} diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp index b0a993e..ff60d6f 100644 --- a/WebCore/platform/graphics/wx/ImageWx.cpp +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -31,6 +31,7 @@ #include "FloatRect.h" #include "GraphicsContext.h" #include "ImageObserver.h" +#include "NotImplemented.h" #include "TransformationMatrix.h" #include <math.h> @@ -45,9 +46,6 @@ #include <wx/image.h> #include <wx/thread.h> -// This function loads resources from WebKit -Vector<char> loadResourceIntoArray(const char*); - namespace WebCore { // this is in GraphicsContextWx.cpp @@ -72,7 +70,9 @@ bool FrameData::clear(bool clearMetadata) PassRefPtr<Image> Image::loadPlatformResource(const char *name) { - Vector<char> arr = loadResourceIntoArray(name); + // FIXME: We need to have some 'placeholder' graphics for things like missing + // plugins or broken images. + Vector<char> arr; RefPtr<Image> img = BitmapImage::create(); RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size()); img->setData(buffer, true); @@ -86,13 +86,13 @@ void BitmapImage::initPlatformData() // Drawing Routines -void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), op); + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } @@ -176,7 +176,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR observer->didDraw(this); } -void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect) +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& dstRect) { if (!m_source.initialized()) return; @@ -261,4 +261,9 @@ void BitmapImage::invalidatePlatformData() } +void Image::drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& destRect) +{ + notImplemented(); +} + } diff --git a/WebCore/platform/graphics/wx/IntSizeWx.cpp b/WebCore/platform/graphics/wx/IntSizeWx.cpp new file mode 100644 index 0000000..8c82854 --- /dev/null +++ b/WebCore/platform/graphics/wx/IntSizeWx.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 Kevin Watters. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntSize.h" + +#include <wx/defs.h> +#include <wx/gdicmn.h> + +namespace WebCore { + +IntSize::IntSize(const wxSize& s) + : m_width(s.x) + , m_height(s.y) +{ +} + +IntSize::operator wxSize() const +{ + return wxSize(m_width, m_height); +} + +} diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp index 2368f83..85979de 100644 --- a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp +++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp @@ -67,6 +67,7 @@ void SimpleFontData::platformCharWidthInit() void SimpleFontData::platformDestroy() { delete m_smallCapsFontData; + m_smallCapsFontData = 0; } SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const |
