diff options
Diffstat (limited to 'WebCore/platform/graphics')
155 files changed, 9320 insertions, 2237 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h index 807c11b..13641d2 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; } @@ -137,6 +141,7 @@ public: #endif #if PLATFORM(WIN) + static PassRefPtr<BitmapImage> create(HBITMAP); virtual bool getHBITMAP(HBITMAP); virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE); #endif @@ -165,10 +170,16 @@ protected: virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator); #endif virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); -#if PLATFORM(WX) || PLATFORM(WINCE) + +#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 +#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..8e51b95 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -47,6 +47,10 @@ typedef struct _GdkColor GdkColor; class wxColour; #endif +#if PLATFORM(HAIKU) +struct rgb_color; +#endif + namespace WebCore { class String; @@ -121,6 +125,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/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h index 0c97c49..06b280b 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,16 @@ public: operator QPointF() const; #endif +<<<<<<< HEAD:WebCore/platform/graphics/FloatPoint.h #if (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(HAIKU) + FloatPoint(const BPoint&); + operator BPoint() const; +#endif + +#if PLATFORM(SKIA) +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/FloatPoint.h operator SkPoint() const; FloatPoint(const SkPoint&); #endif diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h index e906812..704241a 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,15 @@ QT_END_NAMESPACE class wxRect2DDouble; #endif +<<<<<<< HEAD:WebCore/platform/graphics/FloatRect.h #if (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(HAIKU) +class BRect; +#endif + +#if PLATFORM(SKIA) +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/FloatRect.h struct SkRect; #endif @@ -123,7 +131,8 @@ public: 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 +147,16 @@ public: operator wxRect2DDouble() const; #endif +<<<<<<< HEAD:WebCore/platform/graphics/FloatRect.h #if (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(HAIKU) + FloatRect(const BRect&); + operator BRect() const; +#endif + +#if PLATFORM(SKIA) +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/FloatRect.h 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..b88305f 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 @@ -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/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/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index a4e8408..ccdce08 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(); } @@ -305,7 +305,7 @@ bool GraphicsContext::paintingDisabled() const } void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op) -{ +{ drawImage(image, p, IntRect(0, 0, -1, -1), op); } @@ -329,7 +329,7 @@ void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPo { if (paintingDisabled()) return; - + font.drawText(this, run, point, from, to); } #endif @@ -383,7 +383,7 @@ void GraphicsContext::initFocusRing(int width, int offset) if (paintingDisabled()) return; clearFocusRing(); - + m_common->m_focusRingWidth = width; m_common->m_focusRingOffset = offset; } @@ -396,12 +396,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; } @@ -436,7 +436,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) @@ -540,10 +540,39 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode) } #endif -#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA) +#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA) && !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 233c14c..b1d1ef9 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -55,8 +55,8 @@ struct SkPoint; 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 @@ -72,6 +72,10 @@ class wxWindowDC; #endif #elif PLATFORM(SKIA) typedef class PlatformContextSkia PlatformGraphicsContext; +#elif PLATFORM(HAIKU) +class BView; +typedef BView PlatformGraphicsContext; +struct pattern; #elif PLATFORM(WINCE) typedef struct HDC__ PlatformGraphicsContext; #else @@ -124,7 +128,7 @@ namespace WebCore { const int cTextFill = 1; const int cTextStroke = 2; const int cTextClip = 4; - + enum StrokeStyle { NoStroke, SolidStroke, @@ -132,12 +136,12 @@ 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 + // 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, @@ -156,11 +160,11 @@ namespace WebCore { public: GraphicsContext(PlatformGraphicsContext*); ~GraphicsContext(); - + #if !PLATFORM(WINCE) || PLATFORM(QT) PlatformGraphicsContext* platformContext() const; #endif - + float strokeThickness() const; void setStrokeThickness(float); StrokeStyle strokeStyle() const; @@ -267,7 +271,7 @@ namespace WebCore { CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator = CompositeSourceOver); - void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, + void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile, CompositeOperator = CompositeSourceOver); @@ -291,13 +295,13 @@ namespace WebCore { void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, 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); @@ -336,7 +340,7 @@ namespace WebCore { void rotate(float angleInRadians); void translate(float x, float y); IntPoint origin(); - + void setURLForRect(const KURL&, const IntRect&); void concatCTM(const TransformationMatrix&); @@ -418,6 +422,10 @@ namespace WebCore { GdkEventExpose* gdkExposeEvent() const; #endif +#if PLATFORM(HAIKU) + pattern getHaikuStrokeStyle(); +#endif + private: void savePlatformState(); void restorePlatformState(); @@ -440,6 +448,8 @@ namespace WebCore { void setPlatformShadow(const IntSize&, int blur, const Color&); void clearPlatformShadow(); + static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle&); + int focusRingWidth() const; int focusRingOffset() const; const Vector<IntRect>& focusRingRects() const; diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h new file mode 100644 index 0000000..5223e05 --- /dev/null +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -0,0 +1,335 @@ +/* + * 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/Noncopyable.h> + +#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 CanvasArray; + class CanvasBuffer; + class CanvasUnsignedByteArray; + class CanvasFloatArray; + class CanvasFramebuffer; + class CanvasIntArray; + class CanvasProgram; + class CanvasRenderbuffer; + class CanvasRenderingContext3D; + class CanvasShader; + class CanvasTexture; + class HTMLCanvasElement; + class HTMLImageElement; + class HTMLVideoElement; + class ImageData; + class WebKitCSSMatrix; + + // FIXME: ideally this would be used on all platforms. +#if PLATFORM(CHROMIUM) + class GraphicsContext3DInternal; +#endif + + class GraphicsContext3D : Noncopyable { + public: + enum ShaderType { FRAGMENT_SHADER, VERTEX_SHADER }; + + GraphicsContext3D(); + 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 checkError() const; + + 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(CanvasProgram* program, CanvasShader* shader); + void bindAttribLocation(CanvasProgram*, unsigned long index, const String& name); + void bindBuffer(unsigned long target, CanvasBuffer*); + void bindFramebuffer(unsigned long target, CanvasFramebuffer*); + void bindRenderbuffer(unsigned long target, CanvasRenderbuffer*); + void bindTexture(unsigned long target, CanvasTexture* 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, CanvasArray* data, unsigned long usage); + void bufferSubData(unsigned long target, long offset, CanvasArray* 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(CanvasShader*); + + //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(CanvasProgram*, CanvasShader*); + 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, CanvasRenderbuffer*); + void framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture*, long level); + void frontFace(unsigned long mode); + void generateMipmap(unsigned long target); + + int getAttribLocation(CanvasProgram*, const String& name); + + bool getBoolean(unsigned long pname); + PassRefPtr<CanvasUnsignedByteArray> getBooleanv(unsigned long pname); + int getBufferParameteri(unsigned long target, unsigned long pname); + PassRefPtr<CanvasIntArray> getBufferParameteriv(unsigned long target, unsigned long pname); + + unsigned long getError(); + + float getFloat(unsigned long pname); + PassRefPtr<CanvasFloatArray> getFloatv(unsigned long pname); + int getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname); + PassRefPtr<CanvasIntArray> getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname); + int getInteger(unsigned long pname); + PassRefPtr<CanvasIntArray> getIntegerv(unsigned long pname); + int getProgrami(CanvasProgram*, unsigned long pname); + PassRefPtr<CanvasIntArray> getProgramiv(CanvasProgram*, unsigned long pname); + String getProgramInfoLog(CanvasProgram*); + int getRenderbufferParameteri(unsigned long target, unsigned long pname); + PassRefPtr<CanvasIntArray> getRenderbufferParameteriv(unsigned long target, unsigned long pname); + int getShaderi(CanvasShader*, unsigned long pname); + PassRefPtr<CanvasIntArray> getShaderiv(CanvasShader*, unsigned long pname); + + String getShaderInfoLog(CanvasShader*); + + // TBD + // void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + + String getShaderSource(CanvasShader*); + String getString(unsigned long name); + + float getTexParameterf(unsigned long target, unsigned long pname); + PassRefPtr<CanvasFloatArray> getTexParameterfv(unsigned long target, unsigned long pname); + int getTexParameteri(unsigned long target, unsigned long pname); + PassRefPtr<CanvasIntArray> getTexParameteriv(unsigned long target, unsigned long pname); + + float getUniformf(CanvasProgram* program, long location); + PassRefPtr<CanvasFloatArray> getUniformfv(CanvasProgram* program, long location); + int getUniformi(CanvasProgram* program, long location); + PassRefPtr<CanvasIntArray> getUniformiv(CanvasProgram* program, long location); + + long getUniformLocation(CanvasProgram*, const String& name); + + float getVertexAttribf(unsigned long index, unsigned long pname); + PassRefPtr<CanvasFloatArray> getVertexAttribfv(unsigned long index, unsigned long pname); + int getVertexAttribi(unsigned long index, unsigned long pname); + PassRefPtr<CanvasIntArray> getVertexAttribiv(unsigned long index, unsigned long pname); + + long getVertexAttribOffset(unsigned long index, unsigned long pname); + + void hint(unsigned long target, unsigned long mode); + bool isBuffer(CanvasBuffer*); + bool isEnabled(unsigned long cap); + bool isFramebuffer(CanvasFramebuffer*); + bool isProgram(CanvasProgram*); + bool isRenderbuffer(CanvasRenderbuffer*); + bool isShader(CanvasShader*); + bool isTexture(CanvasTexture*); + void lineWidth(double); + void linkProgram(CanvasProgram*); + void pixelStorei(unsigned long pname, long param); + void polygonOffset(double factor, double units); + + // TBD + //void readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* pixels); + + 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(CanvasShader*, 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, CanvasArray* 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, HTMLImageElement* image, + bool flipY, bool premultiplyAlpha); + int texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, + 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, CanvasArray* 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, HTMLImageElement* image, + bool flipY, bool premultiplyAlpha); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, HTMLCanvasElement* canvas, + 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(CanvasProgram*); + void validateProgram(CanvasProgram*); + + 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(CanvasRenderingContext3D* context); + void endPaint(); + + // Support for buffer creation and deletion + unsigned createBuffer(); + unsigned createFramebuffer(); + unsigned createProgram(); + unsigned createRenderbuffer(); + unsigned createShader(ShaderType); + unsigned createTexture(); + + void deleteBuffer(unsigned); + void deleteFramebuffer(unsigned); + void deleteProgram(unsigned); + void deleteRenderbuffer(unsigned); + void deleteShader(unsigned); + void deleteTexture(unsigned); + + private: + 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; +#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/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index 7d43832..b375bd3 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -69,10 +69,11 @@ 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) + , m_maskLayer(0) #ifndef NDEBUG , m_repaintCount(0) #endif diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 4d7668a..2924073 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__ @@ -152,7 +156,7 @@ protected: class GraphicsLayer { public: - static GraphicsLayer* createGraphicsLayer(GraphicsLayerClient*); + static PassOwnPtr<GraphicsLayer> create(GraphicsLayerClient*); virtual ~GraphicsLayer(); @@ -180,6 +184,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 +236,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 +262,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); @@ -347,6 +358,8 @@ 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 diff --git a/WebCore/platform/graphics/GraphicsLayerClient.h b/WebCore/platform/graphics/GraphicsLayerClient.h index 8c0b7ed..5facc94 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 { 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..eabeeab 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -51,6 +51,8 @@ class SkBitmapRef; class PrivateAndroidImageSourceRec; #elif PLATFORM(SKIA) class NativeImageSkia; +#elif PLATFORM(HAIKU) +class BBitmap; #elif PLATFORM(WINCE) #include "SharedBitmap.h" #endif @@ -61,22 +63,14 @@ 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; +<<<<<<< HEAD:WebCore/platform/graphics/ImageSource.h #elif PLATFORM(ANDROID) #if PLATFORM(SGL) class String; @@ -98,18 +92,27 @@ typedef ImageDecoder* NativeImageSourcePtr; typedef NativeImageSkia* NativeImagePtr; #endif #elif PLATFORM(CAIRO) +======= +#else +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/ImageSource.h 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; diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h index e6d4816..afbfb46 100644 --- a/WebCore/platform/graphics/IntPoint.h +++ b/WebCore/platform/graphics/IntPoint.h @@ -55,6 +55,8 @@ class QPoint; QT_END_NAMESPACE #elif PLATFORM(GTK) typedef struct _GdkPoint GdkPoint; +#elif PLATFORM(HAIKU) +class BPoint; #endif #if PLATFORM(WX) @@ -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) diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h index 0b607f5..cd912ff 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,6 +49,8 @@ class QRect; QT_END_NAMESPACE #elif PLATFORM(GTK) typedef struct _GdkRectangle GdkRectangle; +#elif PLATFORM(HAIKU) +class BRect; #endif #if PLATFORM(WX) @@ -144,6 +146,9 @@ public: #elif PLATFORM(GTK) IntRect(const GdkRectangle&); operator GdkRectangle() const; +#elif PLATFORM(HAIKU) + explicit IntRect(const BRect&); + operator BRect() const; #endif #if PLATFORM(CG) @@ -156,7 +161,8 @@ public: 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 8792640..3898386 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" @@ -67,11 +68,12 @@ public: 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) { } @@ -93,7 +95,7 @@ public: 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; } @@ -260,11 +262,19 @@ bool MediaPlayer::canLoadPoster() const { return m_private->canLoadPoster(); } +<<<<<<< HEAD:WebCore/platform/graphics/MediaPlayer.cpp +======= + +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/MediaPlayer.cpp void MediaPlayer::setPoster(const String& url) { m_private->setPoster(url); +<<<<<<< HEAD:WebCore/platform/graphics/MediaPlayer.cpp } +======= +} +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/MediaPlayer.cpp void MediaPlayer::cancelLoad() { @@ -275,7 +285,11 @@ void MediaPlayer::prepareToPlay() { m_private->prepareToPlay(); } +<<<<<<< HEAD:WebCore/platform/graphics/MediaPlayer.cpp +======= + +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/MediaPlayer.cpp void MediaPlayer::play() { m_private->play(); @@ -331,11 +345,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; @@ -344,6 +363,11 @@ bool MediaPlayer::inMediaDocument() return document && document->isMediaDocument(); } +PlatformMedia MediaPlayer::platformMedia() const +{ + return m_private->platformMedia(); +} + MediaPlayer::NetworkState MediaPlayer::networkState() { return m_private->networkState(); @@ -397,9 +421,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 d0220ed..4cc6476 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 @@ -38,8 +38,24 @@ #include <wtf/OwnPtr.h> #include <wtf/Noncopyable.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 +64,7 @@ class IntSize; class MediaPlayer; class MediaPlayerPrivateInterface; class String; +class TimeRanges; #if USE(ACCELERATED_COMPOSITING) class GraphicsLayer; @@ -109,8 +126,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; } @@ -146,7 +166,7 @@ public: bool preservesPitch() const; void setPreservesPitch(bool); - float maxTimeBuffered(); + PassRefPtr<TimeRanges> buffered(); float maxTimeSeekable(); unsigned bytesLoaded(); diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h index de7f75c..925e563 100644 --- a/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -44,6 +44,11 @@ public: virtual void cancelLoad() = 0; virtual void prepareToPlay() { } +<<<<<<< HEAD:WebCore/platform/graphics/MediaPlayerPrivate.h +======= + virtual PlatformMedia platformMedia() const { return NoPlatformMedia; } + +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/MediaPlayerPrivate.h virtual void play() = 0; virtual void pause() = 0; @@ -53,6 +58,7 @@ public: virtual IntSize naturalSize() const = 0; virtual bool hasVideo() const = 0; + virtual bool hasAudio() const = 0; virtual void setVisible(bool) = 0; @@ -77,7 +83,7 @@ public: 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; diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index da324bc..6b617a0 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -52,6 +52,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; diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h index 02ad3ec..2f1192c 100644 --- a/WebCore/platform/graphics/Pattern.h +++ b/WebCore/platform/graphics/Pattern.h @@ -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/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index 0f7ae79..1a951c2 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -46,7 +46,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); diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 5765546..de8afb3 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -31,7 +31,6 @@ #if PLATFORM(CAIRO) -#include "TransformationMatrix.h" #include "CairoPath.h" #include "FloatRect.h" #include "Font.h" @@ -41,6 +40,7 @@ #include "Path.h" #include "Pattern.h" #include "SimpleFontData.h" +#include "TransformationMatrix.h" #include <cairo.h> #include <math.h> @@ -53,8 +53,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 @@ -142,38 +142,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 +207,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 +284,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 +292,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 +315,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 +325,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) { @@ -828,15 +794,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 +819,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 +853,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; } } diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index c905ee8..0213944 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -138,16 +138,17 @@ 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 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 +157,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 +168,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 +181,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 +197,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 +220,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,12 +253,25 @@ 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; } } +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) { Vector<char>* in = reinterpret_cast<Vector<char>*>(closure); 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..1b843e4 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -28,14 +28,15 @@ #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> @@ -86,7 +87,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() @@ -178,19 +179,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); @@ -221,7 +222,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 +236,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 +249,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth) CGContextRestoreGState(context); - + if (shouldAntialias()) CGContextSetShouldAntialias(context, true); } @@ -263,7 +264,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect) if (paintingDisabled()) return; - + CGContextRef context = platformContext(); CGContextBeginPath(context); float r = (float)rect.width() / 2; @@ -275,25 +276,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 +305,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 +329,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 +339,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 +353,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 +375,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 +383,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points CGContextClosePath(context); drawPath(); - + if (antialiased != shouldAntialias()) CGContextSetShouldAntialias(context, shouldAntialias()); } @@ -391,35 +391,31 @@ 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.get()->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.get()->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) @@ -463,7 +459,7 @@ void GraphicsContext::drawPath() strokePath(); return; } - + if (state.fillColorSpace == PatternColorSpace) applyFillPattern(); if (state.strokeColorSpace == PatternColorSpace) @@ -599,7 +595,7 @@ void GraphicsContext::clipOut(const IntRect& rect) { if (paintingDisabled()) return; - + CGRect rects[2] = { CGContextGetClipBoundingBox(platformContext()), rect }; CGContextBeginPath(platformContext()); CGContextAddRects(platformContext(), rects, 2); @@ -610,7 +606,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) { if (paintingDisabled()) return; - + CGContextBeginPath(platformContext()); CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); CGContextAddEllipseInRect(platformContext(), rect); @@ -639,13 +635,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 +649,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()); @@ -731,12 +727,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, createCGColor(color)); CGContextSetShadowWithColor(context, CGSizeMake(width, height), - blurRadius, - colorCG); - CGColorRelease(colorCG); + blurRadius, + colorCG.get()); } } @@ -799,15 +794,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 +816,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; } } @@ -858,7 +853,7 @@ void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) return; - + CGContextBeginPath(platformContext()); CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); CGContextAddPath(platformContext(), path.platformPath()); @@ -909,9 +904,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 +929,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 +979,13 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri } } } - + if (fillColor() != strokeColor()) setCGFillColor(platformContext(), strokeColor()); CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness)); if (fillColor() != strokeColor()) setCGFillColor(platformContext(), fillColor()); - + if (restoreAntialiasMode) CGContextSetShouldAntialias(platformContext(), true); } @@ -999,51 +994,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: + 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; + quality = kCGInterpolationMedium; + break; #endif - case InterpolationHigh: - quality = kCGInterpolationHigh; - break; + case InterpolationHigh: + quality = kCGInterpolationHigh; + break; } CGContextSetInterpolationQuality(platformContext(), quality); } @@ -1055,18 +1049,18 @@ 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; + case kCGInterpolationMedium: + return InterpolationMedium; #endif - case kCGInterpolationHigh: - return InterpolationHigh; + case kCGInterpolationHigh: + return InterpolationHigh; } return InterpolationDefault; } @@ -1079,32 +1073,32 @@ 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; } } @@ -1138,54 +1132,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..38c5506 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -38,12 +38,10 @@ public: #endif , m_userToDeviceTransformKnownToBeIdentity(false) { - CGContextRetain(m_cgContext); } ~GraphicsContextPlatformPrivate() { - CGContextRelease(m_cgContext); } #if PLATFORM(MAC) || PLATFORM(CHROMIUM) @@ -80,7 +78,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..4da7018 100644 --- a/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/WebCore/platform/graphics/cg/ImageCG.cpp @@ -101,30 +101,29 @@ 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; } } @@ -252,14 +251,14 @@ 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)); } #ifndef BUILDING_ON_TIGER @@ -275,7 +274,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 +287,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..66246fe 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -109,18 +109,16 @@ 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()); #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. 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); + RetainPtr<CFAllocatorRef> derefAllocator(AdoptCF, CFAllocatorCreate(kCFAllocatorDefault, &context)); + RetainPtr<CFDataRef> cfData(AdoptCF, CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), derefAllocator.get())); #endif - CGImageSourceUpdateData(m_decoder, cfData, allDataReceived); - CFRelease(cfData); + CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived); } String ImageSource::filenameExtension() const @@ -138,12 +136,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 +150,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 +176,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 +200,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 +226,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/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp index 858b18e..2f5c15e 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -68,16 +68,14 @@ 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()); #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); + RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(this->data()->data()), this->data()->size(), kCFAllocatorNull)); #endif - CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); - CFRelease(data); - m_document = CGPDFDocumentCreateWithProvider(dataProvider); - CGDataProviderRelease(dataProvider); + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); + m_document = CGPDFDocumentCreateWithProvider(dataProvider.get()); setCurrentPage(0); } return m_document; // return true if size is available 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..229188e 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -459,14 +459,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/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index d4e45fb..dca0efb 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() @@ -136,27 +141,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 +290,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 +423,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 +432,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; }; 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/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..2364cc4 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->subRegion()); + RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); + + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->subRegion()); + 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..1e2e552 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -166,7 +166,7 @@ void FEColorMatrix::apply(Filter* filter) filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); 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 +186,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..43e5edd 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*) +void identity(unsigned char*, const ComponentTransferFunction&) +{ +} + +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); + } +} + +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); + } +} + +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); + } +} + +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->subRegion()); + 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..1b41165 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(), calculateDrawingRect(m_in2->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + break; + case FECOMPOSITE_OPERATOR_IN: + filterContext->save(); + filterContext->clipToImageBuffer(calculateDrawingRect(m_in2->subRegion()), m_in2->resultImage()); + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->restore(); + break; + case FECOMPOSITE_OPERATOR_OUT: + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion()), srcRect, CompositeDestinationOut); + break; + case FECOMPOSITE_OPERATOR_ATOP: + filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()), srcRect, CompositeSourceAtop); + break; + case FECOMPOSITE_OPERATOR_XOR: + filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()), srcRect, CompositeXOR); + break; + case FECOMPOSITE_OPERATOR_ARITHMETIC: { + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->subRegion()); + RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); + + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->subRegion()); + 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/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index 41e8a39..5818e50 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -59,6 +59,13 @@ FloatRect FilterEffect::calculateEffectRect(Filter* filter) return subRegion(); } +IntRect FilterEffect::calculateDrawingIntRect(const FloatRect& effectRect) +{ + IntPoint location = roundedIntPoint(FloatPoint(subRegion().x() - effectRect.x(), + subRegion().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()); diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index 8dc6233..e2b8a0e 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -77,6 +77,7 @@ namespace WebCore { GraphicsContext* getEffectContext(); FloatRect calculateDrawingRect(const FloatRect&); + IntRect calculateDrawingIntRect(const FloatRect&); virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return filter->filterRegion(); } virtual FloatRect calculateEffectRect(Filter*); diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index 646a57b..57436be 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,28 @@ 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); + return filter->filterRegion(); +} + +void SourceAlpha::apply(Filter* filter) +{ + GraphicsContext* filterContext = getEffectContext(); + if (!filterContext) + return; + + FloatRect imageRect(FloatPoint(), filter->sourceImage()->image()->size()); + filterContext->save(); + filterContext->clipToImageBuffer(imageRect, filter->sourceImage()); + filterContext->fillRect(imageRect, Color::black); + 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/gtk/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp new file mode 100644 index 0000000..a6c2dfb --- /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, 0); + 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/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/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..65c64b4 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 @@ -24,6 +25,7 @@ #if ENABLE(VIDEO) #include "MediaPlayerPrivateGStreamer.h" +#include "DataSourceGStreamer.h" #include "CString.h" #include "GraphicsContext.h" @@ -35,6 +37,7 @@ #include "ScrollView.h" #include "VideoSinkGStreamer.h" #include "Widget.h" +#include "TimeRanges.h" #include <gst/base/gstbasesrc.h> #include <gst/gst.h> @@ -56,13 +59,19 @@ gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpoin GOwnPtr<gchar> debug; 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); + LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); + + MediaPlayer::NetworkState error = MediaPlayer::Empty; + if (err->domain == GST_CORE_ERROR || err->domain == GST_LIBRARY_ERROR) + error = MediaPlayer::DecodeError; + else if (err->domain == GST_RESOURCE_ERROR) + error = MediaPlayer::FormatError; + else if (err->domain == GST_STREAM_ERROR) + error = MediaPlayer::NetworkError; + + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + if (mp) + mp->loadingFailed(error); } return true; } @@ -112,6 +121,19 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) registrar(create, getSupportedTypes, supportsType); } +static bool gstInitialized = false; + +static void do_gst_init() { + // FIXME: We should pass the arguments from the command line + if (!gstInitialized) { + gst_init(0, 0); + gstInitialized = true; + gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, + WEBKIT_TYPE_DATA_SRC); + + } +} + MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player) , m_playBin(0) @@ -119,7 +141,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_source(0) , m_rate(1.0f) , m_endTime(numeric_limits<float>::infinity()) - , m_isEndReached(false) , m_volume(0.5f) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) @@ -127,19 +148,22 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_isStreaming(false) , m_size(IntSize()) , m_visible(true) + , 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; - } + do_gst_init(); // 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); } +static gboolean idleUnref(gpointer data) +{ + g_object_unref(reinterpret_cast<GObject*>(data)); + return FALSE; +} + MediaPlayerPrivate::~MediaPlayerPrivate() { if (m_surface) @@ -149,6 +173,18 @@ MediaPlayerPrivate::~MediaPlayerPrivate() gst_element_set_state(m_playBin, GST_STATE_NULL); gst_object_unref(GST_OBJECT(m_playBin)); } + + // FIXME: We should find a better way to handle the lifetime of this object; this is + // needed because the object is sometimes being destroyed inbetween a call to + // webkit_video_sink_render, and the idle it schedules. Adding a ref in + // webkit_video_sink_render that would be balanced by the idle is not an option, + // because in some cases the destruction of the sink may happen in time for the idle + // to be removed from the queue, so it may not run. It would also cause lots of ref + // counting churn (render/idle are called many times). This is an ugly race. + if (m_videoSink) { + g_idle_add(idleUnref, m_videoSink); + m_videoSink = 0; + } } void MediaPlayerPrivate::load(const String& url) @@ -170,20 +206,13 @@ 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; - gst_element_set_state(m_playBin, GST_STATE_PLAYING); - m_startedPlaying = true; } void MediaPlayerPrivate::pause() { LOG_VERBOSE(Media, "Pause"); gst_element_set_state(m_playBin, GST_STATE_PAUSED); - m_startedPlaying = false; } float MediaPlayerPrivate::duration() const @@ -191,17 +220,24 @@ 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 +#if !GST_CHECK_VERSION(0, 10, 23) + // 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. + // See https://bugs.webkit.org/show_bug.cgi?id=24639 which has been + // fixed in gst-plugins-base 0.10.23 if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeLength <= 0) { +#else + if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength)) { +#endif LOG_VERBOSE(Media, "Time duration query failed."); - m_isStreaming = true; return numeric_limits<float>::infinity(); } @@ -215,22 +251,24 @@ 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; + + float ret = 0.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 { + if (!gst_element_query(m_playBin, query)) { LOG_VERBOSE(Media, "Position query failed..."); - ret = 0.0; + gst_query_unref(query); + return ret; } + + 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)); + gst_query_unref(query); return ret; @@ -246,35 +284,23 @@ 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, 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; } 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 +320,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 +334,28 @@ 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); + gst_video_get_size(GST_PAD(pad), &width, &height); + GstCaps* caps = GST_PAD_CAPS(pad); + gfloat pixelAspectRatio; + gint pixelAspectRatioNumerator, pixelAspectRatioDenominator; + + if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, + &pixelAspectRatioDenominator)) + pixelAspectRatioNumerator = pixelAspectRatioDenominator = 1; + + 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,24 +366,31 @@ bool MediaPlayerPrivate::hasVideo() const return currentVideo > -1; } +bool MediaPlayerPrivate::hasAudio() const +{ + gint currentAudio = -1; + if (m_playBin) + g_object_get(G_OBJECT(m_playBin), "current-audio", ¤tAudio, NULL); + return currentAudio > -1; +} + void MediaPlayerPrivate::setVolume(float volume) { m_volume = volume; LOG_VERBOSE(Media, "Volume to %f", volume); - setMuted(false); + + if (!m_playBin) + return; + + g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL); } -void MediaPlayerPrivate::setMuted(bool b) +void MediaPlayerPrivate::setMuted(bool mute) { 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), "mute", mute, NULL); } void MediaPlayerPrivate::setRate(float rate) @@ -351,17 +399,13 @@ void MediaPlayerPrivate::setRate(float rate) gst_element_set_state(m_playBin, GST_STATE_PAUSED); return; } + if (m_isStreaming) return; m_rate = rate; 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); + seek(currentTime()); } int MediaPlayerPrivate::dataRate() const @@ -380,16 +424,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 +448,9 @@ float MediaPlayerPrivate::maxTimeSeekable() const float MediaPlayerPrivate::maxTimeLoaded() const { + if (m_errorOccured) + return 0.0; + // TODO LOG_VERBOSE(Media, "maxTimeLoaded"); notImplemented(); @@ -416,29 +467,30 @@ 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() @@ -452,17 +504,21 @@ 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", @@ -474,6 +530,16 @@ void MediaPlayerPrivate::updateStates() } else if (state == GST_STATE_PAUSED) m_readyState = MediaPlayer::HaveEnoughData; + if (state == GST_STATE_PLAYING) + m_paused = false; + else + m_paused = true; + + if (m_seeking) { + shouldUpdateAfterSeek = true; + m_seeking = false; + } + m_networkState = MediaPlayer::Loaded; g_object_get(m_playBin, "source", &m_source, NULL); @@ -486,11 +552,17 @@ 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) @@ -506,6 +578,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); @@ -546,15 +621,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) { @@ -565,7 +639,18 @@ void MediaPlayerPrivate::loadingFailed() void MediaPlayerPrivate::setSize(const IntSize& size) { + // Destroy and re-create the cairo surface only if the size + // changed. + if (size != m_size) { + if (m_surface) + cairo_surface_destroy(m_surface); + m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), + size.height()); + g_object_set(m_videoSink, "surface", m_surface, 0); + } + m_size = size; + } void MediaPlayerPrivate::setVisible(bool visible) @@ -586,11 +671,12 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) if (!m_visible) return; - //TODO: m_size vs rect? cairo_t* cr = context->platformContext(); cairo_save(cr); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + + // paint the rectangle on the context and draw the surface inside. 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); @@ -598,24 +684,124 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) cairo_restore(cr); } +static HashSet<String> mimeTypeCache() +{ + + do_gst_init(); + + static HashSet<String> cache; + static bool typeListInitialized = false; + + if (!typeListInitialized) { + // These subtypes are already beeing supported by WebKit itself + HashSet<String> ignoredApplicationSubtypes; + ignoredApplicationSubtypes.add(String("javascript")); + ignoredApplicationSubtypes.add(String("ecmascript")); + ignoredApplicationSubtypes.add(String("x-javascript")); + ignoredApplicationSubtypes.add(String("xml")); + ignoredApplicationSubtypes.add(String("xhtml+xml")); + ignoredApplicationSubtypes.add(String("rss+xml")); + ignoredApplicationSubtypes.add(String("atom+xml")); + ignoredApplicationSubtypes.add(String("x-ftp-directory")); + ignoredApplicationSubtypes.add(String("x-java-applet")); + ignoredApplicationSubtypes.add(String("x-java-bean")); + ignoredApplicationSubtypes.add(String("x-java-vm")); + ignoredApplicationSubtypes.add(String("x-shockwave-flash")); + + 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); + + // Splitting the capability by comma and taking the first part + // as capability can be something like "audio/x-wavpack, framed=(boolean)false" + GOwnPtr<gchar> capabilityString(gst_caps_to_string(caps)); + gchar** capability = g_strsplit(capabilityString.get(), ",", 2); + gchar** mimetype = g_strsplit(capability[0], "/", 2); + + // 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 + if (g_str_equal(mimetype[0], "audio") || + g_str_equal(mimetype[0], "video") || + (g_str_equal(mimetype[0], "application") && + !ignoredApplicationSubtypes.contains(String(mimetype[1])))) { + cache.add(String(capability[0])); + + // These formats are supported by GStreamer, but not correctly advertised + if (g_str_equal(capability[0], "video/x-h264") || + g_str_equal(capability[0], "audio/x-m4a")) { + cache.add(String("video/mp4")); + cache.add(String("audio/aac")); + } + + if (g_str_equal(capability[0], "video/x-theora")) + cache.add(String("video/ogg")); + + if (g_str_equal(capability[0], "audio/x-wav")) + cache.add(String("audio/wav")); + + if (g_str_equal(capability[0], "audio/mpeg")) { + // This is what we are handling: mpegversion=(int)1, layer=(int)[ 1, 3 ] + gchar** versionAndLayer = g_strsplit(capability[1], ",", 2); + + if (g_str_has_suffix (versionAndLayer[0], "(int)1")) { + for (int i = 0; versionAndLayer[1][i] != '\0'; i++) { + if (versionAndLayer[1][i] == '1') + cache.add(String("audio/mp1")); + else if (versionAndLayer[1][i] == '2') + cache.add(String("audio/mp2")); + else if (versionAndLayer[1][i] == '3') + cache.add(String("audio/mp3")); + } + } + + g_strfreev(versionAndLayer); + } + } + + g_strfreev(capability); + 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); @@ -627,10 +813,12 @@ void MediaPlayerPrivate::createGSTPlayBin(String url) g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL); - GstElement* audioSink = gst_element_factory_make("gconfaudiosink", 0); m_videoSink = webkit_video_sink_new(m_surface); - g_object_set(m_playBin, "audio-sink", audioSink, NULL); + // This ref is to protect the sink from being destroyed before we stop the idle it + // creates internally. See the comment in ~MediaPlayerPrivate. + g_object_ref(m_videoSink); + g_object_set(m_playBin, "video-sink", m_videoSink, NULL); g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this); @@ -641,4 +829,3 @@ void MediaPlayerPrivate::createGSTPlayBin(String url) } #endif - diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h index 8842f84..d305759 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h @@ -56,6 +56,7 @@ namespace WebCore { IntSize naturalSize() const; bool hasVideo() const; + bool hasAudio() const; void load(const String &url); void cancelLoad(); @@ -80,7 +81,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; @@ -95,11 +96,15 @@ namespace WebCore { 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); @@ -132,6 +137,10 @@ namespace WebCore { IntSize m_size; bool m_visible; cairo_surface_t* m_surface; + + 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..9a616f4 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -50,9 +50,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 +63,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 +130,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..fb86fe9 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -33,8 +33,14 @@ #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) +#else + GST_STATIC_CAPS(GST_VIDEO_CAPS_xRGB) +#endif +); GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug); #define GST_CAT_DEFAULT webkit_video_sink_debug @@ -102,9 +108,14 @@ webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass) static gboolean webkit_video_sink_idle_func(gpointer data) { - WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(data); + WebKitVideoSink* sink = reinterpret_cast<WebKitVideoSink*>(data); WebKitVideoSinkPrivate* priv = sink->priv; GstBuffer* buffer; + GstCaps* caps; + GstVideoFormat format; + gint par_n, par_d; + gfloat par; + gint bwidth, bheight; if (!priv->async_queue) return FALSE; @@ -113,19 +124,35 @@ webkit_video_sink_idle_func(gpointer data) if (!buffer || G_UNLIKELY(!GST_IS_BUFFER(buffer))) return FALSE; + caps = GST_BUFFER_CAPS(buffer); + if (!gst_video_format_parse_caps(caps, &format, &bwidth, &bheight)) { + GST_ERROR_OBJECT(sink, "Unknown video format in buffer caps '%s'", + gst_caps_to_string(caps)); + return FALSE; + } + + if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &par_n, &par_d)) + par_n = par_d = 1; + + par = (gfloat) par_n / (gfloat) par_d; + // 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); + cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), + CAIRO_FORMAT_RGB24, + bwidth, bheight, + 4 * bwidth); // TODO: We copy the data twice right now. This could be easily improved. cairo_t* cr = cairo_create(priv->surface); + cairo_scale(cr, par, 1.0 / par); 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); - gst_buffer_unref(buffer); + g_async_queue_unref(priv->async_queue); g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0); @@ -138,6 +165,7 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); WebKitVideoSinkPrivate* priv = sink->priv; + g_async_queue_ref(priv->async_queue); 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); @@ -151,9 +179,7 @@ webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps) WebKitVideoSinkPrivate* priv = sink->priv; GstStructure* structure; gboolean ret; - const GValue* fps; - const GValue* par; - gint width, height; + gint width, height, fps_n, fps_d; int red_mask; GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps); @@ -167,25 +193,19 @@ webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps) 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 (!ret) - return FALSE; + /* We dont yet use fps but handy to have */ + ret &= gst_structure_get_fraction(structure, "framerate", + &fps_n, &fps_d); + g_return_val_if_fail(ret, FALSE); priv->width = width; priv->height = height; + priv->fps_n = fps_n; + priv->fps_d = fps_d; - /* 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); - - if (par) { - priv->par_n = gst_value_get_fraction_numerator(par); - priv->par_d = gst_value_get_fraction_denominator(par); - } else + if (!gst_structure_get_fraction(structure, "pixel-aspect-ratio", + &priv->par_n, &priv->par_d)) priv->par_n = priv->par_d = 1; gst_structure_get_int(structure, "red_mask", &red_mask); @@ -265,6 +285,8 @@ webkit_video_sink_stop(GstBaseSink* base_sink) g_async_queue_unlock(priv->async_queue); + g_idle_remove_by_data(base_sink); + return TRUE; } 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..d785ef4 --- /dev/null +++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -0,0 +1,536 @@ +/* + * 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) +{ + 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) +{ + 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::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) +{ + 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) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetHighColor(color); +} + +void GraphicsContext::clearPlatformShadow() +{ + notImplemented(); +} + +void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&) +{ + 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..dccac4a --- /dev/null +++ b/WebCore/platform/graphics/haiku/IconHaiku.cpp @@ -0,0 +1,57 @@ +/* + * 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::createIconForFile(const String& filename) +{ + notImplemented(); + return 0; +} + +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..323d6ab --- /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, CompositeOperator op) +{ + startAnimation(); + + BBitmap* image = nativeImageForCurrentFrame(); + if (!image || !image->IsValid()) // If the image hasn't fully loaded. + return; + + if (mayFillWithSolidColor()) { + fillWithSolidColor(ctxt, dst, solidColor(), 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, 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..34941c0 --- /dev/null +++ b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp @@ -0,0 +1,108 @@ +/* + * 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> + + +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 +{ + const char charArray[1] = { glyph }; + float escapements[1]; + + if (m_platformData.font()) { + m_platformData.font()->GetEscapements(charArray, 1, escapements); + return escapements[0] * m_platformData.font()->Size(); + } + + return 0; +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.h b/WebCore/platform/graphics/mac/Canvas3DLayer.h new file mode 100644 index 0000000..6c65676 --- /dev/null +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.h @@ -0,0 +1,50 @@ +/* + * 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; + +@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..545c58b --- /dev/null +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.mm @@ -0,0 +1,123 @@ +/* + * 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> + +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 +{ + CGLPixelFormatAttribute attribs[] = + { + (CGLPixelFormatAttribute) kCGLPFAAccelerated, + (CGLPixelFormatAttribute) kCGLPFAColorSize, (CGLPixelFormatAttribute) 32, + (CGLPixelFormatAttribute) kCGLPFADisplayMask, (CGLPixelFormatAttribute) mask, + (CGLPixelFormatAttribute) 0 + }; + + CGLPixelFormatObj pixelFormatObj; + GLint numPixelFormats; + + CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats); + return pixelFormatObj; +} + +-(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 +{ + 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]; +} + +@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/CoreTextController.cpp index 05f29b5..b2682e4 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.cpp +++ b/WebCore/platform/graphics/mac/CoreTextController.cpp @@ -365,7 +365,7 @@ void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsig RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes())); + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode()))); RetainPtr<CTTypesetterRef> typesetter; diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index e40bbab..5e72101 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -46,11 +46,13 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) 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 +77,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 +89,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..b2b9a5c 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); diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm index 051abb7..409bda4 100644 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm @@ -105,12 +105,12 @@ static bool fontHasMirroringInfo(ATSUFontID fontID) return false; } -static void disableLigatures(const SimpleFontData* fontData) +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 (fontData->platformData().allowsLigatures()) + if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures()) return; ATSUFontFeatureType featureTypes[] = { kLigaturesType }; @@ -120,7 +120,7 @@ static void disableLigatures(const SimpleFontData* fontData) LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", status); } -static void initializeATSUStyle(const SimpleFontData* fontData) +static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode) { if (fontData->m_ATSUStyleInitialized) return; @@ -141,19 +141,28 @@ static void initializeATSUStyle(const SimpleFontData* fontData) 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); + bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; + if (!allowKerning) { + // 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); + } else { + ATSUAttributeTag styleTags[3] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag }; + ATSUAttributeValuePtr styleValues[3] = { &fontSize, &fontID, &transform, }; + status = ATSUSetAttributes(fontData->m_ATSUStyle, 3, 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); + disableLigatures(fontData, textMode); fontData->m_ATSUStyleInitialized = true; } @@ -329,7 +338,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g OSStatus status; ATSULayoutOperationOverrideSpecifier overrideSpecifier; - initializeATSUStyle(fontData); + initializeATSUStyle(fontData, m_font->fontDescription().textRenderingMode()); // FIXME: This is currently missing the following required features that the CoreGraphics code path has: // - \n, \t, and nonbreaking space render as a space. @@ -393,7 +402,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g const FontData* fallbackFontData = m_font->fontDataForCharacters(m_run.characters() + substituteOffset, substituteLength); substituteFontData = fallbackFontData ? fallbackFontData->fontDataForCharacter(m_run[0]) : 0; if (substituteFontData) { - initializeATSUStyle(substituteFontData); + initializeATSUStyle(substituteFontData, m_font->fontDescription().textRenderingMode()); if (substituteFontData->m_ATSUStyle) ATSUSetRunStyle(layout, substituteFontData->m_ATSUStyle, substituteOffset, substituteLength); } else @@ -412,7 +421,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g if (i == substituteOffset || i == substituteOffset + substituteLength) { if (isSmallCap) { isSmallCap = false; - initializeATSUStyle(r->smallCapsFontData(m_font->fontDescription())); + initializeATSUStyle(r->smallCapsFontData(m_font->fontDescription()), m_font->fontDescription().textRenderingMode()); ATSUSetRunStyle(layout, r->smallCapsFontData(m_font->fontDescription())->m_ATSUStyle, firstSmallCap, i - firstSmallCap); } if (i == substituteOffset && substituteLength > 0) @@ -456,7 +465,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g } else { if (isSmallCap) { isSmallCap = false; - initializeATSUStyle(smallCapsData); + initializeATSUStyle(smallCapsData, m_font->fontDescription().textRenderingMode()); ATSUSetRunStyle(layout, smallCapsData->m_ATSUStyle, firstSmallCap, i - firstSmallCap); } m_fonts[i] = r; @@ -504,8 +513,8 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& firstGlyphBounds = zeroTrapezoid; } - float beforeWidth = MIN(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x)); - float afterWidth = MAX(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x)); + 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); @@ -591,8 +600,8 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon 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)); + 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 diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp new file mode 100644 index 0000000..cd66445 --- /dev/null +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -0,0 +1,1698 @@ +/* + * 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 "CanvasBuffer.h" +#include "CanvasFramebuffer.h" +#include "CanvasArray.h" +#include "CanvasFloatArray.h" +#include "CanvasIntArray.h" +#include "CanvasObject.h" +#include "CanvasProgram.h" +#include "CanvasRenderbuffer.h" +#include "CanvasShader.h" +#include "CanvasTexture.h" +#include "CanvasUnsignedByteArray.h" +#include "CString.h" +#include "HTMLCanvasElement.h" +#include "HTMLImageElement.h" +#include "ImageBuffer.h" +#include "NotImplemented.h" +#include "WebKitCSSMatrix.h" + +#include <CoreGraphics/CGBitmapContext.h> + +namespace WebCore { + +GraphicsContext3D::GraphicsContext3D() +{ + CGLPixelFormatAttribute attribs[] = + { + (CGLPixelFormatAttribute) kCGLPFAAccelerated, + (CGLPixelFormatAttribute) kCGLPFAColorSize, (CGLPixelFormatAttribute) 32, + (CGLPixelFormatAttribute) kCGLPFADepthSize, (CGLPixelFormatAttribute) 32, + (CGLPixelFormatAttribute) kCGLPFASupersample, + (CGLPixelFormatAttribute) 0 + }; + + CGLPixelFormatObj pixelFormatObj; + GLint numPixelFormats; + + CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats); + + CGLCreateContext(pixelFormatObj, 0, &m_contextObj); + + CGLDestroyPixelFormat(pixelFormatObj); + + // 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() +{ + CGLSetCurrentContext(m_contextObj); + ::glDeleteRenderbuffersEXT(1, & m_depthBuffer); + ::glDeleteTextures(1, &m_texture); + ::glDeleteFramebuffersEXT(1, &m_fbo); + CGLSetCurrentContext(0); + CGLDestroyContext(m_contextObj); +} + +void GraphicsContext3D::checkError() const +{ + // FIXME: This needs to only be done in the debug context. It will probably throw an exception + // on error and print the error message to the debug console + GLenum error = ::glGetError(); + if (error != GL_NO_ERROR) + notImplemented(); +} + +void GraphicsContext3D::makeContextCurrent() +{ + CGLSetCurrentContext(m_contextObj); +} + +void GraphicsContext3D::beginPaint(CanvasRenderingContext3D* context) +{ + UNUSED_PARAM(context); +} + +void GraphicsContext3D::endPaint() +{ +} + +void GraphicsContext3D::reshape(int width, int height) +{ + if (width == m_currentWidth && height == m_currentHeight) + 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) +{ + CGLContextObj currentContext = CGLGetCurrentContext(); + if (currentContext != context) + CGLSetCurrentContext(context); +} + +void GraphicsContext3D::activeTexture(unsigned long texture) +{ + ensureContext(m_contextObj); + ::glActiveTexture(texture); +} + +void GraphicsContext3D::attachShader(CanvasProgram* program, CanvasShader* shader) +{ + if (!program || !shader) + return; + ensureContext(m_contextObj); + ::glAttachShader((GLuint) program->object(), (GLuint) shader->object()); +} + +void GraphicsContext3D::bindAttribLocation(CanvasProgram* program, unsigned long index, const String& name) +{ + if (!program) + return; + ensureContext(m_contextObj); + ::glBindAttribLocation((GLuint) program->object(), index, name.utf8().data()); +} + +void GraphicsContext3D::bindBuffer(unsigned long target, CanvasBuffer* buffer) +{ + ensureContext(m_contextObj); + ::glBindBuffer(target, buffer ? (GLuint) buffer->object() : 0); +} + + +void GraphicsContext3D::bindFramebuffer(unsigned long target, CanvasFramebuffer* buffer) +{ + ensureContext(m_contextObj); + ::glBindFramebufferEXT(target, buffer ? (GLuint) buffer->object() : m_fbo); +} + +void GraphicsContext3D::bindRenderbuffer(unsigned long target, CanvasRenderbuffer* renderbuffer) +{ + ensureContext(m_contextObj); + ::glBindBuffer(target, renderbuffer ? (GLuint) renderbuffer->object() : 0); +} + + +void GraphicsContext3D::bindTexture(unsigned long target, CanvasTexture* 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, CanvasArray* array, unsigned long usage) +{ + if (!array || !array->length()) + return; + + ensureContext(m_contextObj); + ::glBufferData(target, array->sizeInBytes(), array->baseAddress(), usage); +} + +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, CanvasArray* array) +{ + if (!array || !array->length()) + return; + + ensureContext(m_contextObj); + ::glBufferSubData(target, offset, array->sizeInBytes(), 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(CanvasShader* shader) +{ + if (!shader) + return; + + 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(CanvasProgram* program, CanvasShader* shader) +{ + if (!program || !shader) + return; + + 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, CanvasRenderbuffer* buffer) +{ + if (!buffer) + return; + + ensureContext(m_contextObj); + ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, (GLuint) buffer->object()); +} + +void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture* texture, long level) +{ + if (!texture) + return; + + ensureContext(m_contextObj); + ::glFramebufferTexture2DEXT(target, attachment, textarget, (GLuint) texture->object(), level); +} + +void GraphicsContext3D::frontFace(unsigned long mode) +{ + ensureContext(m_contextObj); + ::glFrontFace(mode); +} + +void GraphicsContext3D::generateMipmap(unsigned long target) +{ + ensureContext(m_contextObj); + ::glGenerateMipmapEXT(target); +} + +int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& name) +{ + if (!program) + return -1; + + ensureContext(m_contextObj); + return ::glGetAttribLocation((GLuint) program->object(), name.utf8().data()); +} + +unsigned long GraphicsContext3D::getError() +{ + 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(CanvasBuffer* 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(CanvasFramebuffer* framebuffer) +{ + if (!framebuffer) + return false; + + ensureContext(m_contextObj); + return ::glIsFramebufferEXT((GLuint) framebuffer->object()); +} + +bool GraphicsContext3D::isProgram(CanvasProgram* program) +{ + if (!program) + return false; + + ensureContext(m_contextObj); + return ::glIsProgram((GLuint) program->object()); +} + +bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer) +{ + if (!renderbuffer) + return false; + + ensureContext(m_contextObj); + return ::glIsRenderbufferEXT((GLuint) renderbuffer->object()); +} + +bool GraphicsContext3D::isShader(CanvasShader* shader) +{ + if (!shader) + return false; + + ensureContext(m_contextObj); + return ::glIsShader((GLuint) shader->object()); +} + +bool GraphicsContext3D::isTexture(CanvasTexture* 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(CanvasProgram* program) +{ + if (!program) + return; + + 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)); +} + +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(CanvasShader* shader, const String& string) +{ + if (!shader) + return; + + 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(CanvasProgram* program) +{ + if (!program) + return; + + ensureContext(m_contextObj); + ::glUseProgram((GLuint) program->object()); +} + +void GraphicsContext3D::validateProgram(CanvasProgram* program) +{ + if (!program) + return; + + 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)); +} + +static int sizeForGetParam(unsigned long pname) +{ + switch(pname) { + case GL_ACTIVE_TEXTURE: return 1; + case GL_ALIASED_LINE_WIDTH_RANGE: return 2; + case GL_ALIASED_POINT_SIZE_RANGE: return 2; + case GL_ALPHA_BITS: return 1; + case GL_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) + case GL_BLEND: return 1; + case GL_BLEND_COLOR: return 4; + case GL_BLEND_DST_ALPHA: return 1; + case GL_BLEND_DST_RGB: return 1; + case GL_BLEND_EQUATION_ALPHA: return 1; + case GL_BLEND_EQUATION_RGB: return 1; + case GL_BLEND_SRC_ALPHA: return 1; + case GL_BLEND_SRC_RGB: return 1; + case GL_BLUE_BITS: return 1; + case GL_COLOR_CLEAR_VALUE: return 4; + case GL_COLOR_WRITEMASK: return 4; + case GL_COMPRESSED_TEXTURE_FORMATS: return GL_NUM_COMPRESSED_TEXTURE_FORMATS; + case GL_CULL_FACE: return 1; + case GL_CULL_FACE_MODE: return 1; + case GL_CURRENT_PROGRAM: return 1; // (* actually a CanvasProgram*) + case GL_DEPTH_BITS: return 1; + case GL_DEPTH_CLEAR_VALUE: return 1; + case GL_DEPTH_FUNC: return 1; + case GL_DEPTH_RANGE: return 2; + case GL_DEPTH_TEST: return 1; + case GL_DEPTH_WRITEMASK: return 1; + case GL_DITHER: return 1; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) + case GL_FRAMEBUFFER_BINDING_EXT: return 1; // (* actually a CanvasFramebuffer*) + case GL_FRONT_FACE: return 1; + case GL_GENERATE_MIPMAP_HINT: return 1; + case GL_GREEN_BITS: return 1; + //case GL_IMPLEMENTATION_COLOR_READ_FORMAT:return 1; + //case GL_IMPLEMENTATION_COLOR_READ_TYPE: return 1; + case GL_LINE_WIDTH: return 1; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:return 1; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: return 1; + //case GL_MAX_FRAGMENT_UNIFORM_VECTORS: return 1; + case GL_MAX_RENDERBUFFER_SIZE_EXT: return 1; + case GL_MAX_TEXTURE_IMAGE_UNITS: return 1; + case GL_MAX_TEXTURE_SIZE: return 1; + //case GL_MAX_VARYING_VECTORS: return 1; + case GL_MAX_VERTEX_ATTRIBS: return 1; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: return 1; + //case GL_MAX_VERTEX_UNIFORM_VECTORS: return 1; + case GL_MAX_VIEWPORT_DIMS: return 2; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: return 1; + //case GL_NUM_SHADER_BINARY_FORMATS: return 1; + case GL_PACK_ALIGNMENT: return 1; + case GL_POLYGON_OFFSET_FACTOR: return 1; + case GL_POLYGON_OFFSET_FILL: return 1; + case GL_POLYGON_OFFSET_UNITS: return 1; + case GL_RED_BITS: return 1; + case GL_RENDERBUFFER_BINDING_EXT: return 1; // (* actually a CanvasRenderbuffer*) + case GL_SAMPLE_BUFFERS: return 1; + case GL_SAMPLE_COVERAGE_INVERT: return 1; + case GL_SAMPLE_COVERAGE_VALUE: return 1; + case GL_SAMPLES: return 1; + case GL_SCISSOR_BOX: return 4; + case GL_SCISSOR_TEST: return 1; + //case GL_SHADER_BINARY_FORMATS: return GL_NUM_SHADER_BINARY_FORMATS; + //case GL_SHADER_COMPILER: return 1; + case GL_STENCIL_BACK_FAIL: return 1; + case GL_STENCIL_BACK_FUNC: return 1; + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: return 1; + case GL_STENCIL_BACK_PASS_DEPTH_PASS: return 1; + case GL_STENCIL_BACK_REF: return 1; + case GL_STENCIL_BACK_VALUE_MASK: return 1; + case GL_STENCIL_BACK_WRITEMASK: return 1; + case GL_STENCIL_BITS: return 1; + case GL_STENCIL_CLEAR_VALUE: return 1; + case GL_STENCIL_FAIL: return 1; + case GL_STENCIL_FUNC: return 1; + case GL_STENCIL_PASS_DEPTH_FAIL: return 1; + case GL_STENCIL_PASS_DEPTH_PASS: return 1; + case GL_STENCIL_REF: return 1; + case GL_STENCIL_TEST: return 1; + case GL_STENCIL_VALUE_MASK: return 1; + case GL_STENCIL_WRITEMASK: return 1; + case GL_SUBPIXEL_BITS: return 1; + case GL_TEXTURE_BINDING_2D: return 1; // (* actually a CanvasTexture*) + case GL_TEXTURE_BINDING_CUBE_MAP: return 1; // (* actually a CanvasTexture*) + case GL_UNPACK_ALIGNMENT: return 1; + case GL_VIEWPORT: return 4; + } + + return -1; +} + +bool GraphicsContext3D::getBoolean(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + bool isAlloced = false; + GLboolean buf[4]; + GLboolean* pbuf = buf; + + if (size > 4) { + pbuf = (GLboolean*) malloc(size * sizeof(GLboolean)); + isAlloced = true; + } + + ::glGetBooleanv(pname, pbuf); + + bool value = pbuf[0]; + + if (isAlloced) + free(pbuf); + + return value; +} + +PassRefPtr<CanvasUnsignedByteArray> GraphicsContext3D::getBooleanv(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(size); + bool isAlloced = false; + GLboolean buf[4]; + GLboolean* pbuf = buf; + + if (size > 4) { + pbuf = (GLboolean*) malloc(size * sizeof(GLboolean)); + isAlloced = true; + } + + ::glGetBooleanv(pname, pbuf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<unsigned char>(pbuf[i])); + + if (isAlloced) + free(pbuf); + + return array; +} + +float GraphicsContext3D::getFloat(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + bool isAlloced = false; + GLfloat buf[4]; + GLfloat* pbuf = buf; + + if (size > 4) { + pbuf = (GLfloat*) malloc(size * sizeof(GLfloat)); + isAlloced = true; + } + + ::glGetFloatv(pname, pbuf); + + float value = pbuf[0]; + + if (isAlloced) + free(pbuf); + + return value; +} + +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getFloatv(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size); + bool isAlloced = false; + GLfloat buf[4]; + GLfloat* pbuf = buf; + + if (size > 4) { + pbuf = (GLfloat*) malloc(size * sizeof(GLfloat)); + isAlloced = true; + } + + ::glGetFloatv(pname, pbuf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<float>(pbuf[i])); + + if (isAlloced) + free(pbuf); + + return array; +} + +int GraphicsContext3D::getInteger(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + bool isAlloced = false; + GLint buf[4]; + GLint* pbuf = buf; + + if (size > 4) { + pbuf = (GLint*) malloc(size * sizeof(GLint)); + isAlloced = true; + } + + ::glGetIntegerv(pname, pbuf); + + int value = pbuf[0]; + + if (isAlloced) + free(pbuf); + + return value; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getIntegerv(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasIntArray> array = CanvasIntArray::create(size); + bool isAlloced = false; + GLint buf[4]; + GLint* pbuf = buf; + + if (size > 4) { + pbuf = (GLint*) malloc(size * sizeof(GLint)); + isAlloced = true; + } + + ::glGetIntegerv(pname, pbuf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<int>(pbuf[i])); + + if (isAlloced) + free(pbuf); + + return array; +} + +int GraphicsContext3D::getBufferParameteri(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetBufferParameteriv(target, pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetBufferParameteriv(target, pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +int GraphicsContext3D::getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +int GraphicsContext3D::getProgrami(CanvasProgram* program, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetProgramiv((GLuint) program->object(), pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getProgramiv(CanvasProgram* program, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetProgramiv((GLuint) program->object(), pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +String GraphicsContext3D::getProgramInfoLog(CanvasProgram* program) +{ + if (!program) + return String(); + + ensureContext(m_contextObj); + GLint length; + ::glGetProgramiv((GLuint) program->object(), GL_INFO_LOG_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) malloc(length); + ::glGetProgramInfoLog((GLuint) program->object(), length, &size, info); + String s(info); + free(info); + return s; +} + +int GraphicsContext3D::getRenderbufferParameteri(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetBufferParameteriv(target, pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetBufferParameteriv(target, pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +int GraphicsContext3D::getShaderi(CanvasShader* shader, unsigned long pname) +{ + if (!shader) + return 0; + + ensureContext(m_contextObj); + GLint data; + ::glGetShaderiv((GLuint) shader->object(), pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getShaderiv(CanvasShader* shader, unsigned long pname) +{ + if (!shader) + return 0; + + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetShaderiv((GLuint) shader->object(), pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +String GraphicsContext3D::getShaderInfoLog(CanvasShader* shader) +{ + if (!shader) + return String(); + + ensureContext(m_contextObj); + GLint length; + ::glGetShaderiv((GLuint) shader->object(), GL_INFO_LOG_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) malloc(length); + ::glGetShaderInfoLog((GLuint) shader->object(), length, &size, info); + String s(info); + free(info); + return s; +} + +String GraphicsContext3D::getShaderSource(CanvasShader* shader) +{ + if (!shader) + return String(); + + ensureContext(m_contextObj); + GLint length; + ::glGetShaderiv((GLuint) shader->object(), GL_SHADER_SOURCE_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) malloc(length); + ::glGetShaderSource((GLuint) shader->object(), length, &size, info); + String s(info); + free(info); + return s; +} + + +float GraphicsContext3D::getTexParameterf(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + GLfloat data; + ::glGetTexParameterfv(target, pname, &data); + return data; +} + +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(1); + GLfloat data; + ::glGetTexParameterfv(target, pname, &data); + array->set(0, static_cast<float>(data)); + + return array; +} + +int GraphicsContext3D::getTexParameteri(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetTexParameteriv(target, pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetTexParameteriv(target, pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +float GraphicsContext3D::getUniformf(CanvasProgram* program, long location) +{ + // FIXME: We need to query glGetUniformLocation to determine the size needed + UNUSED_PARAM(program); + UNUSED_PARAM(location); + notImplemented(); + return 0; +} + +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getUniformfv(CanvasProgram* program, long location) +{ + // FIXME: We need to query glGetUniformLocation to determine the size needed + UNUSED_PARAM(program); + UNUSED_PARAM(location); + notImplemented(); + return 0; +} + +int GraphicsContext3D::getUniformi(CanvasProgram* program, long location) +{ + // FIXME: We need to query glGetUniformLocation to determine the size needed + UNUSED_PARAM(program); + UNUSED_PARAM(location); + notImplemented(); + return 0; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getUniformiv(CanvasProgram* program, long location) +{ + // FIXME: We need to query glGetUniformLocation to determine the size needed + UNUSED_PARAM(program); + UNUSED_PARAM(location); + notImplemented(); + return 0; +} + +long GraphicsContext3D::getUniformLocation(CanvasProgram* program, const String& name) +{ + if (!program) + return -1; + + ensureContext(m_contextObj); + return ::glGetUniformLocation((GLuint) program->object(), name.utf8().data()); +} + +static int sizeForGetVertexAttribParam(unsigned long pname) +{ + switch(pname) { + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: return 1; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: return 1; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: return 1; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: return 1; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: return 1; + case GL_CURRENT_VERTEX_ATTRIB: return 4; + } + + return -1; +} + +float GraphicsContext3D::getVertexAttribf(unsigned long index, unsigned long pname) +{ + ensureContext(m_contextObj); + GLfloat buf[4]; + ::glGetVertexAttribfv(index, pname, buf); + return buf[0]; +} + +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname) +{ + int size = sizeForGetVertexAttribParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size); + GLfloat buf[4]; + ::glGetVertexAttribfv(index, pname, buf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<float>(buf[i])); + + return array; +} + +int GraphicsContext3D::getVertexAttribi(unsigned long index, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint buf[4]; + ::glGetVertexAttribiv(index, pname, buf); + return buf[0]; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname) +{ + int size = sizeForGetVertexAttribParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasIntArray> array = CanvasIntArray::create(size); + GLint buf[4]; + ::glGetVertexAttribiv(index, pname, buf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<int>(buf[i])); + + return array; +} + +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*) malloc(textureWidth * textureHeight * 4); + CGContextRef textureContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, 8, textureWidth * 4, + CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast); + + 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); + free(textureData); +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, CanvasArray* 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, HTMLImageElement* image, bool flipY, bool premultiplyAlpha) +{ + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + + if (!image) + return -1; + + ensureContext(m_contextObj); + CachedImage* cachedImage = image->cachedImage(); + if (!cachedImage) + return -1; + + imageToTexture(cachedImage->image(), target, level); + return 0; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha) +{ + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + + if (!canvas) + return -1; + + ensureContext(m_contextObj); + ImageBuffer* buffer = canvas->buffer(); + if (!buffer) + return -1; + + imageToTexture(buffer->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, CanvasArray* 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, HTMLImageElement* 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, HTMLCanvasElement* canvas, 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(canvas); + + // 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(ShaderType 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; + } +} + +} + +#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..d0e1108 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -62,6 +62,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 +88,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,6 +104,9 @@ public: virtual void setContentsToImage(Image*); virtual void setContentsToVideo(PlatformLayer*); +#if ENABLE(3D_CANVAS) + virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*); +#endif virtual PlatformLayer* platformLayer() const; @@ -170,8 +179,12 @@ private: void updateContentsImage(); void updateContentsVideo(); +#if ENABLE(3D_CANVAS) + void updateContentsGraphicsContext3D(); +#endif void updateContentsRect(); void updateGeometryOrientation(); + void updateMaskLayer(); void updateLayerAnimations(); @@ -199,8 +212,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 +232,9 @@ private: NoContentsLayer = 0, ContentsLayerForImage, ContentsLayerForVideo +#if ENABLE(3D_CANVAS) + ,ContentsLayerForGraphicsLayer3D +#endif }; ContentsLayerPurpose m_contentsLayerPurpose; @@ -260,6 +280,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..e9960f1 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" @@ -145,11 +148,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 +160,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 +217,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; } @@ -331,7 +350,7 @@ static NSDictionary* nullActionsDictionary() return actions; } -GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client) +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) { return new GraphicsLayerCA(client); } @@ -341,6 +360,10 @@ GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* 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]); @@ -432,6 +455,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 +704,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 +765,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 +798,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 +852,9 @@ void GraphicsLayerCA::commitLayerChanges() if (m_uncommittedChanges & GeometryOrientationChanged) updateGeometryOrientation(); + if (m_uncommittedChanges & MaskLayerChanged) + updateMaskLayer(); + m_uncommittedChanges = NoChange; END_BLOCK_OBJC_EXCEPTIONS } @@ -821,10 +864,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]; } @@ -1061,6 +1106,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 +1151,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()) { @@ -1247,6 +1310,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()) @@ -1765,6 +1862,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/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..0a63626 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(); @@ -104,7 +108,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..30d0c82 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,28 @@ 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 +{ + return true; +} + void MediaPlayerPrivate::setVolume(float volume) { - if (!metaDataAvailable()) - return; - [m_qtMovie.get() setVolume:volume]; + if (m_qtMovie) + [m_qtMovie.get() setVolume:volume]; } 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 +777,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 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/opentype/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index 895887f..b2e3d92 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,8 +398,42 @@ 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) { RemoveFontMemResourceEx(fontHandle); @@ -404,5 +442,6 @@ HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) 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..1113eae 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -48,7 +48,7 @@ FontCache::FontCache() { } -void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&) { } @@ -58,8 +58,8 @@ class FontPlatformDataCacheKey { public: FontPlatformDataCacheKey(const FontDescription& description) : m_familyName() - , m_bold(false) , m_size(description.computedPixelSize()) + , m_bold(false) , m_italic(description.italic()) , m_smallCaps(description.smallCaps()) , m_hash(0) @@ -177,7 +177,7 @@ typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCac // 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) +FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString&, bool) { if (!gFontPlatformDataCache) gFontPlatformDataCache = new FontPlatformDataCache; diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp index c29fd56..8e1e4f6 100644 --- a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp +++ b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp @@ -130,7 +130,7 @@ const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* fon return primaryFontData(font); } -void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData& platformData) +void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData&) { m_familyIndex = cAllFamiliesScanned; } diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index e8eb923..c5960ac 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -197,7 +197,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()); diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index e259a4e..fa7b070 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; @@ -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,50 @@ 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.fillColorSpace != SolidColorSpace) + || (fillColor().alpha())) { + drawFilledShadowPath(this, p, &path); + 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; + } } m_data->currentPath = QPainterPath(); } @@ -642,59 +667,88 @@ 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.strokeColorSpace != SolidColorSpace) + || (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); + } + switch (m_common->state.strokeColorSpace) { + case SolidColorSpace: + if (strokeColor().alpha()) + 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 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; - } + 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; + } + } } 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.fillColorSpace != SolidColorSpace) + || (fillColor().alpha())) { + drawBorderlessRectShadow(this, p, rect); + 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; + } } - m_data->currentPath = QPainterPath(); } void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) @@ -702,8 +756,10 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) 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) @@ -712,7 +768,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef 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 +808,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 +827,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 +851,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 +860,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 +869,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 +886,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&) { // 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 +911,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 +934,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 +952,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 +979,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 +1011,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 +1022,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 +1032,7 @@ void GraphicsContext::setAlpha(float opacity) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); p->setOpacity(opacity); } @@ -995,15 +1058,19 @@ 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 +1128,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 +1150,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 +1190,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,7 +1215,7 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform) } } -void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +void GraphicsContext::setURLForRect(const KURL&, const IntRect&) { notImplemented(); } @@ -1143,7 +1224,7 @@ void GraphicsContext::setPlatformStrokeColor(const Color& color) { 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 +1234,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,7 +1244,7 @@ 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); @@ -1184,7 +1265,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..98f4606 100644 --- a/WebCore/platform/graphics/qt/IconQt.cpp +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -47,7 +47,7 @@ PassRefPtr<Icon> Icon::createIconForFile(const String& filename) return i.release(); } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) { //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..3a27fe3 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -35,150 +35,9 @@ #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 }; - - // 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); - - QImageReader *reader() { return &m_reader; } -private: - enum IncrementalReadResult { IncrementalReadFailed, IncrementalReadPartial, IncrementalReadComplete }; - // Incrementally read an image - IncrementalReadResult readImageLines(ImageData &); - - const LoadMode m_loadMode; - - QByteArray m_data; - QBuffer m_buffer; - QImageReader m_reader; - - ImageList &m_target; - - // Detected data format of the stream - enum QImage::Format m_dataFormat; - QSize m_size; - -}; - -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) -{ - m_buffer.open(QIODevice::ReadOnly); -} - - -ImageDecoderQt::ReadContext::ReadResult - ImageDecoderQt::ReadContext::read(bool allDataReceived) -{ - // 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)); - } - - // 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; - } - } - return ReadComplete; -} - - - -ImageDecoderQt::ReadContext::IncrementalReadResult - ImageDecoderQt::ReadContext::readImageLines(ImageData &imageData) -{ - // 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; -} - -ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data) +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) @@ -189,149 +48,196 @@ ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data) if (!buffer.open(QBuffer::ReadOnly)) return 0; - QString imageFormat = QString::fromLatin1(QImageReader::imageFormat(&buffer).toLower()); + QByteArray imageFormat = QImageReader::imageFormat(&buffer); if (imageFormat.isEmpty()) return 0; // Image format not supported return new ImageDecoderQt(imageFormat); } -ImageDecoderQt::ImageDecoderQt(const QString &imageFormat) - : m_hasAlphaChannel(false) - , m_imageFormat(imageFormat) +ImageDecoderQt::ImageDecoderQt(const QByteArray& imageFormat) + : m_buffer(0) + , m_reader(0) + , m_repetitionCount(-1) { } ImageDecoderQt::~ImageDecoderQt() { + delete m_reader; + delete m_buffer; } -bool ImageDecoderQt::hasFirstImageHeader() const +void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) { - return !m_imageList.empty() && m_imageList[0].m_imageState >= ImageHeaderValid; -} + if (m_failed) + return; -void ImageDecoderQt::reset() -{ - m_hasAlphaChannel = false; - m_failed = false; - m_imageList.clear(); - m_pixmapCache.clear(); - m_loopCount = cAnimationNone; -} + // Cache our own new data. + ImageDecoder::setData(data, allDataReceived); -void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) -{ - 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; - } -} + // No progressive loading possible + if (!allDataReceived) + return; + + // 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); + + if (!m_reader->canRead()) + failRead(); +} bool ImageDecoderQt::isSizeAvailable() { - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << ImageDecoder::isSizeAvailable(); + if (!m_failed && !ImageDecoder::isSizeAvailable() && m_reader) + internalDecodeSize(); + return ImageDecoder::isSizeAvailable(); } -size_t ImageDecoderQt::frameCount() const +size_t ImageDecoderQt::frameCount() { - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::frameCount() returns" << m_imageList.size(); - return m_imageList.size(); + if (m_frameBufferCache.isEmpty() && m_reader) { + if (m_reader->supportsAnimation()) { + int imageCount = m_reader->imageCount(); + + // 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 m_frameBufferCache.size(); } int ImageDecoderQt::repetitionCount() const { - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::repetitionCount() returns" << m_loopCount; - return m_loopCount; + if (m_reader && m_reader->supportsAnimation()) + m_repetitionCount = qMax(0, m_reader->loopCount()); + + return m_repetitionCount; } -bool ImageDecoderQt::supportsAlpha() const +String ImageDecoderQt::filenameExtension() const { - return m_hasAlphaChannel; -} + return m_format; +}; -int ImageDecoderQt::duration(size_t index) const +RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) { - if (index >= m_imageList.size()) + // this information might not have been set + int count = m_frameBufferCache.size(); + if (count == 0) { + internalDecodeSize(); + count = frameCount(); + } + + if (index >= static_cast<size_t>(count)) return 0; - return m_imageList[index].m_duration; + + RGBA32Buffer& frame = m_frameBufferCache[index]; + if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) + internalReadImage(index); + return &frame; } -String ImageDecoderQt::filenameExtension() const +void ImageDecoderQt::clearFrameBufferCache(size_t index) { - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::filenameExtension() returns" << m_imageFormat; - return m_imageFormat; -}; + // Currently QImageReader will be asked to read everything. This + // might change when we read gif images on demand. For now we + // can have a rather simple implementation. + if (index > m_frameBufferCache.size()) + return; -RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) + for (size_t i = 0; i < index; ++index) + m_frameBufferCache[index].clear(); +} + +void ImageDecoderQt::internalDecodeSize() { - Q_ASSERT("use imageAtIndex instead"); - return 0; + ASSERT(m_reader); + + QSize size = m_reader->size(); + setSize(size.width(), size.height()); } -QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const +void ImageDecoderQt::internalReadImage(size_t frameIndex) { - if (debugImageDecoderQt) - qDebug() << "ImageDecoderQt::imageAtIndex(" << index << ')'; + ASSERT(m_reader); - if (index >= m_imageList.size()) - return 0; + if (m_reader->supportsAnimation()) + m_reader->jumpToImage(frameIndex); + else if (frameIndex != 0) + return failRead(); - if (!m_pixmapCache.contains(index)) { - m_pixmapCache.insert(index, - QPixmap::fromImage(m_imageList[index].m_image)); + internalHandleCurrentImage(frameIndex); - // 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]; + // Attempt to return some memory + for (int i = 0; i < m_frameBufferCache.size(); ++i) + if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete) + return; + + delete m_reader; + delete m_buffer; + m_buffer = 0; + m_reader = 0; } -void ImageDecoderQt::clearFrame(size_t index) +void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) { - if (m_imageList.size() < (int)index) - m_imageList[index].m_image = QImage(); - m_pixmapCache.take(index); + // Now get the QImage from Qt and place it in the RGBA32Buffer + QImage img; + if (!m_reader->read(&img)) + return failRead(); + + // 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); } +// We will parse everything and we have no idea how +// many images we have... We will have to find out the +// hard way. +void ImageDecoderQt::forceLoadEverything() +{ + int imageCount = 0; + + do { + m_frameBufferCache.resize(++imageCount); + internalHandleCurrentImage(imageCount - 1); + } while(!m_failed); + + // reset the failed state and resize the vector... + m_frameBufferCache.resize(imageCount - 1); + m_failed = false; +} + +void ImageDecoderQt::failRead() +{ + 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..7b3b686 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(const QByteArray& imageFormat); ~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: + String 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..da6ddac 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -76,6 +76,7 @@ bool FrameData::clear(bool clearMetadata) m_haveMetadata = false; if (m_frame) { + delete m_frame; m_frame = 0; return true; } 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..7078d16 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; @@ -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.h b/WebCore/platform/graphics/qt/StillImageQt.h index 2b2c1f7..6c417b1 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.h +++ b/WebCore/platform/graphics/qt/StillImageQt.h @@ -41,7 +41,7 @@ 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; 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..c9f1349 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,7 +293,7 @@ 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)); + r.inset(SkIntToScalar(thickness), SkIntToScalar(thickness)); path.addOval(r, SkPath::kCCW_Direction); } platformContext()->canvas()->clipPath(path); @@ -403,6 +403,9 @@ 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); } @@ -487,7 +490,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 +524,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 +558,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); } @@ -844,9 +825,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 +900,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++) @@ -990,8 +971,8 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, 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; } diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 7935ff1..a5c8926 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; @@ -118,16 +119,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 +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,11 +149,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 +162,21 @@ 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 = SkPMColorToColor(srcRow[x]); + destPixel[0] = SkColorGetR(color); + destPixel[1] = SkColorGetG(color); + destPixel[2] = SkColorGetB(color); + destPixel[3] = SkColorGetA(color); + } 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 +184,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 +204,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 +235,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..ecab364 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); } 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/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index e0a292c..1fb62fc 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -46,6 +46,11 @@ #include <wtf/MathExtras.h> +namespace WebCore +{ +extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path); +} + // State ----------------------------------------------------------------------- // Encapsulates the additional painting state information we store for each @@ -278,6 +283,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 +301,7 @@ void PlatformContextSkia::drawRect(SkRect rect) void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const { -#ifdef SK_DEBUGx +#if defined(SK_DEBUG) { SkPaint defaultPaint; SkASSERT(*paint == defaultPaint); diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index 803f5db..e2ed130 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); 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..1923ecc 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -65,7 +65,7 @@ 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) { @@ -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/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp index 8a8e943..285fb71 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); diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp index 591375f..0b27438 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); diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index eb7334e..15e1001 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) @@ -268,10 +324,14 @@ int MediaPlayerPrivate::dataRate() const 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 +635,3 @@ bool MediaPlayerPrivate::hasSingleSecurityOrigin() const } #endif - diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index f584148..4a3a28e 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -52,7 +52,8 @@ public: IntSize naturalSize() const; bool hasVideo() const; - + bool hasAudio() const; + void load(const String& url); void cancelLoad(); @@ -76,7 +77,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; diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp index aaa61f1..56f3d0b 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -62,10 +62,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 +76,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 +169,7 @@ QTMovieWinPrivate::~QTMovieWinPrivate() CFRelease(m_currentURL); } -static void taskTimerFired() +void QTMovieWin::taskTimerFired() { // The hash content might change during task() Vector<QTMovieWinPrivate*> tasks; @@ -867,6 +870,13 @@ 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)); +} + pascal OSErr movieDrawingCompleteProc(Movie movie, long data) { UppParam param; @@ -990,6 +1000,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 +1025,6 @@ bool QTMovieWin::initializeQuickTime() return false; } EnterMovies(); - setSharedTimerFiredFunction(taskTimerFired); gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc); initializationSucceeded = true; } @@ -1020,7 +1035,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..d178eb8 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,7 @@ public: void setDisabled(bool); bool hasVideo() const; + bool hasAudio() const; 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..26b22af 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp @@ -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/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/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..9673d18 --- /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 "c_class.h" +#include "c_instance.h" +#include "c_runtime.h" +#include "DocumentLoader.h" +#include "HTMLPlugInElement.h" +#include "HTMLVideoElement.h" +#include "JSDOMBinding.h" +#include "JSPluginElementFunctions.h" +#include "MediaPlayer.h" +#include "Node.h" +#include "npruntime_impl.h" +#include "PlatformString.h" +#include "PluginView.h" +#include "RenderPartObject.h" +#include "RenderWidget.h" +#include "runtime.h" +#include <runtime/Identifier.h> +#include "Widget.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/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 59e388e..686fb07 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -506,4 +506,59 @@ void GraphicsContext::fillRect(const FloatRect& rect) return; } +void GraphicsContext::setPlatformShadow(IntSize const&,int,Color const&) +{ + 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(); +} + } diff --git a/WebCore/platform/graphics/wx/IconWx.cpp b/WebCore/platform/graphics/wx/IconWx.cpp new file mode 100644 index 0000000..e82091e --- /dev/null +++ b/WebCore/platform/graphics/wx/IconWx.cpp @@ -0,0 +1,53 @@ +/* + * 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::createIconForFile(const String& filename) +{ + notImplemented(); + return 0; +} + +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..bd129cf 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); @@ -261,4 +261,9 @@ void BitmapImage::invalidatePlatformData() } +void Image::drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, 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); +} + +} |