diff options
author | Steve Block <steveblock@google.com> | 2010-04-27 16:31:00 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-05-11 14:42:12 +0100 |
commit | dcc8cf2e65d1aa555cce12431a16547e66b469ee (patch) | |
tree | 92a8d65cd5383bca9749f5327fb5e440563926e6 /WebCore/platform/graphics | |
parent | ccac38a6b48843126402088a309597e682f40fe6 (diff) | |
download | external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.zip external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.gz external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.bz2 |
Merge webkit.org at r58033 : Initial merge by git
Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1
Diffstat (limited to 'WebCore/platform/graphics')
191 files changed, 9037 insertions, 1529 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp index 0cd3907..e3db752 100644 --- a/WebCore/platform/graphics/BitmapImage.cpp +++ b/WebCore/platform/graphics/BitmapImage.cpp @@ -270,6 +270,11 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary) if (m_frameTimer || !shouldAnimate() || frameCount() <= 1) return; + // If we aren't already animating, set now as the animation start time. + const double time = currentTime(); + if (!m_desiredFrameStartTime) + m_desiredFrameStartTime = time; + // Don't advance the animation to an incomplete frame. size_t nextFrame = (m_currentFrame + 1) % frameCount(); if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame)) @@ -286,19 +291,14 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary) // in this calculation, we make the animation appear to run at its desired // rate regardless of how fast it's being repainted. const double currentDuration = frameDurationAtIndex(m_currentFrame); - const double time = currentTime(); - if (m_desiredFrameStartTime == 0) { + m_desiredFrameStartTime += currentDuration; + + // When an animated image is more than five minutes out of date, the + // user probably doesn't care about resyncing and we could burn a lot of + // time looping through frames below. Just reset the timings. + const double cAnimationResyncCutoff = 5 * 60; + if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff) m_desiredFrameStartTime = time + currentDuration; - } else { - m_desiredFrameStartTime += currentDuration; - - // When an animated image is more than five minutes out of date, the - // user probably doesn't care about resyncing and we could burn a lot of - // time looping through frames below. Just reset the timings. - const double cAnimationResyncCutoff = 5 * 60; - if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff) - m_desiredFrameStartTime = time + currentDuration; - } // The image may load more slowly than it's supposed to animate, so that by // the time we reach the end of the first repetition, we're well behind. @@ -311,7 +311,7 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary) // switch tabs (and thus stop drawing the animation, which will pause it) // during that initial loop, then switch back later. if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time) - m_desiredFrameStartTime = time; + m_desiredFrameStartTime = time; if (!catchUpIfNecessary || time < m_desiredFrameStartTime) { // Haven't yet reached time for next frame to start; delay until then. diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h index c348166..b8d19e0 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -27,7 +27,6 @@ #define Color_h #include <wtf/FastAllocBase.h> -#include <wtf/Platform.h> #if PLATFORM(CG) typedef struct CGColor* CGColorRef; diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h index bf568d4..7443e97 100644 --- a/WebCore/platform/graphics/FloatPoint.h +++ b/WebCore/platform/graphics/FloatPoint.h @@ -30,7 +30,6 @@ #include "FloatSize.h" #include "IntPoint.h" #include <wtf/MathExtras.h> -#include <wtf/Platform.h> #if PLATFORM(CG) typedef struct CGPoint CGPoint; @@ -71,6 +70,9 @@ public: FloatPoint(float x, float y) : m_x(x), m_y(y) { } FloatPoint(const IntPoint&); + + static FloatPoint zero() { return FloatPoint(); } + static FloatPoint narrowPrecision(double x, double y); float x() const { return m_x; } diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h index b265121..4c3a382 100644 --- a/WebCore/platform/graphics/FloatRect.h +++ b/WebCore/platform/graphics/FloatRect.h @@ -29,6 +29,10 @@ #include "FloatPoint.h" +#if PLATFORM(EFL) +#include <Evas.h> +#endif + #if PLATFORM(CG) typedef struct CGRect CGRect; #endif @@ -145,6 +149,11 @@ public: operator QRectF() const; #endif +#if PLATFORM(EFL) + explicit FloatRect(const Eina_Rectangle&); + operator Eina_Rectangle() const; +#endif + #if PLATFORM(WX) && USE(WXGC) FloatRect(const wxRect2DDouble&); operator wxRect2DDouble() const; diff --git a/WebCore/platform/graphics/FloatSize.h b/WebCore/platform/graphics/FloatSize.h index a3233d1..97ee00d 100644 --- a/WebCore/platform/graphics/FloatSize.h +++ b/WebCore/platform/graphics/FloatSize.h @@ -30,7 +30,6 @@ #include "IntSize.h" #include <wtf/MathExtras.h> -#include <wtf/Platform.h> #if PLATFORM(CG) typedef struct CGSize CGSize; diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp index 7d0e5a9..7bdefba 100644 --- a/WebCore/platform/graphics/Font.cpp +++ b/WebCore/platform/graphics/Font.cpp @@ -182,7 +182,7 @@ void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoi return drawComplexText(context, run, point, from, to); } -float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) @@ -198,7 +198,7 @@ float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallb } #endif - return floatWidthForComplexText(run, fallbackFonts); + return floatWidthForComplexText(run, fallbackFonts, glyphOverflow); } float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const @@ -267,12 +267,13 @@ FontSelector* Font::fontSelector() const String Font::normalizeSpaces(const String& string) { + const UChar* characters = string.characters(); unsigned length = string.length(); Vector<UChar, 256> buffer(length); bool didReplacement = false; for (unsigned i = 0; i < length; ++i) { - UChar originalCharacter = string[i]; + UChar originalCharacter = characters[i]; buffer[i] = normalizeSpaces(originalCharacter); if (buffer[i] != originalCharacter) didReplacement = true; diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h index 3c07be7..62525b0 100644 --- a/WebCore/platform/graphics/Font.h +++ b/WebCore/platform/graphics/Font.h @@ -56,6 +56,21 @@ struct GlyphData; const unsigned defaultUnitsPerEm = 1000; +struct GlyphOverflow { + GlyphOverflow() + : left(0) + , right(0) + , top(0) + , bottom(0) + { + } + + int left; + int right; + int top; + int bottom; +}; + class Font { public: Font(); @@ -81,8 +96,8 @@ public: void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const; - int width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0) const { return lroundf(floatWidth(run, fallbackFonts)); } - float floatWidth(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; + int width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* glyphOverflow = 0) const { return lroundf(floatWidth(run, fallbackFonts, glyphOverflow)); } + float floatWidth(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* glyphOverflow = 0) const; float floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const; int offsetForPosition(const TextRun&, int position, bool includePartialGlyphs) const; @@ -159,7 +174,7 @@ private: #endif void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; - float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; + float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; int offsetForPositionForComplexText(const TextRun&, int position, bool includePartialGlyphs) const; FloatRect selectionRectForComplexText(const TextRun&, const IntPoint&, int h, int from, int to) const; diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp index 428e85e..6e2a744 100644 --- a/WebCore/platform/graphics/FontFastPath.cpp +++ b/WebCore/platform/graphics/FontFastPath.cpp @@ -24,17 +24,17 @@ #include "Font.h" #include "CharacterNames.h" +#include "FloatRect.h" #include "FontCache.h" #include "FontFallbackList.h" -#include "FloatRect.h" #include "GlyphBuffer.h" #include "GlyphPageTreeNode.h" #include "IntPoint.h" #include "SimpleFontData.h" #include "WidthIterator.h" -#include <wtf/unicode/Unicode.h> #include <wtf/MathExtras.h> +#include <wtf/unicode/Unicode.h> using namespace WTF; using namespace Unicode; @@ -234,6 +234,13 @@ bool Font::canUseGlyphCache(const TextRun& run) const if (c <= 0x194F) return false; + // FIXME: we should not use complex text path for these characters. + + if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics + continue; + if (c <= 0x2000) + return false; + if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols continue; if (c <= 0x20FF) diff --git a/WebCore/platform/graphics/GlyphWidthMap.cpp b/WebCore/platform/graphics/GlyphMetricsMap.cpp index 43cab65..d3c3180 100644 --- a/WebCore/platform/graphics/GlyphWidthMap.cpp +++ b/WebCore/platform/graphics/GlyphMetricsMap.cpp @@ -27,14 +27,14 @@ */ #include "config.h" -#include "GlyphWidthMap.h" +#include "GlyphMetricsMap.h" namespace WebCore { -GlyphWidthMap::GlyphWidthPage* GlyphWidthMap::locatePageSlowCase(unsigned pageNumber) +GlyphMetricsMap::GlyphMetricsPage* GlyphMetricsMap::locatePageSlowCase(unsigned pageNumber) { - GlyphWidthPage* page; - if (pageNumber == 0) { + GlyphMetricsPage* page; + if (!pageNumber) { ASSERT(!m_filledPrimaryPage); page = &m_primaryPage; m_filledPrimaryPage = true; @@ -43,14 +43,18 @@ GlyphWidthMap::GlyphWidthPage* GlyphWidthMap::locatePageSlowCase(unsigned pageNu if ((page = m_pages->get(pageNumber))) return page; } else - m_pages.set(new HashMap<int, GlyphWidthPage*>); - page = new GlyphWidthPage; + m_pages.set(new HashMap<int, GlyphMetricsPage*>); + page = new GlyphMetricsPage; m_pages->set(pageNumber, page); } - // Fill in the whole page with the unknown glyph width value. - for (unsigned i = 0; i < GlyphWidthPage::size; i++) - page->setWidthForIndex(i, cGlyphWidthUnknown); + GlyphMetrics unknownMetrics; + unknownMetrics.horizontalAdvance = cGlyphSizeUnknown; + unknownMetrics.boundingBox.setWidth(cGlyphSizeUnknown); + unknownMetrics.boundingBox.setHeight(cGlyphSizeUnknown); + // Fill in the whole page with the unknown glyph information. + for (unsigned i = 0; i < GlyphMetricsPage::size; i++) + page->setMetricsForIndex(i, unknownMetrics); return page; } diff --git a/WebCore/platform/graphics/GlyphWidthMap.h b/WebCore/platform/graphics/GlyphMetricsMap.h index 66dea1f..49854be 100644 --- a/WebCore/platform/graphics/GlyphWidthMap.h +++ b/WebCore/platform/graphics/GlyphMetricsMap.h @@ -26,9 +26,10 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GlyphWidthMap_h -#define GlyphWidthMap_h +#ifndef GlyphMetricsMap_h +#define GlyphMetricsMap_h +#include "FloatRect.h" #include <wtf/HashMap.h> #include <wtf/OwnPtr.h> #include <wtf/unicode/Unicode.h> @@ -37,53 +38,67 @@ namespace WebCore { typedef unsigned short Glyph; -const float cGlyphWidthUnknown = -1; +const float cGlyphSizeUnknown = -1; -class GlyphWidthMap : public Noncopyable { +struct GlyphMetrics { + float horizontalAdvance; + FloatRect boundingBox; +}; + +class GlyphMetricsMap : public Noncopyable { public: - GlyphWidthMap() : m_filledPrimaryPage(false) { } - ~GlyphWidthMap() { if (m_pages) { deleteAllValues(*m_pages); } } + GlyphMetricsMap() : m_filledPrimaryPage(false) { } + ~GlyphMetricsMap() + { + if (m_pages) + deleteAllValues(*m_pages); + } + + GlyphMetrics metricsForGlyph(Glyph glyph) + { + return locatePage(glyph / GlyphMetricsPage::size)->metricsForGlyph(glyph); + } float widthForGlyph(Glyph glyph) { - return locatePage(glyph / GlyphWidthPage::size)->widthForGlyph(glyph); + return locatePage(glyph / GlyphMetricsPage::size)->metricsForGlyph(glyph).horizontalAdvance; } - void setWidthForGlyph(Glyph glyph, float width) + void setMetricsForGlyph(Glyph glyph, const GlyphMetrics& metrics) { - locatePage(glyph / GlyphWidthPage::size)->setWidthForGlyph(glyph, width); + locatePage(glyph / GlyphMetricsPage::size)->setMetricsForGlyph(glyph, metrics); } private: - struct GlyphWidthPage { + struct GlyphMetricsPage { static const size_t size = 256; // Usually covers Latin-1 in a single page. - float m_widths[size]; + GlyphMetrics m_metrics[size]; - float widthForGlyph(Glyph glyph) const { return m_widths[glyph % size]; } - void setWidthForGlyph(Glyph glyph, float width) + GlyphMetrics metricsForGlyph(Glyph glyph) const { return m_metrics[glyph % size]; } + void setMetricsForGlyph(Glyph glyph, const GlyphMetrics& metrics) { - setWidthForIndex(glyph % size, width); + setMetricsForIndex(glyph % size, metrics); } - void setWidthForIndex(unsigned index, float width) + void setMetricsForIndex(unsigned index, const GlyphMetrics& metrics) { - m_widths[index] = width; + m_metrics[index] = metrics; } }; - GlyphWidthPage* locatePage(unsigned pageNumber) + GlyphMetricsPage* locatePage(unsigned pageNumber) { if (!pageNumber && m_filledPrimaryPage) return &m_primaryPage; return locatePageSlowCase(pageNumber); } - GlyphWidthPage* locatePageSlowCase(unsigned pageNumber); + GlyphMetricsPage* locatePageSlowCase(unsigned pageNumber); bool m_filledPrimaryPage; - GlyphWidthPage m_primaryPage; // We optimize for the page that contains glyph indices 0-255. - OwnPtr<HashMap<int, GlyphWidthPage*> > m_pages; + GlyphMetricsPage m_primaryPage; // We optimize for the page that contains glyph indices 0-255. + OwnPtr<HashMap<int, GlyphMetricsPage*> > m_pages; }; -} +} // namespace WebCore #endif diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp index 9f53f0b..59a5efb 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -29,10 +29,12 @@ #include "config.h" #include "GlyphPageTreeNode.h" -#include "CString.h" #include "CharacterNames.h" +#include "PlatformString.h" #include "SegmentedFontData.h" #include "SimpleFontData.h" +#include <stdio.h> +#include <wtf/text/CString.h> #include <wtf/unicode/Unicode.h> namespace WebCore { diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h index 0efd3bf..371cad7 100644 --- a/WebCore/platform/graphics/Gradient.h +++ b/WebCore/platform/graphics/Gradient.h @@ -63,7 +63,13 @@ typedef class PlatformGradientRec* PlatformGradient; class SkShader; typedef class SkShader* PlatformGradient; typedef class SkShader* PlatformPattern; +<<<<<<< HEAD #endif +======= +#elif PLATFORM(HAIKU) +class BGradient; +typedef BGradient* PlatformGradient; +>>>>>>> webkit.org at r58033 #else typedef void* PlatformGradient; #endif diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 45b516a..caa0a7c 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -35,7 +35,7 @@ #include "Path.h" #include "TextDirection.h" #include <wtf/Noncopyable.h> -#include <wtf/Platform.h> +#include <wtf/PassOwnPtr.h> #if PLATFORM(CG) typedef struct CGContext PlatformGraphicsContext; diff --git a/WebCore/platform/graphics/GraphicsContext3D.cpp b/WebCore/platform/graphics/GraphicsContext3D.cpp index 3eb9818..97465e2 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.cpp +++ b/WebCore/platform/graphics/GraphicsContext3D.cpp @@ -31,6 +31,7 @@ #include "GraphicsContext3D.h" #include "Image.h" +#include "ImageData.h" namespace WebCore { @@ -57,6 +58,28 @@ bool GraphicsContext3D::extractImageData(Image* image, return true; } +bool GraphicsContext3D::extractImageData(ImageData* imageData, + bool flipY, + bool premultiplyAlpha, + Vector<uint8_t>& data) +{ + if (!imageData) + return false; + int width = imageData->width(); + int height = imageData->height(); + int dataBytes = width * height * 4; + data.resize(dataBytes); + uint8_t* dst = data.data(); + uint8_t* src = imageData->data()->data()->data(); + memcpy(dst, src, dataBytes); + processImageData(dst, + width, + height, + flipY, + premultiplyAlpha ? kAlphaDoPremultiply : kAlphaDoNothing); + return true; +} + void GraphicsContext3D::processImageData(uint8_t* imageData, unsigned width, unsigned height, diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index 0a41dc6..45f6f06 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -33,7 +33,7 @@ #include <wtf/PassOwnPtr.h> // FIXME: Find a better way to avoid the name confliction for NO_ERROR. -#if ((PLATFORM(CHROMIUM) && OS(WINDOWS)) || PLATFORM(WIN)) +#if ((PLATFORM(CHROMIUM) && OS(WINDOWS)) || PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS))) #undef NO_ERROR #endif @@ -44,6 +44,13 @@ typedef void* PlatformGraphicsContext3D; const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; typedef GLuint Platform3DObject; const Platform3DObject NullPlatform3DObject = 0; +#elif PLATFORM(QT) +#include <QtOpenGL/QtOpenGL> + +typedef void* PlatformGraphicsContext3D; +const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; +typedef int Platform3DObject; +const Platform3DObject NullPlatform3DObject = 0; #else typedef void* PlatformGraphicsContext3D; const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; @@ -65,6 +72,8 @@ namespace WebCore { class WebGLShader; class WebGLTexture; class Image; + class ImageData; + class HostWindow; struct ActiveInfo { String name; @@ -73,7 +82,7 @@ namespace WebCore { }; // FIXME: ideally this would be used on all platforms. -#if PLATFORM(CHROMIUM) +#if PLATFORM(CHROMIUM) || PLATFORM(QT) class GraphicsContext3DInternal; #endif @@ -354,6 +363,7 @@ namespace WebCore { DEPTH_COMPONENT16 = 0x81A5, STENCIL_INDEX = 0x1901, STENCIL_INDEX8 = 0x8D48, + DEPTH_STENCIL = 0x84F9, RENDERBUFFER_WIDTH = 0x8D42, RENDERBUFFER_HEIGHT = 0x8D43, RENDERBUFFER_INTERNAL_FORMAT = 0x8D44, @@ -370,6 +380,7 @@ namespace WebCore { COLOR_ATTACHMENT0 = 0x8CE0, DEPTH_ATTACHMENT = 0x8D00, STENCIL_ATTACHMENT = 0x8D20, + DEPTH_STENCIL_ATTACHMENT = 0x821A, NONE = 0, FRAMEBUFFER_COMPLETE = 0x8CD5, FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6, @@ -400,7 +411,7 @@ namespace WebCore { bool premultipliedAlpha; }; - static PassOwnPtr<GraphicsContext3D> create(Attributes attrs); + static PassOwnPtr<GraphicsContext3D> create(Attributes attrs, HostWindow* hostWindow); virtual ~GraphicsContext3D(); #if PLATFORM(MAC) @@ -409,12 +420,20 @@ namespace WebCore { #elif PLATFORM(CHROMIUM) PlatformGraphicsContext3D platformGraphicsContext3D() const; Platform3DObject platformTexture() const; +#elif PLATFORM(QT) + PlatformGraphicsContext3D platformGraphicsContext3D(); + Platform3DObject platformTexture() const; #else PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } Platform3DObject platformTexture() const { return NullPlatform3DObject; } #endif void makeContextCurrent(); - + +#if PLATFORM(MAC) + // With multisampling on, blit from multisampleFBO to regular FBO. + void prepareTexture(); +#endif + // Helper to return the size in bytes of OpenGL data types // like GL_FLOAT, GL_INT, etc. int sizeInBytes(int type); @@ -435,6 +454,14 @@ namespace WebCore { unsigned int* format, unsigned int* internalFormat); + // Extracts the contents of the given ImageData into the passed + // Vector, obeying the flipY and premultiplyAlpha flags. + // Returns true upon success. + bool extractImageData(ImageData*, + bool flipY, + bool premultiplyAlpha, + Vector<uint8_t>& data); + // Processes the given image data in preparation for uploading // via texImage2D or texSubImage2D. The input data must be in // 4-component format with the alpha channel last (i.e., RGBA @@ -566,7 +593,7 @@ namespace WebCore { void pixelStorei(unsigned long pname, long param); void polygonOffset(double factor, double units); - PassRefPtr<WebGLArray> readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type); + void readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* data); void releaseShaderCompiler(); void renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height); @@ -659,7 +686,7 @@ namespace WebCore { void synthesizeGLError(unsigned long error); private: - GraphicsContext3D(Attributes attrs); + GraphicsContext3D(Attributes attrs, HostWindow* hostWindow); // Helpers for texture uploading. void premultiplyAlpha(unsigned char* rgbaData, int numPixels); @@ -689,6 +716,14 @@ namespace WebCore { AlphaOp* neededAlphaOp, unsigned int* format); +#if PLATFORM(MAC) + // Take into account the user's requested context creation attributes, + // in particular stencil and antialias, and determine which could or + // could not be honored based on the capabilities of the OpenGL + // implementation. + void validateAttributes(); +#endif + int m_currentWidth, m_currentHeight; #if PLATFORM(MAC) @@ -698,13 +733,22 @@ namespace WebCore { CGLContextObj m_contextObj; GLuint m_texture; GLuint m_fbo; - GLuint m_depthBuffer; + GLuint m_depthStencilBuffer; + + // For tracking which FBO is bound + GLuint m_boundFBO; + + // For multisampling + GLuint m_multisampleFBO; + GLuint m_multisampleDepthStencilBuffer; + GLuint m_multisampleColorBuffer; + // Errors raised by synthesizeGLError(). ListHashSet<unsigned long> m_syntheticErrors; #endif // FIXME: ideally this would be used on all platforms. -#if PLATFORM(CHROMIUM) +#if PLATFORM(CHROMIUM) || PLATFORM(QT) friend class GraphicsContext3DInternal; OwnPtr<GraphicsContext3DInternal> m_internal; #endif diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index 2336d0b..b7567bf 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -32,6 +32,11 @@ #include "FloatPoint.h" #include "RotateTransformOperation.h" #include "TextStream.h" +#include <wtf/text/CString.h> + +#ifndef NDEBUG +#include <stdio.h> +#endif namespace WebCore { @@ -388,17 +393,23 @@ static void writeIndent(TextStream& ts, int indent) ts << " "; } -void GraphicsLayer::dumpLayer(TextStream& ts, int indent) const +void GraphicsLayer::dumpLayer(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const { writeIndent(ts, indent); - ts << "(" << "GraphicsLayer" << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this)); - ts << " \"" << m_name << "\"\n"; - dumpProperties(ts, indent); + ts << "(" << "GraphicsLayer"; + + if (behavior & LayerTreeAsTextDebug) { + ts << " " << static_cast<void*>(const_cast<GraphicsLayer*>(this)); + ts << " \"" << m_name << "\""; + } + + ts << "\n"; + dumpProperties(ts, indent, behavior); writeIndent(ts, indent); ts << ")\n"; } -void GraphicsLayer::dumpProperties(TextStream& ts, int indent) const +void GraphicsLayer::dumpProperties(TextStream& ts, int indent, LayerTreeAsTextBehavior behavior) const { writeIndent(ts, indent + 1); ts << "(position " << m_position.x() << " " << m_position.y() << ")\n"; @@ -416,21 +427,23 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent) const ts << "(usingTiledLayer " << m_usingTiledLayer << ")\n"; writeIndent(ts, indent + 1); - ts << "(m_preserves3D " << m_preserves3D << ")\n"; + ts << "(preserves3D " << m_preserves3D << ")\n"; writeIndent(ts, indent + 1); ts << "(drawsContent " << m_drawsContent << ")\n"; writeIndent(ts, indent + 1); - ts << "(m_backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n"; + ts << "(backfaceVisibility " << (m_backfaceVisibility ? "visible" : "hidden") << ")\n"; - writeIndent(ts, indent + 1); - ts << "(client "; - if (m_client) - ts << static_cast<void*>(m_client); - else - ts << "none"; - ts << ")\n"; + if (behavior & LayerTreeAsTextDebug) { + writeIndent(ts, indent + 1); + ts << "("; + if (m_client) + ts << "client " << static_cast<void*>(m_client); + else + ts << "no client"; + ts << ")\n"; + } writeIndent(ts, indent + 1); ts << "(backgroundColor "; @@ -466,13 +479,19 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent) const if (m_replicaLayer) { writeIndent(ts, indent + 1); - ts << "(replica layer " << m_replicaLayer << ")\n"; - m_replicaLayer->dumpLayer(ts, indent+2); + ts << "(replica layer"; + if (behavior & LayerTreeAsTextDebug) + ts << " " << m_replicaLayer; + ts << ")\n"; + m_replicaLayer->dumpLayer(ts, indent + 2, behavior); } if (m_replicatedLayer) { writeIndent(ts, indent + 1); - ts << "(replicated layer " << m_replicatedLayer << ")\n"; + ts << "(replicated layer"; + if (behavior & LayerTreeAsTextDebug) + ts << " " << m_replicatedLayer;; + ts << ")\n"; } if (m_children.size()) { @@ -481,12 +500,31 @@ void GraphicsLayer::dumpProperties(TextStream& ts, int indent) const unsigned i; for (i = 0; i < m_children.size(); i++) - m_children[i]->dumpLayer(ts, indent+2); + m_children[i]->dumpLayer(ts, indent + 2, behavior); writeIndent(ts, indent + 1); ts << ")\n"; } } +String GraphicsLayer::layerTreeAsText(LayerTreeAsTextBehavior behavior) const +{ + TextStream ts; + + dumpLayer(ts, 0, behavior); + return ts.release(); +} + } // namespace WebCore +#ifndef NDEBUG +void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer) +{ + if (!layer) + return; + + WebCore::String output = layer->layerTreeAsText(LayerTreeAsTextDebug); + fprintf(stderr, "%s\n", output.utf8().data()); +} +#endif + #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index a097620..340b911 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -60,14 +60,28 @@ typedef WKCACFLayer PlatformLayer; typedef void* NativeLayer; } #elif PLATFORM(QT) +QT_BEGIN_NAMESPACE class QGraphicsItem; +QT_END_NAMESPACE typedef QGraphicsItem PlatformLayer; typedef QGraphicsItem* NativeLayer; +#elif PLATFORM(CHROMIUM) +namespace WebCore { +class LayerChromium; +typedef LayerChromium PlatformLayer; +typedef void* NativeLayer; +} #else typedef void* PlatformLayer; typedef void* NativeLayer; #endif +enum LayerTreeAsTextBehaviorFlags { + LayerTreeAsTextBehaviorNormal = 0, + LayerTreeAsTextDebug = 1 << 0, // Dump extra debugging info like layer addresses. +}; +typedef unsigned LayerTreeAsTextBehavior; + namespace WebCore { class FloatPoint3D; @@ -298,7 +312,7 @@ public: virtual PlatformLayer* platformLayer() const { return 0; } - void dumpLayer(TextStream&, int indent = 0) const; + void dumpLayer(TextStream&, int indent = 0, LayerTreeAsTextBehavior = LayerTreeAsTextBehaviorNormal) const; int repaintCount() const { return m_repaintCount; } int incrementRepaintCount() { return ++m_repaintCount; } @@ -333,6 +347,10 @@ public: // Some compositing systems may do internal batching to synchronize compositing updates // with updates drawn into the window. This is a signal to flush any internal batched state. virtual void syncCompositingState() { } + + // Return a string with a human readable form of the layer tree, If debug is true + // pointers for the layers and timing data will be included in the returned string. + String layerTreeAsText(LayerTreeAsTextBehavior = LayerTreeAsTextBehaviorNormal) const; protected: @@ -349,7 +367,7 @@ protected: GraphicsLayer(GraphicsLayerClient*); - void dumpProperties(TextStream&, int indent) const; + void dumpProperties(TextStream&, int indent, LayerTreeAsTextBehavior) const; GraphicsLayerClient* m_client; String m_name; @@ -398,6 +416,11 @@ protected: } // namespace WebCore +#ifndef NDEBUG +// Outside the WebCore namespace for ease of invocation from gdb. +void showGraphicsLayerTree(const WebCore::GraphicsLayer* layer); +#endif + #endif // USE(ACCELERATED_COMPOSITING) #endif // GraphicsLayer_h diff --git a/WebCore/platform/graphics/Icon.h b/WebCore/platform/graphics/Icon.h index e9f2dc7..59c732f 100644 --- a/WebCore/platform/graphics/Icon.h +++ b/WebCore/platform/graphics/Icon.h @@ -39,6 +39,8 @@ typedef struct HICON__* HICON; #include <QIcon> #elif PLATFORM(GTK) typedef struct _GdkPixbuf GdkPixbuf; +#elif PLATFORM(EFL) +#include <Evas.h> #elif PLATFORM(CHROMIUM) #include "PlatformIcon.h" #endif @@ -51,8 +53,6 @@ class String; class Icon : public RefCounted<Icon> { public: - // Deprecated. This function will be removed. - // FIXME: Remove it when all implementations are moved to ChromeClient::iconForFiles(). static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames); ~Icon(); @@ -76,6 +76,9 @@ private: #elif PLATFORM(GTK) Icon(); GdkPixbuf* m_icon; +#elif PLATFORM(EFL) + Icon(); + Evas_Object* m_icon; #elif PLATFORM(CHROMIUM) Icon(const PlatformIcon&); PlatformIcon m_icon; diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp index 8263faa..6f2311c 100644 --- a/WebCore/platform/graphics/Image.cpp +++ b/WebCore/platform/graphics/Image.cpp @@ -32,9 +32,9 @@ #include "GraphicsContext.h" #include "IntRect.h" #include "MIMETypeRegistry.h" -#include <wtf/StdLibExtras.h> - +#include "SharedBuffer.h" #include <math.h> +#include <wtf/StdLibExtras.h> #if PLATFORM(CG) #include <CoreFoundation/CoreFoundation.h> @@ -53,6 +53,7 @@ Image::~Image() Image* Image::nullImage() { + ASSERT(isMainThread()); DEFINE_STATIC_LOCAL(RefPtr<Image>, nullImage, (BitmapImage::create()));; return nullImage.get(); } diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h index b786106..212175c 100644 --- a/WebCore/platform/graphics/Image.h +++ b/WebCore/platform/graphics/Image.h @@ -32,8 +32,9 @@ #include "GraphicsTypes.h" #include "ImageSource.h" #include "IntRect.h" -#include "SharedBuffer.h" +#include "PlatformString.h" #include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> #include <wtf/RefPtr.h> #if PLATFORM(MAC) @@ -73,7 +74,6 @@ class FloatRect; class FloatSize; class GraphicsContext; class SharedBuffer; -class String; class AffineTransform; // This class gets notified when an image creates or destroys decoded frames and when it advances animation frames. diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h index 5137485..d4ea2f2 100644 --- a/WebCore/platform/graphics/IntPoint.h +++ b/WebCore/platform/graphics/IntPoint.h @@ -27,7 +27,6 @@ #define IntPoint_h #include "IntSize.h" -#include <wtf/Platform.h> #if PLATFORM(QT) #include <QDataStream> @@ -57,6 +56,8 @@ QT_END_NAMESPACE typedef struct _GdkPoint GdkPoint; #elif PLATFORM(HAIKU) class BPoint; +#elif PLATFORM(EFL) +typedef struct _Evas_Point Evas_Point; #endif #if PLATFORM(WX) @@ -80,6 +81,8 @@ public: IntPoint(int x, int y) : m_x(x), m_y(y) { } explicit IntPoint(const IntSize& size) : m_x(size.width()), m_y(size.height()) { } + static IntPoint zero() { return IntPoint(); } + int x() const { return m_x; } int y() const { return m_y; } @@ -103,7 +106,7 @@ public: void clampNegativeToZero() { - *this = expandedTo(IntPoint()); + *this = expandedTo(zero()); } #if PLATFORM(CG) @@ -130,6 +133,9 @@ public: #elif PLATFORM(HAIKU) explicit IntPoint(const BPoint&); operator BPoint() const; +#elif PLATFORM(EFL) + explicit IntPoint(const Evas_Point&); + operator Evas_Point() const; #endif #if PLATFORM(WX) @@ -189,6 +195,11 @@ inline bool operator!=(const IntPoint& a, const IntPoint& b) return a.x() != b.x() || a.y() != b.y(); } +inline IntPoint toPoint(const IntSize& size) +{ + return IntPoint(size.width(), size.height()); +} + #if PLATFORM(QT) inline QDataStream& operator<<(QDataStream& stream, const IntPoint& point) { diff --git a/WebCore/platform/graphics/IntPointHash.h b/WebCore/platform/graphics/IntPointHash.h new file mode 100644 index 0000000..bf25b14 --- /dev/null +++ b/WebCore/platform/graphics/IntPointHash.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef IntPointHash_h +#define IntPointHash_h + +#include "IntPoint.h" +#include <wtf/HashFunctions.h> +#include <wtf/HashTraits.h> + +namespace WTF { + +// The empty value is (0, INT_MIN), the deleted value is (INT_MIN, 0) +struct IntPointHash { + static unsigned hash(const WebCore::IntPoint& p) { return WTF::intHash(static_cast<uint64_t>(p.x()) << 32 | p.y()); } + static bool equal(const WebCore::IntPoint& a, const WebCore::IntPoint& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; +template<> struct HashTraits<WebCore::IntPoint> : GenericHashTraits<WebCore::IntPoint> { + static const bool needsDestruction = false; + static WebCore::IntPoint emptyValue() { return WebCore::IntPoint(0, std::numeric_limits<int>::min()); } + + static void constructDeletedValue(WebCore::IntPoint& slot) { slot = WebCore::IntPoint(std::numeric_limits<int>::min(), 0); } + static bool isDeletedValue(const WebCore::IntPoint& slot) { return slot == WebCore::IntPoint(std::numeric_limits<int>::min(), 0); } +}; +template<> struct DefaultHash<WebCore::IntPoint> { + typedef IntPointHash Hash; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h index e3633df..5c5eae1 100644 --- a/WebCore/platform/graphics/IntRect.h +++ b/WebCore/platform/graphics/IntRect.h @@ -27,7 +27,6 @@ #define IntRect_h #include "IntPoint.h" -#include <wtf/Platform.h> #include <wtf/Vector.h> #if PLATFORM(CG) @@ -52,6 +51,8 @@ QT_END_NAMESPACE typedef struct _GdkRectangle GdkRectangle; #elif PLATFORM(HAIKU) class BRect; +#elif PLATFORM(EFL) +#include <Evas.h> #endif #if PLATFORM(WX) @@ -105,6 +106,10 @@ public: int right() const { return x() + width(); } int bottom() const { return y() + height(); } + // NOTE: The result is rounded to integer values, and thus may be not the exact + // center point. + IntPoint center() const { return IntPoint(x() + width() / 2, y() + height() / 2); } + void move(const IntSize& s) { m_location += s; } void move(int dx, int dy) { m_location.move(dx, dy); } @@ -150,6 +155,9 @@ public: #elif PLATFORM(HAIKU) explicit IntRect(const BRect&); operator BRect() const; +#elif PLATFORM(EFL) + explicit IntRect(const Eina_Rectangle&); + operator Eina_Rectangle() const; #endif #if PLATFORM(CG) diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h index 6938afd..b60338c 100644 --- a/WebCore/platform/graphics/IntSize.h +++ b/WebCore/platform/graphics/IntSize.h @@ -26,8 +26,6 @@ #ifndef IntSize_h #define IntSize_h -#include <wtf/Platform.h> - #if PLATFORM(CG) typedef struct CGSize CGSize; #endif diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index 9a7f7b3..813b29c 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -37,6 +37,10 @@ #include "Document.h" #include "TimeRanges.h" +#if PLATFORM(QT) +#include <QtGlobal> +#endif + #if PLATFORM(MAC) #include "MediaPlayerPrivateQTKit.h" #elif OS(WINCE) && !PLATFORM(QT) @@ -46,7 +50,11 @@ #elif PLATFORM(GTK) #include "MediaPlayerPrivateGStreamer.h" #elif PLATFORM(QT) +#if QT_VERSION < 0x040700 #include "MediaPlayerPrivatePhonon.h" +#else +#include "MediaPlayerPrivateQt.h" +#endif #elif PLATFORM(CHROMIUM) #include "MediaPlayerPrivateChromium.h" #elif PLATFORM(ANDROID) @@ -153,7 +161,14 @@ static Vector<MediaPlayerFactory*>& installedMediaEngines() if (!enginesQueried) { enginesQueried = true; +#if USE(GSTREAMER) + MediaPlayerPrivateGStreamer::registerMediaEngine(addMediaEngine); +#else + // FIXME: currently all the MediaEngines are named + // MediaPlayerPrivate. This code will need an update when bug + // 36663 is adressed. MediaPlayerPrivate::registerMediaEngine(addMediaEngine); +#endif // register additional engines here } @@ -198,15 +213,19 @@ MediaPlayer::MediaPlayer(MediaPlayerClient* client) , m_private(createNullMediaPlayer(this)) , m_currentMediaEngine(0) , m_frameView(0) + , m_preload(Auto) , m_visible(false) , m_rate(1.0f) , m_volume(1.0f) , m_muted(false) , m_preservesPitch(true) +<<<<<<< HEAD , m_autobuffer(false) #if PLATFORM(ANDROID) , m_mediaElementType(Video) #endif +======= +>>>>>>> webkit.org at r58033 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) , m_playerProxy(0) #endif @@ -257,7 +276,7 @@ void MediaPlayer::load(const String& url, const ContentType& contentType) #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) m_private->setMediaPlayerProxy(m_playerProxy); #endif - m_private->setAutobuffer(autobuffer()); + m_private->setPreload(m_preload); m_private->setPreservesPitch(preservesPitch()); } @@ -395,7 +414,9 @@ float MediaPlayer::volume() const void MediaPlayer::setVolume(float volume) { m_volume = volume; - m_private->setVolume(volume); + + if (m_private->supportsMuting() || !m_muted) + m_private->setVolume(volume); } bool MediaPlayer::muted() const @@ -403,15 +424,14 @@ bool MediaPlayer::muted() const return m_muted; } -bool MediaPlayer::supportsMuting() const -{ - return m_private->supportsMuting(); -} - void MediaPlayer::setMuted(bool muted) { m_muted = muted; - m_private->setMuted(muted); + + if (m_private->supportsMuting()) + m_private->setMuted(muted); + else + m_private->setVolume(muted ? 0 : m_volume); } bool MediaPlayer::hasClosedCaptions() const @@ -478,17 +498,15 @@ void MediaPlayer::setVisible(bool b) m_private->setVisible(b); } -bool MediaPlayer::autobuffer() const +MediaPlayer::Preload MediaPlayer::preload() const { - return m_autobuffer; + return m_preload; } -void MediaPlayer::setAutobuffer(bool b) +void MediaPlayer::setPreload(MediaPlayer::Preload preload) { - if (m_autobuffer != b) { - m_autobuffer = b; - m_private->setAutobuffer(b); - } + m_preload = preload; + m_private->setPreload(preload); } void MediaPlayer::paint(GraphicsContext* p, const IntRect& r) diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index f067cc9..24f4225 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -32,6 +32,7 @@ #include "MediaPlayerProxy.h" #endif +#include "Document.h" #include "IntRect.h" #include "StringHash.h" #include <wtf/HashSet.h> @@ -75,6 +76,9 @@ class MediaPlayerClient { public: virtual ~MediaPlayerClient() { } + // Get the document which the media player is owned by + virtual Document* mediaPlayerOwningDocument() { return 0; } + // the network state has changed virtual void mediaPlayerNetworkStateChanged(MediaPlayer*) { } @@ -189,15 +193,14 @@ public: float volume() const; void setVolume(float); - bool supportsMuting() const; bool muted() const; void setMuted(bool); bool hasClosedCaptions() const; void setClosedCaptionsVisible(bool closedCaptionsVisible); - bool autobuffer() const; - void setAutobuffer(bool); + bool autoplay() const; + void setAutoplay(bool); void paint(GraphicsContext*, const IntRect&); void paintCurrentFrameInContext(GraphicsContext*, const IntRect&); @@ -211,6 +214,10 @@ public: enum MovieLoadType { Unknown, Download, StoredStream, LiveStream }; MovieLoadType movieLoadType() const; + enum Preload { None, MetaData, Auto }; + Preload preload() const; + void setPreload(Preload); + void networkStateChanged(); void readyStateChanged(); void volumeChanged(float); @@ -253,15 +260,19 @@ private: void* m_currentMediaEngine; FrameView* m_frameView; IntSize m_size; + Preload m_preload; bool m_visible; float m_rate; float m_volume; bool m_muted; bool m_preservesPitch; +<<<<<<< HEAD bool m_autobuffer; #if PLATFORM(ANDROID) MediaElementType m_mediaElementType; #endif +======= +>>>>>>> webkit.org at r58033 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private #endif diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h index 3bb8475..16ff543 100644 --- a/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -97,7 +97,7 @@ public: virtual void paintCurrentFrameInContext(GraphicsContext* c, const IntRect& r) { paint(c, r); } - virtual void setAutobuffer(bool) { }; + virtual void setPreload(MediaPlayer::Preload) { }; virtual bool hasAvailableVideoFrame() const { return readyState() >= MediaPlayer::HaveCurrentData; } diff --git a/WebCore/platform/graphics/Path.cpp b/WebCore/platform/graphics/Path.cpp index e30703c..af94be7 100644 --- a/WebCore/platform/graphics/Path.cpp +++ b/WebCore/platform/graphics/Path.cpp @@ -39,6 +39,7 @@ static const float QUARTER = 0.552f; // approximation of control point positions // to simulate a quarter of a circle. namespace WebCore { +#if !PLATFORM(OPENVG) static void pathLengthApplierFunction(void* info, const PathElement* element) { PathTraversalState& traversalState = *static_cast<PathTraversalState*>(info); @@ -107,6 +108,7 @@ float Path::normalAngleAtLength(float length, bool& ok) ok = traversalState.m_success; return traversalState.m_normalAngle; } +#endif Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& roundingRadii) { diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index 533ef8f..b69670f 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -33,6 +33,11 @@ #if PLATFORM(CG) typedef struct CGPath PlatformPath; +#elif PLATFORM(OPENVG) +namespace WebCore { +class PlatformPathOpenVG; +} +typedef WebCore::PlatformPathOpenVG PlatformPath; #elif PLATFORM(QT) #include <qpainterpath.h> typedef QPainterPath PlatformPath; diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h index b0cf283..48e8d8b 100644 --- a/WebCore/platform/graphics/Pattern.h +++ b/WebCore/platform/graphics/Pattern.h @@ -87,6 +87,9 @@ public: void setPatternSpaceTransform(const AffineTransform& patternSpaceTransformation); void setPlatformPatternSpaceTransform(); + bool repeatX() const { return m_repeatX; } + bool repeatY() const { return m_repeatY; } + private: Pattern(Image*, bool repeatX, bool repeatY); diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp index 2ec8abb..04b6ab1 100644 --- a/WebCore/platform/graphics/SimpleFontData.cpp +++ b/WebCore/platform/graphics/SimpleFontData.cpp @@ -157,9 +157,11 @@ void SimpleFontData::platformGlyphInit() // are mapped to the ZERO WIDTH SPACE glyph. Glyph zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph; if (zeroWidthSpaceGlyph) { - if (zeroWidthSpaceGlyph != m_spaceGlyph) - m_glyphToWidthMap.setWidthForGlyph(zeroWidthSpaceGlyph, 0); - else + if (zeroWidthSpaceGlyph != m_spaceGlyph) { + GlyphMetrics metrics; + metrics.horizontalAdvance = 0; + m_glyphToMetricsMap.setMetricsForGlyph(zeroWidthSpaceGlyph, metrics); + } else LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width not overridden."); } diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h index 0366e3b..efdbba4 100644 --- a/WebCore/platform/graphics/SimpleFontData.h +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -26,8 +26,8 @@ #include "FontData.h" #include "FontPlatformData.h" +#include "GlyphMetricsMap.h" #include "GlyphPageTreeNode.h" -#include "GlyphWidthMap.h" #include "TypesettingFeatures.h" #include <wtf/OwnPtr.h> @@ -58,9 +58,9 @@ class FontDescription; class FontPlatformData; class SharedBuffer; class SVGFontData; -class WidthMap; enum Pitch { UnknownPitch, FixedPitch, VariablePitch }; +enum GlyphMetricsMode { GlyphBoundingBox, GlyphWidthOnly }; class SimpleFontData : public FontData { public: @@ -81,8 +81,9 @@ public: float xHeight() const { return m_xHeight; } unsigned unitsPerEm() const { return m_unitsPerEm; } - float widthForGlyph(Glyph) const; - float platformWidthForGlyph(Glyph) const; + float widthForGlyph(Glyph glyph) const { return metricsForGlyph(glyph, GlyphWidthOnly).horizontalAdvance; } + GlyphMetrics metricsForGlyph(Glyph, GlyphMetricsMode = GlyphBoundingBox) const; + GlyphMetrics platformMetricsForGlyph(Glyph, GlyphMetricsMode) const; float spaceWidth() const { return m_spaceWidth; } float adjustedSpaceWidth() const { return m_adjustedSpaceWidth; } @@ -167,7 +168,7 @@ private: || (OS(WINDOWS) && PLATFORM(WX)) void initGDIFont(); void platformCommonDestroy(); - float widthForGDIGlyph(Glyph glyph) const; + GlyphMetrics metricsForGDIGlyph(Glyph glyph) const; #endif int m_ascent; @@ -181,7 +182,7 @@ private: FontPlatformData m_platformData; - mutable GlyphWidthMap m_glyphToWidthMap; + mutable GlyphMetricsMap m_glyphToMetricsMap; bool m_treatAsFixedPitch; @@ -237,16 +238,16 @@ private: #if !PLATFORM(QT) -ALWAYS_INLINE float SimpleFontData::widthForGlyph(Glyph glyph) const +ALWAYS_INLINE GlyphMetrics SimpleFontData::metricsForGlyph(Glyph glyph, GlyphMetricsMode metricsMode) const { - float width = m_glyphToWidthMap.widthForGlyph(glyph); - if (width != cGlyphWidthUnknown) - return width; - - width = platformWidthForGlyph(glyph); - m_glyphToWidthMap.setWidthForGlyph(glyph, width); - - return width; + GlyphMetrics metrics = m_glyphToMetricsMap.metricsForGlyph(glyph); + if ((metricsMode == GlyphWidthOnly && metrics.horizontalAdvance != cGlyphSizeUnknown) || (metricsMode == GlyphBoundingBox && metrics.boundingBox.width() != cGlyphSizeUnknown)) + return metrics; + + metrics = platformMetricsForGlyph(glyph, metricsMode); + m_glyphToMetricsMap.setMetricsForGlyph(glyph, metrics); + + return metrics; } #endif diff --git a/WebCore/platform/graphics/Tile.h b/WebCore/platform/graphics/Tile.h new file mode 100644 index 0000000..c623ec9 --- /dev/null +++ b/WebCore/platform/graphics/Tile.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef Tile_h +#define Tile_h + +#if ENABLE(TILED_BACKING_STORE) + +#include "IntPoint.h" +#include "IntPointHash.h" +#include "IntRect.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +#if PLATFORM(QT) +QT_BEGIN_NAMESPACE +class QPixmap; +class QRegion; +QT_END_NAMESPACE +#endif + +namespace WebCore { + +class GraphicsContext; +class TiledBackingStore; + +class Tile : public RefCounted<Tile> { +public: + typedef IntPoint Coordinate; + + static PassRefPtr<Tile> create(TiledBackingStore* backingStore, const Coordinate& tileCoordinate) { return adoptRef(new Tile(backingStore, tileCoordinate)); } + ~Tile(); + + bool isDirty() const; + void invalidate(const IntRect&); + void updateBackBuffer(); + void swapBackBufferToFront(); + bool isReadyToPaint() const; + void paint(GraphicsContext*, const IntRect&); + + const Tile::Coordinate& coordinate() const { return m_coordinate; } + const IntRect& rect() const { return m_rect; } + + static void paintCheckerPattern(GraphicsContext*, const FloatRect&); + +private: + Tile(TiledBackingStore*, const Coordinate&); + + TiledBackingStore* m_backingStore; + Coordinate m_coordinate; + IntRect m_rect; + +#if PLATFORM(QT) + QPixmap* m_buffer; + QPixmap* m_backBuffer; + QRegion* m_dirtyRegion; +#endif +}; + +} +#endif +#endif diff --git a/WebCore/platform/graphics/TiledBackingStore.cpp b/WebCore/platform/graphics/TiledBackingStore.cpp new file mode 100644 index 0000000..6214f1b --- /dev/null +++ b/WebCore/platform/graphics/TiledBackingStore.cpp @@ -0,0 +1,378 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "TiledBackingStore.h" + +#if ENABLE(TILED_BACKING_STORE) + +#include "GraphicsContext.h" +#include "TiledBackingStoreClient.h" + +namespace WebCore { + +static const int defaultTileWidth = 512; +static const int defaultTileHeight = 512; + +TiledBackingStore::TiledBackingStore(TiledBackingStoreClient* client) + : m_client(client) + , m_tileBufferUpdateTimer(new TileTimer(this, &TiledBackingStore::tileBufferUpdateTimerFired)) + , m_tileCreationTimer(new TileTimer(this, &TiledBackingStore::tileCreationTimerFired)) + , m_tileSize(defaultTileWidth, defaultTileHeight) + , m_contentsScale(1.f) + , m_pendingScale(0) + , m_contentsFrozen(false) +{ +} + +TiledBackingStore::~TiledBackingStore() +{ + delete m_tileBufferUpdateTimer; + delete m_tileCreationTimer; +} + +void TiledBackingStore::invalidate(const IntRect& contentsDirtyRect) +{ + IntRect dirtyRect(mapFromContents(contentsDirtyRect)); + + Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.topLeft()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(dirtyRect.bottomRight()); + + for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { + for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { + RefPtr<Tile> currentTile = tileAt(Tile::Coordinate(xCoordinate, yCoordinate)); + if (!currentTile) + continue; + currentTile->invalidate(dirtyRect); + } + } + + startTileBufferUpdateTimer(); +} + +void TiledBackingStore::updateTileBuffers() +{ + if (m_contentsFrozen) + return; + + Vector<IntRect> paintedArea; + Vector<RefPtr<Tile> > dirtyTiles; + TileMap::iterator end = m_tiles.end(); + for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) { + if (!it->second->isDirty()) + continue; + dirtyTiles.append(it->second); + // FIXME: should not request system repaint for the full tile. + paintedArea.append(mapToContents(it->second->rect())); + } + + if (dirtyTiles.isEmpty()) + return; + + m_client->tiledBackingStorePaintBegin(); + + // FIXME: In single threaded case, tile back buffers could be updated asynchronously + // one by one and then swapped to front in one go. This would minimize the time spent + // blocking on tile updates. + unsigned size = dirtyTiles.size(); + for (unsigned n = 0; n < size; ++n) + dirtyTiles[n]->updateBackBuffer(); + + for (unsigned n = 0; n < size; ++n) + dirtyTiles[n]->swapBackBufferToFront(); + + m_client->tiledBackingStorePaintEnd(paintedArea); +} + +void TiledBackingStore::paint(GraphicsContext* context, const IntRect& rect) +{ + context->save(); + + // Assumes the backing store is painted with the scale transform applied. + // Since tile content is already scaled, first revert the scaling from the painter. + context->scale(FloatSize(1.f / m_contentsScale, 1.f / m_contentsScale)); + + IntRect dirtyRect = mapFromContents(rect); + + Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.topLeft()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(dirtyRect.bottomRight()); + + for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { + for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { + Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); + RefPtr<Tile> currentTile = tileAt(currentCoordinate); + if (currentTile && currentTile->isReadyToPaint()) + currentTile->paint(context, dirtyRect); + else { + FloatRect tileRect = tileRectForCoordinate(currentCoordinate); + FloatRect target = intersection(tileRect, FloatRect(rect)); + Tile::paintCheckerPattern(context, target); + } + } + } + context->restore(); +} + +void TiledBackingStore::viewportChanged(const IntRect& contentsViewport) +{ + IntRect viewport = mapFromContents(contentsViewport); + if (m_viewport == viewport) + return; + + m_viewport = viewport; + + startTileCreationTimer(); +} + +void TiledBackingStore::setContentsScale(float scale) +{ + if (m_pendingScale == m_contentsScale) { + m_pendingScale = 0; + return; + } + m_pendingScale = scale; + if (m_contentsFrozen) + return; + commitScaleChange(); +} + +void TiledBackingStore::commitScaleChange() +{ + m_contentsScale = m_pendingScale; + m_pendingScale = 0; + m_tiles.clear(); + createTiles(); +} + +double TiledBackingStore::tileDistance(const IntRect& viewport, const Tile::Coordinate& tileCoordinate) +{ + if (viewport.intersects(tileRectForCoordinate(tileCoordinate))) + return 0; + + IntPoint viewCenter = viewport.location() + IntSize(viewport.width() / 2, viewport.height() / 2); + Tile::Coordinate centerCoordinate = tileCoordinateForPoint(viewCenter); + + // Manhattan distance, biased so that vertical distances are shorter. + const double horizontalBias = 1.3; + return abs(centerCoordinate.y() - tileCoordinate.y()) + horizontalBias * abs(centerCoordinate.x() - tileCoordinate.x()); +} + +void TiledBackingStore::createTiles() +{ + if (m_contentsFrozen) + return; + + if (m_viewport.isEmpty()) + return; + + // Remove tiles that extend outside the current contents rect. + dropOverhangingTiles(); + + // FIXME: Make configurable/adapt to memory. + IntRect keepRect = m_viewport; + keepRect.inflateX(m_viewport.width()); + keepRect.inflateY(3 * m_viewport.height()); + keepRect.intersect(contentsRect()); + + dropTilesOutsideRect(keepRect); + + IntRect coverRect = m_viewport; + coverRect.inflateX(m_viewport.width() / 2); + coverRect.inflateY(2 * m_viewport.height()); + coverRect.intersect(contentsRect()); + + // Search for the tile position closest to the viewport center that does not yet contain a tile. + // Which position is considered the closest depends on the tileDistance function. + double shortestDistance = std::numeric_limits<double>::infinity(); + Vector<Tile::Coordinate> tilesToCreate; + unsigned requiredTileCount = 0; + Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.topLeft()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(coverRect.bottomRight()); + for (unsigned yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { + for (unsigned xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { + Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); + if (tileAt(currentCoordinate)) + continue; + ++requiredTileCount; + // Distance is 0 for all currently visible tiles. + double distance = tileDistance(m_viewport, currentCoordinate); + if (distance > shortestDistance) + continue; + if (distance < shortestDistance) { + tilesToCreate.clear(); + shortestDistance = distance; + } + tilesToCreate.append(currentCoordinate); + } + } + + // Now construct the tile(s) + unsigned tilesToCreateCount = tilesToCreate.size(); + for (unsigned n = 0; n < tilesToCreateCount; ++n) { + Tile::Coordinate coordinate = tilesToCreate[n]; + setTile(coordinate, Tile::create(this, coordinate)); + } + requiredTileCount -= tilesToCreateCount; + + // Paint the content of the newly created tiles + if (tilesToCreateCount) + updateTileBuffers(); + + // Keep creating tiles until the whole coverRect is covered. + if (requiredTileCount) + m_tileCreationTimer->startOneShot(0); +} + +void TiledBackingStore::dropOverhangingTiles() +{ + IntRect contentsRect = this->contentsRect(); + + Vector<Tile::Coordinate> tilesToRemove; + TileMap::iterator end = m_tiles.end(); + for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) { + Tile::Coordinate tileCoordinate = it->second->coordinate(); + IntRect tileRect = it->second->rect(); + IntRect expectedTileRect = tileRectForCoordinate(tileCoordinate); + if (expectedTileRect != tileRect || !contentsRect.contains(tileRect)) + tilesToRemove.append(tileCoordinate); + } + unsigned removeCount = tilesToRemove.size(); + for (unsigned n = 0; n < removeCount; ++n) + removeTile(tilesToRemove[n]); +} + +void TiledBackingStore::dropTilesOutsideRect(const IntRect& keepRect) +{ + FloatRect keepRectF = keepRect; + + Vector<Tile::Coordinate> toRemove; + TileMap::iterator end = m_tiles.end(); + for (TileMap::iterator it = m_tiles.begin(); it != end; ++it) { + Tile::Coordinate coordinate = it->second->coordinate(); + FloatRect tileRect = it->second->rect(); + if (!tileRect.intersects(keepRectF)) + toRemove.append(coordinate); + } + unsigned removeCount = toRemove.size(); + for (unsigned n = 0; n < removeCount; ++n) + removeTile(toRemove[n]); +} + +PassRefPtr<Tile> TiledBackingStore::tileAt(const Tile::Coordinate& coordinate) const +{ + return m_tiles.get(coordinate); +} + +void TiledBackingStore::setTile(const Tile::Coordinate& coordinate, PassRefPtr<Tile> tile) +{ + m_tiles.set(coordinate, tile); +} + +void TiledBackingStore::removeTile(const Tile::Coordinate& coordinate) +{ + m_tiles.remove(coordinate); +} + +IntRect TiledBackingStore::mapToContents(const IntRect& rect) const +{ + return enclosingIntRect(FloatRect(rect.x() / m_contentsScale, + rect.y() / m_contentsScale, + rect.width() / m_contentsScale, + rect.height() / m_contentsScale)); +} + +IntRect TiledBackingStore::mapFromContents(const IntRect& rect) const +{ + return enclosingIntRect(FloatRect(rect.x() * m_contentsScale, + rect.y() * m_contentsScale, + rect.width() * m_contentsScale, + rect.height() * m_contentsScale)); +} + +IntRect TiledBackingStore::contentsRect() const +{ + return mapFromContents(m_client->tiledBackingStoreContentsRect()); +} + +IntRect TiledBackingStore::tileRectForCoordinate(const Tile::Coordinate& coordinate) const +{ + IntRect rect(coordinate.x() * m_tileSize.width(), + coordinate.y() * m_tileSize.height(), + m_tileSize.width(), + m_tileSize.height()); + + rect.intersect(contentsRect()); + return rect; +} + +Tile::Coordinate TiledBackingStore::tileCoordinateForPoint(const IntPoint& point) const +{ + int x = point.x() / m_tileSize.width(); + int y = point.y() / m_tileSize.height(); + return Tile::Coordinate(std::max(x, 0), std::max(y, 0)); +} + + +void TiledBackingStore::startTileBufferUpdateTimer() +{ + if (m_tileBufferUpdateTimer->isActive() || m_contentsFrozen) + return; + m_tileBufferUpdateTimer->startOneShot(0); +} + +void TiledBackingStore::tileBufferUpdateTimerFired(TileTimer*) +{ + updateTileBuffers(); +} + +void TiledBackingStore::startTileCreationTimer() +{ + if (m_tileCreationTimer->isActive() || m_contentsFrozen) + return; + m_tileCreationTimer->startOneShot(0); +} + +void TiledBackingStore::tileCreationTimerFired(TileTimer*) +{ + createTiles(); +} + +void TiledBackingStore::setContentsFrozen(bool freeze) +{ + if (m_contentsFrozen == freeze) + return; + + m_contentsFrozen = freeze; + + // Restart the timers. There might be pending invalidations that + // were not painted or created because tiles are not created or + // painted when in frozen state. + if (m_contentsFrozen) + return; + if (m_pendingScale) + commitScaleChange(); + else { + startTileCreationTimer(); + startTileBufferUpdateTimer(); + } +} + +} + +#endif diff --git a/WebCore/platform/graphics/TiledBackingStore.h b/WebCore/platform/graphics/TiledBackingStore.h new file mode 100644 index 0000000..8ed4336 --- /dev/null +++ b/WebCore/platform/graphics/TiledBackingStore.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TiledBackingStore_h +#define TiledBackingStore_h + +#if ENABLE(TILED_BACKING_STORE) + +#include "FloatSize.h" +#include "IntPoint.h" +#include "IntRect.h" +#include "Tile.h" +#include "Timer.h" +#include <wtf/Assertions.h> +#include <wtf/HashMap.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class GraphicsContext; +class TiledBackingStoreClient; + +class TiledBackingStore : public Noncopyable { +public: + TiledBackingStore(TiledBackingStoreClient*); + ~TiledBackingStore(); + + void viewportChanged(const IntRect& viewportRect); + + float contentsScale() { return m_contentsScale; } + void setContentsScale(float); + + bool contentsFrozen() const { return m_contentsFrozen; } + void setContentsFrozen(bool); + + void invalidate(const IntRect& dirtyRect); + void paint(GraphicsContext*, const IntRect&); + +private: + void startTileBufferUpdateTimer(); + void startTileCreationTimer(); + + typedef Timer<TiledBackingStore> TileTimer; + + void tileBufferUpdateTimerFired(TileTimer*); + void tileCreationTimerFired(TileTimer*); + + void updateTileBuffers(); + void createTiles(); + + void commitScaleChange(); + + void dropOverhangingTiles(); + void dropTilesOutsideRect(const IntRect&); + + PassRefPtr<Tile> tileAt(const Tile::Coordinate&) const; + void setTile(const Tile::Coordinate& coordinate, PassRefPtr<Tile> tile); + void removeTile(const Tile::Coordinate& coordinate); + + IntRect mapToContents(const IntRect&) const; + IntRect mapFromContents(const IntRect&) const; + + IntRect contentsRect() const; + + IntRect tileRectForCoordinate(const Tile::Coordinate&) const; + Tile::Coordinate tileCoordinateForPoint(const IntPoint&) const; + double tileDistance(const IntRect& viewport, const Tile::Coordinate&); + + void paintCheckerPattern(GraphicsContext*, const IntRect&, const Tile::Coordinate&); + +private: + TiledBackingStoreClient* m_client; + + typedef HashMap<Tile::Coordinate, RefPtr<Tile> > TileMap; + TileMap m_tiles; + + TileTimer* m_tileBufferUpdateTimer; + TileTimer* m_tileCreationTimer; + + IntSize m_tileSize; + + IntRect m_viewport; + float m_contentsScale; + float m_pendingScale; + + bool m_contentsFrozen; + + friend class Tile; +}; + +} + +#endif +#endif diff --git a/WebCore/platform/graphics/TiledBackingStoreClient.h b/WebCore/platform/graphics/TiledBackingStoreClient.h new file mode 100644 index 0000000..4adbbab --- /dev/null +++ b/WebCore/platform/graphics/TiledBackingStoreClient.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TiledBackingStoreClient_h +#define TiledBackingStoreClient_h + +namespace WebCore { + +#if ENABLE(TILED_BACKING_STORE) +class TiledBackingStoreClient { +public: + virtual void tiledBackingStorePaintBegin() = 0; + virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&) = 0; + virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea) = 0; + virtual IntRect tiledBackingStoreContentsRect() = 0; +}; + +#else +class TiledBackingStoreClient {}; +#endif + +} + +#endif diff --git a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp b/WebCore/platform/graphics/cairo/FontCacheCairo.cpp index d2b2f39..d2b2f39 100644 --- a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp +++ b/WebCore/platform/graphics/cairo/FontCacheCairo.cpp diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index 169c74c..c2aae49 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2010 Holger Hans Peter Freyther * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -157,7 +158,11 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } } - if (context->textDrawingMode() & cTextStroke) { + // Prevent running into a long computation within cairo. If the stroke width is + // twice the size of the width of the text we will not ask cairo to stroke + // the text as even one single stroke would cover the full wdth of the text. + // See https://bugs.webkit.org/show_bug.cgi?id=33759. + if (context->textDrawingMode() & cTextStroke && context->strokeThickness() < 2 * offset) { if (context->strokeGradient()) { cairo_set_source(cr, context->strokeGradient()->platformGradient()); if (context->getAlpha() < 1.0f) { diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp b/WebCore/platform/graphics/cairo/FontCustomPlatformData.cpp index bb2e064..bb2e064 100644 --- a/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/cairo/FontCustomPlatformData.cpp diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.h b/WebCore/platform/graphics/cairo/FontCustomPlatformData.h index b36cc79..b36cc79 100644 --- a/WebCore/platform/graphics/gtk/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/cairo/FontCustomPlatformData.h diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/cairo/FontPlatformData.h index d30b480..3c926fe 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformData.h +++ b/WebCore/platform/graphics/cairo/FontPlatformData.h @@ -2,7 +2,7 @@ * This file is part of the internal font implementation. It should not be included by anyone other than * FontMac.cpp, FontWin.cpp and Font.cpp. * - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2007, 2008 Apple Inc. * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com * Copyright (C) 2007 Holger Hans Peter Freyther * Copyright (C) 2007 Pioneer Research Center USA, Inc. @@ -28,18 +28,25 @@ #ifndef FontPlatformData_h #define FontPlatformData_h -#include "GlyphBuffer.h" #include "FontDescription.h" +#include "GlyphBuffer.h" #include <cairo.h> #if defined(USE_FREETYPE) #include <cairo-ft.h> #include <fontconfig/fcfreetype.h> #elif defined(USE_PANGO) #include <pango/pangocairo.h> +#elif PLATFORM(WIN) +#include <cairo-win32.h> +#include "RefCountedHFONT.h" +#include "StringImpl.h" #else #error "Must defined a font backend" #endif +#if PLATFORM(WIN) +typedef struct HFONT__* HFONT; +#endif namespace WebCore { class String; @@ -53,9 +60,16 @@ public: #elif defined(USE_PANGO) : m_context(0) , m_font(hashTableDeletedFontValue()) +#elif PLATFORM(WIN) + : m_fontFace(0) + , m_useGDI(false) + , m_font(WTF::HashTableDeletedValue) #else #error "Must defined a font backend" #endif + , m_size(0) + , m_syntheticBold(false) + , m_syntheticOblique(false) , m_scaledFont(0) { } @@ -66,24 +80,41 @@ public: #elif defined(USE_PANGO) : m_context(0) , m_font(0) +#elif PLATFORM(WIN) + : m_fontFace(0) + , m_useGDI(false) #else #error "Must defined a font backend" #endif + , m_size(0) + , m_syntheticBold(false) + , m_syntheticOblique(false) , m_scaledFont(0) { } +#if PLATFORM(WIN) + FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI); +#else FontPlatformData(const FontDescription&, const AtomicString& family); +#endif + FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic); FontPlatformData(float size, bool bold, bool italic); - FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic); FontPlatformData(const FontPlatformData&); ~FontPlatformData(); +#if !PLATFORM(WIN) static bool init(); +#else + HFONT hfont() const { return m_font->hfont(); } + bool useGDI() const { return m_useGDI; } + cairo_font_face_t* fontFace() const { return m_fontFace; } +#endif bool isFixedPitch(); float size() const { return m_size; } + void setSize(float size) { m_size = size; } bool syntheticBold() const { return m_syntheticBold; } bool syntheticOblique() const { return m_syntheticOblique; } @@ -91,23 +122,30 @@ public: unsigned hash() const { +#if PLATFORM(WIN) + return m_font->hash(); +#else #if defined(USE_FREETYPE) if (m_pattern) return FcPatternHash(m_pattern); #endif uintptr_t hashCodes[1] = { reinterpret_cast<uintptr_t>(m_scaledFont) }; return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); +#endif } bool operator==(const FontPlatformData&) const; FontPlatformData& operator=(const FontPlatformData&); - bool isHashTableDeletedValue() const { + bool isHashTableDeletedValue() const + { #if defined(USE_FREETYPE) return m_pattern == hashTableDeletedFontValue(); #elif defined(USE_PANGO) return m_font == hashTableDeletedFontValue(); +#elif PLATFORM(WIN) + return m_font.isHashTableDeletedValue(); #endif - }; + } #ifndef NDEBUG String description() const; @@ -122,6 +160,13 @@ public: PangoContext* m_context; PangoFont* m_font; +#elif PLATFORM(WIN) +private: + void platformDataInit(HFONT, float size, HDC, WCHAR* faceName); + + RefPtr<RefCountedHFONT> m_font; + cairo_font_face_t* m_fontFace; + bool m_useGDI; #else #error "Must defined a font backend" #endif diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/cairo/FontPlatformDataCairo.cpp index 0b1280e..974c195 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp +++ b/WebCore/platform/graphics/cairo/FontPlatformDataCairo.cpp @@ -25,14 +25,14 @@ #include "config.h" #include "FontPlatformData.h" -#include "CString.h" #include "PlatformString.h" #include "FontDescription.h" +#include <wtf/text/CString.h> #include <cairo-ft.h> #include <cairo.h> #include <fontconfig/fcfreetype.h> -#include <gtk/gtk.h> +#include <gdk/gdk.h> namespace WebCore { @@ -134,7 +134,7 @@ FontPlatformData::FontPlatformData(float size, bool bold, bool italic) { } -FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic) +FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic) : m_pattern(0) , m_fallbacks(0) , m_size(size) diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp b/WebCore/platform/graphics/cairo/GlyphPageTreeNodeCairo.cpp index 7c9ffe6..7c9ffe6 100644 --- a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp +++ b/WebCore/platform/graphics/cairo/GlyphPageTreeNodeCairo.cpp diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index bc68b37..91cecd3 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -89,7 +89,7 @@ bool Path::hasCurrentPoint() const void Path::translate(const FloatSize& p) { cairo_t* cr = platformPath()->m_cr; - cairo_translate(cr, p.width(), p.height()); + cairo_translate(cr, -p.width(), -p.height()); } void Path::moveTo(const FloatPoint& p) @@ -267,9 +267,6 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) bool Path::contains(const FloatPoint& point, WindRule rule) const { - if (!boundingRect().contains(point)) - return false; - cairo_t* cr = platformPath()->m_cr; cairo_fill_rule_t cur = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, rule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/cairo/SimpleFontDataCairo.cpp index df25393..0be45f6 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/cairo/SimpleFontDataCairo.cpp @@ -114,7 +114,7 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = m_platformData.isFixedPitch(); } -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode) const { ASSERT(m_platformData.m_scaledFont); @@ -125,7 +125,10 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const float w = (float)m_spaceWidth; if (cairo_scaled_font_status(m_platformData.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) w = (float)extents.x_advance; - return w; + + GlyphMetrics metrics; + metrics.horizontalAdvance = w; + return metrics; } } diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/cg/FontPlatformData.h index 5084469..da2b7e3 100644 --- a/WebCore/platform/graphics/win/FontPlatformData.h +++ b/WebCore/platform/graphics/cg/FontPlatformData.h @@ -2,7 +2,7 @@ * This file is part of the internal font implementation. It should not be included by anyone other than * FontMac.cpp, FontWin.cpp and Font.cpp. * - * Copyright (C) 2006, 2007, 2008 Apple Inc. + * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,17 +21,14 @@ * */ -#ifndef FontPlatformData_H -#define FontPlatformData_H +#ifndef FontPlatformData_h +#define FontPlatformData_h +#include "RefCountedHFONT.h" #include "StringImpl.h" #include <wtf/PassRefPtr.h> -#include <wtf/RetainPtr.h> #include <wtf/RefCounted.h> - -#if PLATFORM(CAIRO) -#include <cairo-win32.h> -#endif +#include <wtf/RetainPtr.h> typedef struct HFONT__* HFONT; typedef struct CGFont* CGFontRef; @@ -44,14 +41,7 @@ class String; class FontPlatformData { public: FontPlatformData() -#if PLATFORM(CAIRO) - : m_fontFace(0) - , m_scaledFont(0) - , -#else - : -#endif - m_size(0) + : m_size(0) , m_syntheticBold(false) , m_syntheticOblique(false) , m_useGDI(false) @@ -61,26 +51,14 @@ public: FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI); FontPlatformData(float size, bool bold, bool oblique); -#if PLATFORM(CG) FontPlatformData(HFONT, CGFontRef, float size, bool bold, bool oblique, bool useGDI); -#elif PLATFORM(CAIRO) - FontPlatformData(cairo_font_face_t*, float size, bool bold, bool oblique); - FontPlatformData(const FontPlatformData&); - - FontPlatformData& operator=(const FontPlatformData&); -#endif ~FontPlatformData(); FontPlatformData(WTF::HashTableDeletedValueType) : m_font(WTF::HashTableDeletedValue) { } bool isHashTableDeletedValue() const { return m_font.isHashTableDeletedValue(); } HFONT hfont() const { return m_font->hfont(); } -#if PLATFORM(CG) CGFontRef cgFont() const { return m_cgFont.get(); } -#elif PLATFORM(CAIRO) - cairo_font_face_t* fontFace() const { return m_fontFace; } - cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } -#endif float size() const { return m_size; } void setSize(float size) { m_size = size; } @@ -95,16 +73,12 @@ public: bool operator==(const FontPlatformData& other) const { - return m_font == other.m_font && -#if PLATFORM(CG) - m_cgFont == other.m_cgFont && -#elif PLATFORM(CAIRO) - m_fontFace == other.m_fontFace && - m_scaledFont == other.m_scaledFont && -#endif - m_size == other.m_size && - m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique && - m_useGDI == other.m_useGDI; + return m_font == other.m_font + && m_cgFont == other.m_cgFont + && m_size == other.m_size + && m_syntheticBold == other.m_syntheticBold + && m_syntheticOblique == other.m_syntheticOblique + && m_useGDI == other.m_useGDI; } #ifndef NDEBUG @@ -112,37 +86,10 @@ public: #endif private: - class RefCountedHFONT : public RefCounted<RefCountedHFONT> { - public: - static PassRefPtr<RefCountedHFONT> create(HFONT hfont) { return adoptRef(new RefCountedHFONT(hfont)); } - static PassRefPtr<RefCountedHFONT> createDeleted() { return adoptRef(new RefCountedHFONT(reinterpret_cast<HFONT>(-1))); } - - ~RefCountedHFONT() { if (m_hfont != reinterpret_cast<HFONT>(-1)) DeleteObject(m_hfont); } - - HFONT hfont() const { return m_hfont; } - unsigned hash() const - { - return StringImpl::computeHash(reinterpret_cast<const UChar*>(&m_hfont), sizeof(HFONT) / sizeof(UChar)); - } - - private: - RefCountedHFONT(HFONT hfont) - : m_hfont(hfont) - { - } - - HFONT m_hfont; - }; - - void platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName); + void platformDataInit(HFONT, float size, HDC, WCHAR* faceName); RefPtr<RefCountedHFONT> m_font; -#if PLATFORM(CG) RetainPtr<CGFontRef> m_cgFont; -#elif PLATFORM(CAIRO) - cairo_font_face_t* m_fontFace; - cairo_scaled_font_t* m_scaledFont; -#endif float m_size; bool m_syntheticBold; diff --git a/WebCore/platform/graphics/cg/GradientCG.cpp b/WebCore/platform/graphics/cg/GradientCG.cpp index 9c91700..4aaaeaf 100644 --- a/WebCore/platform/graphics/cg/GradientCG.cpp +++ b/WebCore/platform/graphics/cg/GradientCG.cpp @@ -29,8 +29,8 @@ #include "CSSParser.h" #include "GraphicsContext.h" - #include <ApplicationServices/ApplicationServices.h> +#include <wtf/RetainPtr.h> namespace WebCore { diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index b1efba1..aac4f45 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <wtf/RetainPtr.h> #include <CoreGraphics/CGContext.h> namespace WebCore { diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 0dc7a53..c82ebdc 100644 --- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -29,15 +29,16 @@ #include "Base64.h" #include "BitmapImage.h" -#include "CString.h" #include "GraphicsContext.h" #include "ImageData.h" #include "MIMETypeRegistry.h" #include "PlatformString.h" #include <ApplicationServices/ApplicationServices.h> #include <wtf/Assertions.h> +#include <wtf/text/CString.h> #include <wtf/OwnArrayPtr.h> #include <wtf/RetainPtr.h> +#include <wtf/Threading.h> #include <math.h> using namespace std; @@ -254,6 +255,8 @@ static RetainPtr<CFStringRef> utiFromMIMEType(const String& mimeType) RetainPtr<CFStringRef> mimeTypeCFString(AdoptCF, mimeType.createCFString()); return RetainPtr<CFStringRef>(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeTypeCFString.get(), 0)); #else + ASSERT(isMainThread()); // It is unclear if CFSTR is threadsafe. + // FIXME: Add Windows support for all the supported UTIs when a way to convert from MIMEType to UTI reliably is found. // For now, only support PNG, JPEG, and GIF. See <rdar://problem/6095286>. static const CFStringRef kUTTypePNG = CFSTR("public.png"); diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index 2b2c6b0..b4e1ca9 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -74,7 +74,7 @@ ImageSource::~ImageSource() void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived) { -#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) // Recent versions of ImageIO discard previously decoded image frames if the client // application no longer holds references to them, so there's no need to throw away // the decoder unless we're explicitly asked to destroy all of the frames. @@ -119,14 +119,22 @@ bool ImageSource::initialized() const void ImageSource::setData(SharedBuffer* data, bool allDataReceived) { - if (!m_decoder) - m_decoder = CGImageSourceCreateIncremental(NULL); #if PLATFORM(MAC) + if (!m_decoder) + m_decoder = CGImageSourceCreateIncremental(0); // 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. RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData()); CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived); #else + if (!m_decoder) { + m_decoder = CGImageSourceCreateIncremental(0); + } else if (allDataReceived) { + // 10.6 bug workaround: image sources with final=false fail to draw into PDF contexts, so re-create image source + // when data is complete. <rdar://problem/7874035> (<http://openradar.appspot.com/7874035>) + CFRelease(m_decoder); + m_decoder = CGImageSourceCreateIncremental(0); + } // Create a CGDataProvider to wrap the SharedBuffer. data->ref(); // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer @@ -234,7 +242,22 @@ CGImageRef ImageSource::createFrameAtIndex(size_t index) bool ImageSource::frameIsCompleteAtIndex(size_t index) { - return CGImageSourceGetStatusAtIndex(m_decoder, index) == kCGImageStatusComplete; + ASSERT(frameCount()); + + // CGImageSourceGetStatusAtIndex claims that all frames of a multi-frame image are incomplete + // when we've not yet received the complete data for an image that is using an incremental data + // source (<rdar://problem/7679174>). We work around this by special-casing all frames except the + // last in an image and treating them as complete if they are present and reported as being + // incomplete. We do this on the assumption that loading new data can only modify the existing last + // frame or append new frames. The last frame is only treated as being complete if the image source + // reports it as such. This ensures that it is truly the last frame of the image rather than just + // the last that we currently have data for. + + CGImageSourceStatus frameStatus = CGImageSourceGetStatusAtIndex(m_decoder, index); + if (index < frameCount() - 1) + return frameStatus >= kCGImageStatusIncomplete; + + return frameStatus == kCGImageStatusComplete; } float ImageSource::frameDurationAtIndex(size_t index) diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp index 67333ae..8bf04f1 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -31,7 +31,9 @@ #include "GraphicsContext.h" #include "ImageObserver.h" +#include "SharedBuffer.h" #include <wtf/MathExtras.h> +#include <wtf/RetainPtr.h> #if !PLATFORM(MAC) #include "ImageSourceCG.h" @@ -54,6 +56,11 @@ PDFDocumentImage::~PDFDocumentImage() CGPDFDocumentRelease(m_document); } +String PDFDocumentImage::filenameExtension() const +{ + return "pdf"; +} + IntSize PDFDocumentImage::size() const { const float sina = sinf(-m_rotation); diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h index 12ab46c..790d620 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.h +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h @@ -46,6 +46,8 @@ namespace WebCore { private: virtual ~PDFDocumentImage(); + virtual String filenameExtension() const; + virtual bool hasSingleSecurityOrigin() const { return true; } virtual bool dataChanged(bool allDataReceived); diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp index 81454b3..eb196d9 100644 --- a/WebCore/platform/graphics/cg/PathCG.cpp +++ b/WebCore/platform/graphics/cg/PathCG.cpp @@ -30,14 +30,14 @@ #if PLATFORM(CG) #include "AffineTransform.h" -#include <ApplicationServices/ApplicationServices.h> #include "FloatRect.h" #include "GraphicsContext.h" #include "IntRect.h" #include "PlatformString.h" #include "StrokeStyleApplier.h" - +#include <ApplicationServices/ApplicationServices.h> #include <wtf/MathExtras.h> +#include <wtf/RetainPtr.h> namespace WebCore { diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp index 8dac612..6f46f7e 100644 --- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -140,6 +140,9 @@ static bool LookupAltName(const String& name, String& altName) // 宋体, SimSun {L"\x5B8B\x4F53", {L"SimSun", simplifiedChineseCodepage}}, {L"simsun", {L"\x5B8B\x4F53", simplifiedChineseCodepage}}, + // 宋体-ExtB, SimSun-ExtB + {L"\x5B8B\x4F53-ExtB", {L"SimSun-ExtB", simplifiedChineseCodepage}}, + {L"simsun-extb", {L"\x5B8B\x4F53-extb", simplifiedChineseCodepage}}, // 黑体, SimHei {L"\x9ED1\x4F53", {L"SimHei", simplifiedChineseCodepage}}, {L"simhei", {L"\x9ED1\x4F53", simplifiedChineseCodepage}}, @@ -164,9 +167,15 @@ static bool LookupAltName(const String& name, String& altName) // 新細明體, PMingLiu {L"\x65B0\x7D30\x660E\x9AD4", {L"PMingLiu", traditionalChineseCodepage}}, {L"pmingliu", {L"\x65B0\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, + // 新細明體-ExtB, PMingLiu-ExtB + {L"\x65B0\x7D30\x660E\x9AD4-ExtB", {L"PMingLiu-ExtB", traditionalChineseCodepage}}, + {L"pmingliu-extb", {L"\x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}}, // 細明體, MingLiu {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}}, {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, + // 細明體-ExtB, MingLiu-ExtB + {L"\x7D30\x660E\x9AD4-ExtB", {L"MingLiu-ExtB", traditionalChineseCodepage}}, + {L"mingliu-extb", {L"x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}}, // 微軟æ£é»‘é«”, Microsoft JhengHei {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", {L"Microsoft JhengHei", traditionalChineseCodepage}}, {L"microsoft jhengHei", {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", traditionalChineseCodepage}}, @@ -363,8 +372,10 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons L"lucida sans unicode", L"microsoft sans serif", L"palatino linotype", - // Four fonts below (and code2000 at the end) are not from MS, but + // Six fonts below (and code2000 at the end) are not from MS, but // once installed, cover a very wide range of characters. + L"dejavu serif", + L"dejavu sasns", L"freeserif", L"freesans", L"gentium", diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp index 03d23c7..ececd13 100644 --- a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp @@ -33,7 +33,6 @@ #include "AtomicString.h" #include "ChromiumBridge.h" -#include "CString.h" #include "Font.h" #include "FontDescription.h" #include "FontPlatformData.h" @@ -47,6 +46,7 @@ #include <unicode/utf16.h> #include <wtf/Assertions.h> +#include <wtf/text/CString.h> namespace WebCore { @@ -107,7 +107,9 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD const char* name = 0; CString s; - if (family.length() == 0) { + // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into + // the fallback name (like "monospace") that fontconfig understands. + if (!family.length() || family.startsWith("-webkit-")) { static const struct { FontDescription::GenericFamilyType mType; const char* mName; @@ -145,6 +147,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD FontPlatformData* result = new FontPlatformData(tf, + name, fontDescription.computedSize(), (style & SkTypeface::kBold) && !tf->isBold(), (style & SkTypeface::kItalic) && !tf->isItalic()); diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 9f8f354..9538a8d 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -503,7 +503,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, context->canvas()->endPlatformPaint(); } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const { UniscribeHelperTextRun state(run, *this); return static_cast<float>(state.width()); diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp index 6432e17..74f1e26 100644 --- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp @@ -101,7 +101,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b return FontPlatformData(hfont, size); #elif OS(LINUX) ASSERT(m_fontReference); - return FontPlatformData(m_fontReference, size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic()); + return FontPlatformData(m_fontReference, "", size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic()); #else notImplemented(); return FontPlatformData(); diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index e76eca8..fa549cd 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -521,7 +521,7 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, } } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const { TextRunWalker walker(run, 0, this); return walker.widthOfFullRun(); diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index bf4697f..2475e65 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "FontPlatformData.h" +#include "ChromiumBridge.h" #include "HarfbuzzSkia.h" #include "NotImplemented.h" #include "PlatformString.h" @@ -66,31 +67,37 @@ FontPlatformData::RefCountedHarfbuzzFace::~RefCountedHarfbuzzFace() FontPlatformData::FontPlatformData(const FontPlatformData& src) : m_typeface(src.m_typeface) + , m_family(src.m_family) , m_textSize(src.m_textSize) , m_fakeBold(src.m_fakeBold) , m_fakeItalic(src.m_fakeItalic) + , m_style(src.m_style) , m_harfbuzzFace(src.m_harfbuzzFace) { m_typeface->safeRef(); } -FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic) +FontPlatformData::FontPlatformData(SkTypeface* tf, const char* family, float textSize, bool fakeBold, bool fakeItalic) : m_typeface(tf) + , m_family(family) , m_textSize(textSize) , m_fakeBold(fakeBold) , m_fakeItalic(fakeItalic) { m_typeface->safeRef(); + querySystemForRenderStyle(); } FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) : m_typeface(src.m_typeface) + , m_family(src.m_family) , m_textSize(textSize) , m_fakeBold(src.m_fakeBold) , m_fakeItalic(src.m_fakeItalic) , m_harfbuzzFace(src.m_harfbuzzFace) { m_typeface->safeRef(); + querySystemForRenderStyle(); } FontPlatformData::~FontPlatformData() @@ -102,10 +109,12 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) { SkRefCnt_SafeAssign(m_typeface, src.m_typeface); + m_family = src.m_family; m_textSize = src.m_textSize; m_fakeBold = src.m_fakeBold; m_fakeItalic = src.m_fakeItalic; m_harfbuzzFace = src.m_harfbuzzFace; + m_style = src.m_style; return *this; } @@ -121,13 +130,26 @@ void FontPlatformData::setupPaint(SkPaint* paint) const { const float ts = m_textSize > 0 ? m_textSize : 12; - paint->setAntiAlias(isSkiaAntiAlias); - paint->setHinting(skiaHinting); - paint->setLCDRenderText(isSkiaSubpixelGlyphs); + paint->setAntiAlias(m_style.useAntiAlias == FontRenderStyle::NoPreference ? isSkiaAntiAlias : m_style.useAntiAlias); + switch (m_style.useHinting) { + case FontRenderStyle::NoPreference: + paint->setHinting(skiaHinting); + break; + case 0: + paint->setHinting(SkPaint::kNo_Hinting); + break; + default: + paint->setHinting(static_cast<SkPaint::Hinting>(m_style.hintStyle)); + break; + } + paint->setTextSize(SkFloatToScalar(ts)); paint->setTypeface(m_typeface); paint->setFakeBoldText(m_fakeBold); paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0); + + if (m_style.useAntiAlias == 1 || m_style.useAntiAlias == FontRenderStyle::NoPreference && isSkiaAntiAlias) + paint->setLCDRenderText(m_style.useSubpixel == FontRenderStyle::NoPreference ? isSkiaSubpixelGlyphs : m_style.useSubpixel); } SkFontID FontPlatformData::uniqueID() const @@ -184,4 +206,21 @@ HB_FaceRec_* FontPlatformData::harfbuzzFace() const return m_harfbuzzFace->face(); } +void FontPlatformData::querySystemForRenderStyle() +{ + if (!m_family.length()) { + // We don't have a family for this. Probably because it's a webfont. We + // set all the values to 'no preference' and take the defaults passed + // in from XSETTINGS. + m_style.useBitmaps = FontRenderStyle::NoPreference; + m_style.useAutoHint = FontRenderStyle::NoPreference; + m_style.useHinting = FontRenderStyle::NoPreference; + m_style.useAntiAlias = FontRenderStyle::NoPreference; + m_style.useSubpixel = FontRenderStyle::NoPreference; + return; + } + + ChromiumBridge::getRenderStyleForStrike(m_family.data(), (((int)m_textSize) << 2) | (m_typeface->style() & 3), &m_style); +} + } // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h index 29ce8e7..e2abe2e 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h @@ -31,8 +31,10 @@ #ifndef FontPlatformDataLinux_h #define FontPlatformDataLinux_h +#include "FontRenderStyle.h" #include "StringImpl.h" #include <wtf/RefPtr.h> +#include <wtf/text/CString.h> #include <SkPaint.h> class SkTypeface; @@ -79,7 +81,7 @@ public: { } FontPlatformData(const FontPlatformData&); - FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic); + FontPlatformData(SkTypeface*, const char* name, float textSize, bool fakeBold, bool fakeItalic); FontPlatformData(const FontPlatformData& src, float textSize); ~FontPlatformData(); @@ -140,11 +142,15 @@ private: HB_FaceRec_* m_harfbuzzFace; }; + void querySystemForRenderStyle(); + // FIXME: Could SkAutoUnref be used here? SkTypeface* m_typeface; + CString m_family; float m_textSize; bool m_fakeBold; bool m_fakeItalic; + FontRenderStyle m_style; mutable RefPtr<RefCountedHarfbuzzFace> m_harfbuzzFace; SkTypeface* hashTableDeletedFontValue() const { return reinterpret_cast<SkTypeface*>(-1); } diff --git a/WebCore/platform/graphics/chromium/FontRenderStyle.h b/WebCore/platform/graphics/chromium/FontRenderStyle.h new file mode 100644 index 0000000..1a3c736 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontRenderStyle.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2010, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontRenderStyle_h +#define FontRenderStyle_h + +namespace WebCore { + +// FontRenderStyle describes the user's preferences for rendering a font at a +// given size. +struct FontRenderStyle { + enum { + NoPreference = 2, + }; + + // Each of the use* members below can take one of three values: + // 0: off + // 1: on + // NoPreference: no preference expressed + char useBitmaps; // use embedded bitmap strike if possible + char useAutoHint; // use 'auto' hinting (FreeType specific) + char useHinting; // hint glyphs to the pixel grid + char hintStyle; // level of hinting, 0..3 + char useAntiAlias; // antialias glyph shapes + char useSubpixel; // use subpixel antialias +}; + +} + +#endif // FontRenderStyle_h diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp index 4e2a226..8dba49e 100644 --- a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -60,6 +60,7 @@ void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) {USCRIPT_GREEK, L"times new roman"}, {USCRIPT_CYRILLIC, L"times new roman"}, {USCRIPT_SIMPLIFIED_HAN, L"simsun"}, + {USCRIPT_TRADITIONAL_HAN, L"pmingliu"}, {USCRIPT_HIRAGANA, L"ms pgothic"}, {USCRIPT_KATAKANA, L"ms pgothic"}, {USCRIPT_KATAKANA_OR_HIRAGANA, L"ms pgothic"}, @@ -106,14 +107,10 @@ void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) localeFamily = scriptFontMap[USCRIPT_HIRAGANA]; else if (locale == icu::Locale::getKorean()) localeFamily = scriptFontMap[USCRIPT_HANGUL]; + else if (locale == icu::Locale::getTraditionalChinese()) + localeFamily = scriptFontMap[USCRIPT_TRADITIONAL_HAN]; else { - // Use Simplified Chinese font for all other locales including - // Traditional Chinese because Simsun (SC font) has a wider - // coverage (covering both SC and TC) than PMingLiu (TC font). - // Note that |fontMap| does not have a separate entry for - // USCRIPT_TRADITIONAL_HAN for that reason. - // This also speeds up the TC version of Chrome when rendering SC - // pages. + // For other locales, use the simplified Chinese font for Han. localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN]; } if (localeFamily) @@ -270,16 +267,27 @@ const UChar* getFallbackFamily(const UChar* characters, if (script == USCRIPT_COMMON) script = getScriptBasedOnUnicodeBlock(ucs4); - // Another lame work-around to cover non-BMP characters. const UChar* family = getFontFamilyForScript(script, generic); - if (!family) { + // Another lame work-around to cover non-BMP characters. + // If the font family for script is not found or the character is + // not in BMP (> U+FFFF), we resort to the hard-coded list of + // fallback fonts for now. + if (!family || ucs4 > 0xFFFF) { int plane = ucs4 >> 16; switch (plane) { case 1: family = L"code2001"; break; case 2: - family = L"simsun-extb"; + // Use a Traditional Chinese ExtB font if in Traditional Chinese locale. + // Otherwise, use a Simplified Chinese ExtB font. Windows Japanese + // fonts do support a small subset of ExtB (that are included in JIS X 0213), + // but its coverage is rather sparse. + // Eventually, this should be controlled by lang/xml:lang. + if (icu::Locale::getDefault() == icu::Locale::getTraditionalChinese()) + family = L"pmingliu-extb"; + else + family = L"simsun-extb"; break; default: family = L"lucida sans unicode"; diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp new file mode 100644 index 0000000..1227a6a --- /dev/null +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * 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: + * + * * 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. + */ + + +/** FIXME + * This file borrows code heavily from platform/graphics/win/GraphicsLayerCACF.cpp + * (and hence it includes both copyrights) + * Ideally the common code (mostly the code that keeps track of the layer hierarchy) + * should be kept separate and shared between platforms. It would be a well worthwhile + * effort once the Windows implementation (binaries and headers) of CoreAnimation is + * checked in to the WebKit repository. Until then only Apple can make this happen. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayerChromium.h" + +#include "FloatConversion.h" +#include "FloatRect.h" +#include "Image.h" +#include "LayerChromium.h" +#include "PlatformString.h" +#include "SystemTime.h" +#include <wtf/CurrentTime.h> +#include <wtf/StringExtras.h> +#include <wtf/text/CString.h> + +using namespace std; + +namespace WebCore { + +static void setLayerBorderColor(LayerChromium& layer, const Color& color) +{ + layer.setBorderColor(color); +} + +static void clearBorderColor(LayerChromium& layer) +{ + layer.setBorderColor(0); +} + +static void setLayerBackgroundColor(LayerChromium& layer, const Color& color) +{ + layer.setBackgroundColor(color); +} + +static void clearLayerBackgroundColor(LayerChromium& layer) +{ + layer.setBackgroundColor(0); +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation() +{ + return CompositingCoordinatesBottomUp; +} + +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) +{ + return new GraphicsLayerChromium(client); +} + +GraphicsLayerChromium::GraphicsLayerChromium(GraphicsLayerClient* client) + : GraphicsLayer(client) + , m_contentsLayerPurpose(NoContentsLayer) + , m_contentsLayerHasBackgroundColor(false) +{ + m_layer = LayerChromium::create(LayerChromium::Layer, this); + + updateDebugIndicators(); +} + +GraphicsLayerChromium::~GraphicsLayerChromium() +{ + // Clean up the Skia layer. + if (m_layer) + m_layer->removeFromSuperlayer(); + + if (m_transformLayer) + m_transformLayer->removeFromSuperlayer(); +} + +void GraphicsLayerChromium::setName(const String& inName) +{ + String name = String::format("GraphicsLayerChromium(%p) GraphicsLayer(%p) ", m_layer.get(), this) + inName; + GraphicsLayer::setName(name); +} + +NativeLayer GraphicsLayerChromium::nativeLayer() const +{ + return m_layer.get(); +} + +bool GraphicsLayerChromium::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + // FIXME: GraphicsLayer::setChildren calls addChild() for each sublayer, which + // will end up calling updateSublayerList() N times. + if (childrenChanged) + updateSublayerList(); + + return childrenChanged; +} + +void GraphicsLayerChromium::addChild(GraphicsLayer* childLayer) +{ + GraphicsLayer::addChild(childLayer); + updateSublayerList(); +} + +void GraphicsLayerChromium::addChildAtIndex(GraphicsLayer* childLayer, int index) +{ + GraphicsLayer::addChildAtIndex(childLayer, index); + updateSublayerList(); +} + +void GraphicsLayerChromium::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildBelow(childLayer, sibling); + updateSublayerList(); +} + +void GraphicsLayerChromium::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer *sibling) +{ + GraphicsLayer::addChildAbove(childLayer, sibling); + updateSublayerList(); +} + +bool GraphicsLayerChromium::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + if (GraphicsLayer::replaceChild(oldChild, newChild)) { + updateSublayerList(); + return true; + } + return false; +} + +void GraphicsLayerChromium::removeFromParent() +{ + GraphicsLayer::removeFromParent(); + layerForSuperlayer()->removeFromSuperlayer(); +} + +void GraphicsLayerChromium::setPosition(const FloatPoint& point) +{ + GraphicsLayer::setPosition(point); + updateLayerPosition(); +} + +void GraphicsLayerChromium::setAnchorPoint(const FloatPoint3D& point) +{ + if (point == m_anchorPoint) + return; + + GraphicsLayer::setAnchorPoint(point); + updateAnchorPoint(); +} + +void GraphicsLayerChromium::setSize(const FloatSize& size) +{ + if (size == m_size) + return; + + GraphicsLayer::setSize(size); + updateLayerSize(); +} + +void GraphicsLayerChromium::setTransform(const TransformationMatrix& transform) +{ + if (transform == m_transform) + return; + + GraphicsLayer::setTransform(transform); + updateTransform(); +} + +void GraphicsLayerChromium::setChildrenTransform(const TransformationMatrix& transform) +{ + if (transform == m_childrenTransform) + return; + + GraphicsLayer::setChildrenTransform(transform); + updateChildrenTransform(); +} + +void GraphicsLayerChromium::setPreserves3D(bool preserves3D) +{ + if (preserves3D == m_preserves3D) + return; + + GraphicsLayer::setPreserves3D(preserves3D); + updateLayerPreserves3D(); +} + +void GraphicsLayerChromium::setMasksToBounds(bool masksToBounds) +{ + if (masksToBounds == m_masksToBounds) + return; + + GraphicsLayer::setMasksToBounds(masksToBounds); + updateMasksToBounds(); +} + +void GraphicsLayerChromium::setDrawsContent(bool drawsContent) +{ + if (drawsContent == m_drawsContent) + return; + + GraphicsLayer::setDrawsContent(drawsContent); + updateLayerDrawsContent(); +} + +void GraphicsLayerChromium::setBackgroundColor(const Color& color) +{ + if (m_backgroundColorSet && m_backgroundColor == color) + return; + + GraphicsLayer::setBackgroundColor(color); + + m_contentsLayerHasBackgroundColor = true; + updateLayerBackgroundColor(); +} + +void GraphicsLayerChromium::clearBackgroundColor() +{ + if (!m_backgroundColorSet) + return; + + GraphicsLayer::clearBackgroundColor(); + clearLayerBackgroundColor(*m_contentsLayer); +} + +void GraphicsLayerChromium::setContentsOpaque(bool opaque) +{ + if (m_contentsOpaque == opaque) + return; + + GraphicsLayer::setContentsOpaque(opaque); + updateContentsOpaque(); +} + +void GraphicsLayerChromium::setBackfaceVisibility(bool visible) +{ + if (m_backfaceVisibility == visible) + return; + + GraphicsLayer::setBackfaceVisibility(visible); + updateBackfaceVisibility(); +} + +void GraphicsLayerChromium::setOpacity(float opacity) +{ + float clampedOpacity = max(min(opacity, 1.0f), 0.0f); + + if (m_opacity == clampedOpacity) + return; + + GraphicsLayer::setOpacity(clampedOpacity); + primaryLayer()->setOpacity(opacity); +} + +void GraphicsLayerChromium::setNeedsDisplay() +{ + if (drawsContent()) + m_layer->setNeedsDisplay(); +} + +void GraphicsLayerChromium::setNeedsDisplayInRect(const FloatRect& rect) +{ + if (drawsContent()) + m_layer->setNeedsDisplay(rect); +} + +void GraphicsLayerChromium::setContentsRect(const IntRect& rect) +{ + if (rect == m_contentsRect) + return; + + GraphicsLayer::setContentsRect(rect); + updateContentsRect(); +} + +void GraphicsLayerChromium::setContentsToImage(Image* image) +{ + // FIXME: Implement +} + +void GraphicsLayerChromium::setContentsToVideo(PlatformLayer* videoLayer) +{ + // FIXME: Implement +} + +void GraphicsLayerChromium::setGeometryOrientation(CompositingCoordinatesOrientation orientation) +{ + if (orientation == m_geometryOrientation) + return; + + GraphicsLayer::setGeometryOrientation(orientation); + updateGeometryOrientation(); +} + +PlatformLayer* GraphicsLayerChromium::hostLayerForSublayers() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerChromium::layerForSuperlayer() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerChromium::platformLayer() const +{ + return primaryLayer(); +} + +void GraphicsLayerChromium::setDebugBackgroundColor(const Color& color) +{ + if (color.isValid()) + setLayerBackgroundColor(*m_layer, color); + else + clearLayerBackgroundColor(*m_layer); +} + +void GraphicsLayerChromium::setDebugBorder(const Color& color, float borderWidth) +{ + if (color.isValid()) { + setLayerBorderColor(*m_layer, color); + m_layer->setBorderWidth(borderWidth); + } else { + clearBorderColor(*m_layer); + m_layer->setBorderWidth(0); + } +} + +void GraphicsLayerChromium::updateSublayerList() +{ + Vector<RefPtr<LayerChromium> > newSublayers; + + if (m_transformLayer) { + // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind. + newSublayers.append(m_layer.get()); + } else if (m_contentsLayer) { + // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. + newSublayers.append(m_contentsLayer.get()); + } + + const Vector<GraphicsLayer*>& childLayers = children(); + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerChromium* curChild = static_cast<GraphicsLayerChromium*>(childLayers[i]); + + LayerChromium* childLayer = curChild->layerForSuperlayer(); + newSublayers.append(childLayer); + } + + for (size_t i = 0; i < newSublayers.size(); ++i) + newSublayers[i]->removeFromSuperlayer(); + + if (m_transformLayer) { + m_transformLayer->setSublayers(newSublayers); + + if (m_contentsLayer) { + // If we have a transform layer, then the contents layer is parented in the + // primary layer (which is itself a child of the transform layer). + m_layer->removeAllSublayers(); + m_layer->addSublayer(m_contentsLayer); + } + } else + m_layer->setSublayers(newSublayers); +} + +void GraphicsLayerChromium::updateLayerPosition() +{ + // Position is offset on the layer by the layer anchor point. + FloatPoint layerPosition(m_position.x() + m_anchorPoint.x() * m_size.width(), + m_position.y() + m_anchorPoint.y() * m_size.height()); + + primaryLayer()->setPosition(layerPosition); +} + +void GraphicsLayerChromium::updateLayerSize() +{ + IntSize layerSize(m_size.width(), m_size.height()); + if (m_transformLayer) { + m_transformLayer->setBounds(layerSize); + // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative. + FloatPoint centerPoint(m_size.width() / 2, m_size.height() / 2); + m_layer->setPosition(centerPoint); + } + + m_layer->setBounds(layerSize); + + // Note that we don't resize m_contentsLayer. It's up the caller to do that. + + // If we've changed the bounds, we need to recalculate the position + // of the layer, taking anchor point into account. + updateLayerPosition(); +} + +void GraphicsLayerChromium::updateAnchorPoint() +{ + primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())); + primaryLayer()->setAnchorPointZ(m_anchorPoint.z()); + updateLayerPosition(); +} + +void GraphicsLayerChromium::updateTransform() +{ + primaryLayer()->setTransform(m_transform); +} + +void GraphicsLayerChromium::updateChildrenTransform() +{ + primaryLayer()->setSublayerTransform(m_childrenTransform); +} + +void GraphicsLayerChromium::updateMasksToBounds() +{ + m_layer->setMasksToBounds(m_masksToBounds); + updateDebugIndicators(); +} + +void GraphicsLayerChromium::updateContentsOpaque() +{ + m_layer->setOpaque(m_contentsOpaque); +} + +void GraphicsLayerChromium::updateBackfaceVisibility() +{ + m_layer->setDoubleSided(m_backfaceVisibility); +} + +void GraphicsLayerChromium::updateLayerPreserves3D() +{ + // FIXME: implement +} + +void GraphicsLayerChromium::updateLayerDrawsContent() +{ + if (m_drawsContent) + m_layer->setNeedsDisplay(); + + updateDebugIndicators(); +} + +void GraphicsLayerChromium::updateLayerBackgroundColor() +{ + if (!m_contentsLayer) + return; + + // We never create the contents layer just for background color yet. + if (m_backgroundColorSet) + setLayerBackgroundColor(*m_contentsLayer, m_backgroundColor); + else + clearLayerBackgroundColor(*m_contentsLayer); +} + +void GraphicsLayerChromium::updateContentsImage() +{ + // FIXME: Implement +} + +void GraphicsLayerChromium::updateContentsVideo() +{ + // FIXME: Implement +} + +void GraphicsLayerChromium::updateContentsRect() +{ + if (!m_contentsLayer) + return; + + m_contentsLayer->setPosition(FloatPoint(m_contentsRect.x(), m_contentsRect.y())); + m_contentsLayer->setBounds(IntSize(m_contentsRect.width(), m_contentsRect.height())); +} + +void GraphicsLayerChromium::updateGeometryOrientation() +{ + switch (geometryOrientation()) { + case CompositingCoordinatesTopDown: + m_layer->setGeometryFlipped(false); + break; + + case CompositingCoordinatesBottomUp: + m_layer->setGeometryFlipped(true); + break; + } + // Geometry orientation is mapped onto children transform in older QuartzCores, + // so is handled via setGeometryOrientation(). +} + +void GraphicsLayerChromium::setupContentsLayer(LayerChromium* contentsLayer) +{ + if (contentsLayer == m_contentsLayer) + return; + + if (m_contentsLayer) { + m_contentsLayer->removeFromSuperlayer(); + m_contentsLayer = 0; + } + + if (contentsLayer) { + m_contentsLayer = contentsLayer; + + m_contentsLayer->setAnchorPoint(FloatPoint(0, 0)); + + // Insert the content layer first. Video elements require this, because they have + // shadow content that must display in front of the video. + m_layer->insertSublayer(m_contentsLayer.get(), 0); + + updateContentsRect(); + + if (showDebugBorders()) { + setLayerBorderColor(*m_contentsLayer, Color(0, 0, 128, 180)); + m_contentsLayer->setBorderWidth(1); + } + } + updateDebugIndicators(); +} + +// This function simply mimics the operation of GraphicsLayerCA +void GraphicsLayerChromium::updateOpacityOnLayer() +{ + primaryLayer()->setOpacity(m_opacity); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h new file mode 100644 index 0000000..03a6d41 --- /dev/null +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GraphicsLayerChromium_h +#define GraphicsLayerChromium_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsContext.h" +#include "GraphicsLayer.h" + +namespace WebCore { + +class LayerChromium; + +class GraphicsLayerChromium : public GraphicsLayer { +public: + GraphicsLayerChromium(GraphicsLayerClient*); + virtual ~GraphicsLayerChromium(); + + virtual void setName(const String&); + + // for hosting this GraphicsLayer in a native layer hierarchy + virtual NativeLayer nativeLayer() const; + + virtual bool setChildren(const Vector<GraphicsLayer*>&); + virtual void addChild(GraphicsLayer*); + virtual void addChildAtIndex(GraphicsLayer*, int index); + virtual void addChildAbove(GraphicsLayer*, GraphicsLayer* sibling); + virtual void addChildBelow(GraphicsLayer*, GraphicsLayer* sibling); + virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild); + + virtual void removeFromParent(); + + virtual void setPosition(const FloatPoint&); + virtual void setAnchorPoint(const FloatPoint3D&); + virtual void setSize(const FloatSize&); + + virtual void setTransform(const TransformationMatrix&); + + virtual void setChildrenTransform(const TransformationMatrix&); + + virtual void setPreserves3D(bool); + virtual void setMasksToBounds(bool); + virtual void setDrawsContent(bool); + + virtual void setBackgroundColor(const Color&); + virtual void clearBackgroundColor(); + + virtual void setContentsOpaque(bool); + virtual void setBackfaceVisibility(bool); + + virtual void setOpacity(float); + + virtual void setNeedsDisplay(); + virtual void setNeedsDisplayInRect(const FloatRect&); + + virtual void setContentsRect(const IntRect&); + + virtual void setContentsToImage(Image*); + virtual void setContentsToVideo(PlatformLayer*); + + virtual PlatformLayer* platformLayer() const; + + virtual void setDebugBackgroundColor(const Color&); + virtual void setDebugBorder(const Color&, float borderWidth); + + virtual void setGeometryOrientation(CompositingCoordinatesOrientation); + + void notifySyncRequired() + { + if (m_client) + m_client->notifySyncRequired(this); + } + +private: + void updateOpacityOnLayer(); + + LayerChromium* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); } + LayerChromium* hostLayerForSublayers() const; + LayerChromium* layerForSuperlayer() const; + + void updateSublayerList(); + void updateLayerPosition(); + void updateLayerSize(); + void updateAnchorPoint(); + void updateTransform(); + void updateChildrenTransform(); + void updateMasksToBounds(); + void updateContentsOpaque(); + void updateBackfaceVisibility(); + void updateLayerPreserves3D(); + void updateLayerDrawsContent(); + void updateLayerBackgroundColor(); + + void updateContentsImage(); + void updateContentsVideo(); + void updateContentsRect(); + void updateGeometryOrientation(); + + void setupContentsLayer(LayerChromium*); + LayerChromium* contentsLayer() const { return m_contentsLayer.get(); } + + RefPtr<LayerChromium> m_layer; + RefPtr<LayerChromium> m_transformLayer; + RefPtr<LayerChromium> m_contentsLayer; + + enum ContentsLayerPurpose { + NoContentsLayer = 0, + ContentsLayerForImage, + ContentsLayerForVideo + }; + + ContentsLayerPurpose m_contentsLayerPurpose; + bool m_contentsLayerHasBackgroundColor : 1; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif diff --git a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp index 1386163..16f55e2 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp @@ -46,12 +46,6 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) -{ - notImplemented(); - return 0; -} - void Icon::paint(GraphicsContext*, const IntRect&) { notImplemented(); diff --git a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp index 23ca698..a24afb2 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp @@ -39,11 +39,6 @@ namespace WebCore { -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) -{ - return 0; -} - Icon::~Icon() { } diff --git a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp index b0145f8..e958d4a 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp @@ -52,13 +52,6 @@ Icon::~Icon() DestroyIcon(m_icon); } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) -{ - // FIXME: We can't access icons directly from renderer processes. - // http://code.google.com/p/chromium/issues/detail?id=4092 - return 0; -} - void Icon::paint(GraphicsContext* context, const IntRect& rect) { if (context->paintingDisabled()) diff --git a/WebCore/platform/graphics/chromium/LayerChromium.cpp b/WebCore/platform/graphics/chromium/LayerChromium.cpp new file mode 100644 index 0000000..4540ac1 --- /dev/null +++ b/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "LayerChromium.h" + +#include "PlatformContextSkia.h" +#include "RenderLayerBacking.h" +#include "skia/ext/platform_canvas.h" + +namespace WebCore { + +using namespace std; + +PassRefPtr<LayerChromium> LayerChromium::create(LayerType type, GraphicsLayerChromium* owner) +{ + return adoptRef(new LayerChromium(type, owner)); +} + +LayerChromium::LayerChromium(LayerType type, GraphicsLayerChromium* owner) + : m_needsDisplayOnBoundsChange(false) + , m_owner(owner) + , m_layerType(type) + , m_superlayer(0) + , m_borderWidth(0) + , m_borderColor(0, 0, 0, 0) + , m_backgroundColor(0, 0, 0, 0) + , m_anchorPointZ(0) + , m_clearsContext(false) + , m_doubleSided(false) + , m_edgeAntialiasingMask(0) + , m_hidden(false) + , m_masksToBounds(false) + , m_contentsGravity(Bottom) + , m_opacity(1.0) + , m_opaque(true) + , m_zPosition(0.0) + , m_canvas(0) + , m_skiaContext(0) + , m_graphicsContext(0) + , m_geometryFlipped(false) +{ + updateGraphicsContext(m_backingStoreRect); +} + +LayerChromium::~LayerChromium() +{ + // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer. + ASSERT(!superlayer()); +} + +void LayerChromium::updateGraphicsContext(const IntSize& size) +{ +#if PLATFORM(SKIA) + // Create new canvas and context. OwnPtr takes care of freeing up + // the old ones. + m_canvas = new skia::PlatformCanvas(size.width(), size.height(), false); + m_skiaContext = new PlatformContextSkia(m_canvas.get()); + + // This is needed to get text to show up correctly. Without it, + // GDI renders with zero alpha and the text becomes invisible. + // Unfortunately, setting this to true disables cleartype. + m_skiaContext->setDrawingToImageBuffer(true); + + m_graphicsContext = new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(m_skiaContext.get())); +#else +#error "Need to implement for your platform." +#endif + // The backing store allocated for a layer can be smaller than the layer's bounds. + // This is mostly true for the root layer whose backing store is sized based on the visible + // portion of the layer rather than the actual page size. + m_backingStoreRect = size; +} + +void LayerChromium::updateContents() +{ + RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); + + if (backing && !backing->paintingGoesToWindow()) + m_owner->paintGraphicsLayerContents(*m_graphicsContext, IntRect(0, 0, m_bounds.width(), m_bounds.height())); +} + +void LayerChromium::drawDebugBorder() +{ + m_graphicsContext->setStrokeColor(m_borderColor, DeviceColorSpace); + m_graphicsContext->setStrokeThickness(m_borderWidth); + m_graphicsContext->drawLine(IntPoint(0, 0), IntPoint(m_bounds.width(), 0)); + m_graphicsContext->drawLine(IntPoint(0, 0), IntPoint(0, m_bounds.height())); + m_graphicsContext->drawLine(IntPoint(m_bounds.width(), 0), IntPoint(m_bounds.width(), m_bounds.height())); + m_graphicsContext->drawLine(IntPoint(0, m_bounds.height()), IntPoint(m_bounds.width(), m_bounds.height())); +} + +void LayerChromium::setNeedsCommit() +{ + // Call notifySyncRequired(), which in this implementation plumbs through to + // call setRootLayerNeedsDisplay() on the WebView, which will cause LayerRendererSkia + // to render a frame. + if (m_owner) + m_owner->notifySyncRequired(); +} + +void LayerChromium::addSublayer(PassRefPtr<LayerChromium> sublayer) +{ + insertSublayer(sublayer, numSublayers()); +} + +void LayerChromium::insertSublayer(PassRefPtr<LayerChromium> sublayer, size_t index) +{ + index = min(index, m_sublayers.size()); + m_sublayers.insert(index, sublayer); + sublayer->setSuperlayer(this); + setNeedsCommit(); +} + +void LayerChromium::removeFromSuperlayer() +{ + LayerChromium* superlayer = this->superlayer(); + if (!superlayer) + return; + + superlayer->removeSublayer(this); +} + +void LayerChromium::removeSublayer(LayerChromium* sublayer) +{ + int foundIndex = indexOfSublayer(sublayer); + if (foundIndex == -1) + return; + + m_sublayers.remove(foundIndex); + sublayer->setSuperlayer(0); + setNeedsCommit(); +} + +int LayerChromium::indexOfSublayer(const LayerChromium* reference) +{ + for (size_t i = 0; i < m_sublayers.size(); i++) { + if (m_sublayers[i] == reference) + return i; + } + return -1; +} + +void LayerChromium::setBackingStoreRect(const IntSize& rect) +{ + if (m_backingStoreRect == rect) + return; + + updateGraphicsContext(rect); +} + +void LayerChromium::setBounds(const IntSize& rect) +{ + if (rect == m_bounds) + return; + + m_bounds = rect; + + // Re-create the canvas and associated contexts. + updateGraphicsContext(m_bounds); + + // Layer contents need to be redrawn as the backing surface + // was recreated above. + updateContents(); + + setNeedsCommit(); +} + +void LayerChromium::setFrame(const FloatRect& rect) +{ + if (rect == m_frame) + return; + + m_frame = rect; + setNeedsCommit(); +} + +const LayerChromium* LayerChromium::rootLayer() const +{ + const LayerChromium* layer = this; + for (LayerChromium* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { } + return layer; +} + +void LayerChromium::removeAllSublayers() +{ + m_sublayers.clear(); + setNeedsCommit(); +} + +void LayerChromium::setSublayers(const Vector<RefPtr<LayerChromium> >& sublayers) +{ + m_sublayers = sublayers; +} + +void LayerChromium::setSuperlayer(LayerChromium* superlayer) +{ + m_superlayer = superlayer; +} + +LayerChromium* LayerChromium::superlayer() const +{ + return m_superlayer; +} + +void LayerChromium::setNeedsDisplay(const FloatRect& dirtyRect) +{ + // Redraw the contents of the layer. + updateContents(); + + setNeedsCommit(); +} + +void LayerChromium::setNeedsDisplay() +{ + // FIXME: implement +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/LayerChromium.h b/WebCore/platform/graphics/chromium/LayerChromium.h new file mode 100644 index 0000000..55b1288 --- /dev/null +++ b/WebCore/platform/graphics/chromium/LayerChromium.h @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef LayerChromium_h +#define LayerChromium_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "FloatPoint.h" +#include "GraphicsContext.h" +#include "GraphicsLayerChromium.h" +#include "PlatformString.h" +#include "StringHash.h" +#include "TransformationMatrix.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + + +namespace skia { +class PlatformCanvas; +} + +namespace WebCore { + +class LayerChromium : public RefCounted<LayerChromium> { +public: + enum LayerType { Layer, TransformLayer }; + enum FilterType { Linear, Nearest, Trilinear, Lanczos }; + enum ContentsGravityType { Center, Top, Bottom, Left, Right, TopLeft, TopRight, + BottomLeft, BottomRight, Resize, ResizeAspect, ResizeAspectFill }; + + static PassRefPtr<LayerChromium> create(LayerType, GraphicsLayerChromium* owner = 0); + + ~LayerChromium(); + + void display(PlatformGraphicsContext*); + + void addSublayer(PassRefPtr<LayerChromium>); + void insertSublayer(PassRefPtr<LayerChromium>, size_t index); + void removeFromSuperlayer(); + + void setAnchorPoint(const FloatPoint& anchorPoint) { m_anchorPoint = anchorPoint; setNeedsCommit(); } + FloatPoint anchorPoint() const { return m_anchorPoint; } + + void setAnchorPointZ(float anchorPointZ) { m_anchorPointZ = anchorPointZ; setNeedsCommit(); } + float anchorPointZ() const { return m_anchorPointZ; } + + void setBackgroundColor(const Color& color) { m_backgroundColor = color; setNeedsCommit(); } + Color backgroundColor() const { return m_backgroundColor; } + + void setBorderColor(const Color& color) { m_borderColor = color; setNeedsCommit(); } + Color borderColor() const { return m_borderColor; } + + void setBorderWidth(float width) { m_borderWidth = width; setNeedsCommit(); } + float borderWidth() const { return m_borderWidth; } + + void setBounds(const IntSize&); + IntSize bounds() const { return m_bounds; } + + void setClearsContext(bool clears) { m_clearsContext = clears; setNeedsCommit(); } + bool clearsContext() const { return m_clearsContext; } + + void setContentsGravity(ContentsGravityType gravityType) { m_contentsGravity = gravityType; setNeedsCommit(); } + ContentsGravityType contentsGravity() const { return m_contentsGravity; } + + void setDoubleSided(bool doubleSided) { m_doubleSided = doubleSided; setNeedsCommit(); } + bool doubleSided() const { return m_doubleSided; } + + void setEdgeAntialiasingMask(uint32_t mask) { m_edgeAntialiasingMask = mask; setNeedsCommit(); } + uint32_t edgeAntialiasingMask() const { return m_edgeAntialiasingMask; } + + void setFrame(const FloatRect&); + FloatRect frame() const { return m_frame; } + + void setHidden(bool hidden) { m_hidden = hidden; setNeedsCommit(); } + bool isHidden() const { return m_hidden; } + + void setMasksToBounds(bool masksToBounds) { m_masksToBounds = masksToBounds; } + bool masksToBounds() const { return m_masksToBounds; } + + void setName(const String& name) { m_name = name; } + String name() const { return m_name; } + + void setNeedsDisplay(const FloatRect& dirtyRect); + void setNeedsDisplay(); + + void setNeedsDisplayOnBoundsChange(bool needsDisplay) { m_needsDisplayOnBoundsChange = needsDisplay; } + + void setOpacity(float opacity) { m_opacity = opacity; setNeedsCommit(); } + float opacity() const { return m_opacity; } + + void setOpaque(bool opaque) { m_opaque = opaque; setNeedsCommit(); } + bool opaque() const { return m_opaque; } + + void setPosition(const FloatPoint& position) { m_position = position; setNeedsCommit(); } + + FloatPoint position() const { return m_position; } + + void setZPosition(float zPosition) { m_zPosition = zPosition; setNeedsCommit(); } + float zPosition() const { return m_zPosition; } + + const LayerChromium* rootLayer() const; + + void removeAllSublayers(); + + void setSublayers(const Vector<RefPtr<LayerChromium> >&); + + const Vector<RefPtr<LayerChromium> >& getSublayers() const { return m_sublayers; } + + void setSublayerTransform(const TransformationMatrix& transform) { m_sublayerTransform = transform; setNeedsCommit(); } + const TransformationMatrix& sublayerTransform() const { return m_sublayerTransform; } + + void setSuperlayer(LayerChromium* superlayer); + LayerChromium* superlayer() const; + + + void setTransform(const TransformationMatrix& transform) { m_transform = transform; setNeedsCommit(); } + const TransformationMatrix& transform() const { return m_transform; } + + void setGeometryFlipped(bool flipped) { m_geometryFlipped = flipped; setNeedsCommit(); } + bool geometryFlipped() const { return m_geometryFlipped; } + + void updateContents(); + + skia::PlatformCanvas* platformCanvas() { return m_canvas.get(); } + GraphicsContext* graphicsContext() { return m_graphicsContext.get(); } + + void setBackingStoreRect(const IntSize&); + + void drawDebugBorder(); + +private: + LayerChromium(LayerType, GraphicsLayerChromium* owner); + + void setNeedsCommit(); + + void paintMe(); + + size_t numSublayers() const + { + return m_sublayers.size(); + } + + // Returns the index of the sublayer or -1 if not found. + int indexOfSublayer(const LayerChromium*); + + // This should only be called from removeFromSuperlayer. + void removeSublayer(LayerChromium*); + + // Re-create the canvas and graphics context. This method + // must be called every time the layer is resized. + void updateGraphicsContext(const IntSize&); + + Vector<RefPtr<LayerChromium> > m_sublayers; + LayerChromium* m_superlayer; + + GraphicsLayerChromium* m_owner; + OwnPtr<skia::PlatformCanvas> m_canvas; + OwnPtr<PlatformContextSkia> m_skiaContext; + OwnPtr<GraphicsContext> m_graphicsContext; + + LayerType m_layerType; + + IntSize m_bounds; + IntSize m_backingStoreRect; + FloatPoint m_position; + FloatPoint m_anchorPoint; + Color m_backgroundColor; + Color m_borderColor; + + FloatRect m_frame; + TransformationMatrix m_transform; + TransformationMatrix m_sublayerTransform; + + uint32_t m_edgeAntialiasingMask; + float m_opacity; + float m_zPosition; + float m_anchorPointZ; + float m_borderWidth; + + bool m_clearsContext; + bool m_doubleSided; + bool m_hidden; + bool m_masksToBounds; + bool m_opaque; + bool m_geometryFlipped; + bool m_needsDisplayOnBoundsChange; + + ContentsGravityType m_contentsGravity; + String m_name; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp new file mode 100644 index 0000000..722c80c --- /dev/null +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) +#include "LayerRendererChromium.h" + +#include "LayerChromium.h" +#include "PlatformContextSkia.h" +#include "skia/ext/platform_canvas.h" + +namespace WebCore { + +PassOwnPtr<LayerRendererChromium> LayerRendererChromium::create() +{ + return new LayerRendererChromium(); +} + +LayerRendererChromium::LayerRendererChromium() + : m_rootLayer(0) + , m_needsDisplay(false) +{ +} + +LayerRendererChromium::~LayerRendererChromium() +{ +} + +void LayerRendererChromium::updateLayerContents() +{ + if (m_rootLayer) + updateLayerContentsRecursive(m_rootLayer.get()); +} + +#if PLATFORM(SKIA) +void LayerRendererChromium::drawLayersInCanvas(skia::PlatformCanvas* canvas, const IntRect& clipRect) +{ + if (!m_rootLayer) + return; + + canvas->save(); + canvas->clipRect(SkRect(clipRect)); + + // First composite the root layer into the canvas. + canvas->drawBitmap(m_rootLayer->platformCanvas()->getDevice()->accessBitmap(false), 0, 0, 0); + + // Account for the scroll offset before compositing the remaining layers. + // Note that the root layer's painting takes into account the scroll offset already. + canvas->translate(-m_scrollFrame.fLeft, -m_scrollFrame.fTop); + + float opacity = 1.0f; + const Vector<RefPtr<LayerChromium> >& sublayers = m_rootLayer->getSublayers(); + for (size_t i = 0; i < sublayers.size(); i++) + drawLayerInCanvasRecursive(canvas, sublayers[i].get(), opacity); + + canvas->restore(); + + m_needsDisplay = false; +} + +void LayerRendererChromium::drawLayerInCanvasRecursive(skia::PlatformCanvas* canvas, LayerChromium* layer, float opacity) +{ + // Guarantees that the canvas is restored to a known state on destruction. + SkAutoCanvasRestore autoRestoreCanvas(canvas, true); + + FloatPoint position = layer->position(); + FloatPoint anchorPoint = layer->anchorPoint(); + SkMatrix transform = layer->transform().toAffineTransform(); + IntSize bounds = layer->bounds(); + + canvas->translate(position.x(), position.y()); + + SkScalar tx = SkScalarMul(anchorPoint.x(), bounds.width()); + SkScalar ty = SkScalarMul(anchorPoint.y(), bounds.height()); + canvas->translate(tx, ty); + canvas->concat(transform); + canvas->translate(-tx, -ty); + + // The position we get is for the center of the layer, but + // drawBitmap starts at the upper-left corner, and therefore + // we need to adjust our transform. + canvas->translate(-0.5f * bounds.width(), -0.5f * bounds.height()); + + layer->drawDebugBorder(); + + SkPaint opacityPaint; + opacity *= layer->opacity(); + opacityPaint.setAlpha(opacity * 255); + + canvas->drawBitmap(layer->platformCanvas()->getDevice()->accessBitmap(false), 0, 0, &opacityPaint); + + const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); + for (size_t i = 0; i < sublayers.size(); i++) + drawLayerInCanvasRecursive(canvas, sublayers[i].get(), opacity); +} +#endif // PLATFORM(SKIA) + +void LayerRendererChromium::updateLayerContentsRecursive(LayerChromium* layer) +{ + layer->updateContents(); + + const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); + for (size_t i = 0; i < sublayers.size(); i++) + updateLayerContentsRecursive(sublayers[i].get()); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/WebCore/platform/graphics/chromium/LayerRendererChromium.h new file mode 100644 index 0000000..7eb429f --- /dev/null +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef LayerRendererChromium_h +#define LayerRendererChromium_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "IntRect.h" +#include "LayerChromium.h" +#include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +namespace skia { +class PlatformCanvas; +} + +namespace WebCore { + +class LayerRendererChromium : public Noncopyable { +public: + static PassOwnPtr<LayerRendererChromium> create(); + + LayerRendererChromium(); + ~LayerRendererChromium(); + +#if PLATFORM(SKIA) + void drawLayersInCanvas(skia::PlatformCanvas*, const IntRect& clipRect); +#endif + void updateLayerContents(); + + void setRootLayer(PassRefPtr<LayerChromium> layer) { m_rootLayer = layer; } + LayerChromium* rootLayer() { return m_rootLayer.get(); } + + void setNeedsDisplay() { m_needsDisplay = true; } + + void setScrollFrame(SkIRect& scrollFrame) { m_scrollFrame = scrollFrame; } + +private: +#if PLATFORM(SKIA) + void drawLayerInCanvasRecursive(skia::PlatformCanvas*, LayerChromium*, float opacity); +#endif + void updateLayerContentsRecursive(LayerChromium*); + + RefPtr<LayerChromium> m_rootLayer; + + bool m_needsDisplay; + SkIRect m_scrollFrame; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp index 3d68ea8..72bbfb4 100644 --- a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp @@ -151,7 +151,7 @@ void SimpleFontData::determinePitch() ReleaseDC(0, dc); } -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode) const { HDC dc = GetDC(0); HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); @@ -170,7 +170,9 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const SelectObject(dc, oldFont); ReleaseDC(0, dc); - return static_cast<float>(width); + GlyphMetrics metrics; + metrics.horizontalAdvance = static_cast<float>(width); + return metrics; } } // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp index 3bff83f..8c639aa 100644 --- a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -172,7 +172,7 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = platformData().isFixedPitch(); } -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode /* metricsMode */) const { SkASSERT(sizeof(glyph) == 2); // compile-time assert @@ -183,7 +183,12 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkScalar width = paint.measureText(&glyph, 2); - return SkScalarToFloat(width); + // Though WebKit supports non-integral advances, Skia only supports them + // for "subpixel" (distinct from LCD subpixel antialiasing) text, which + // we don't use. + GlyphMetrics metrics; + metrics.horizontalAdvance = round(SkScalarToFloat(width)); + return metrics; } } // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp index 10fcdf6..dda84a9 100644 --- a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp +++ b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp @@ -398,7 +398,6 @@ void UniscribeHelper::draw(GraphicsContext* graphicsContext, &shaping.m_advance[fromGlyph], justify, &shaping.m_offsets[fromGlyph]); - ASSERT(S_OK == hr); textOutOk = (hr == S_OK); } else { SkPoint origin; diff --git a/WebCore/platform/graphics/efl/FloatRectEfl.cpp b/WebCore/platform/graphics/efl/FloatRectEfl.cpp new file mode 100644 index 0000000..12f8d03 --- /dev/null +++ b/WebCore/platform/graphics/efl/FloatRectEfl.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics + * + * 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 "FloatRect.h" + +namespace WebCore { + +FloatRect::FloatRect(const Eina_Rectangle& r) + : m_location(FloatPoint(r.x, r.y)) + , m_size(r.w, r.h) +{ +} + +FloatRect::operator Eina_Rectangle() const // NOLINT +{ + Eina_Rectangle r = {(int) round(x()), (int) round(y()), (int) round(width()), (int) round(height())}; + return r; +} + +} + diff --git a/WebCore/platform/graphics/efl/FontEfl.cpp b/WebCore/platform/graphics/efl/FontEfl.cpp new file mode 100644 index 0000000..2aeb397 --- /dev/null +++ b/WebCore/platform/graphics/efl/FontEfl.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2006 Apple Inc. All rights reserved. + * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Font.h" + +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "SimpleFontData.h" + +#include <cairo.h> + +namespace WebCore { + +void Font::drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const +{ + notImplemented(); +} + +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + +float Font::floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>*, GlyphOverflow*) const +{ + notImplemented(); + return 0.0f; +} + +int Font::offsetForPositionForComplexText(const TextRun&, int, bool) const +{ + notImplemented(); + return 0; +} + +FloatRect Font::selectionRectForComplexText(const TextRun&, const IntPoint&, int, int, int) const +{ + notImplemented(); + return FloatRect(); +} + +} diff --git a/WebCore/platform/graphics/win/FontDatabase.h b/WebCore/platform/graphics/efl/IconEfl.cpp index 4f76c9e..6b3de04 100644 --- a/WebCore/platform/graphics/win/FontDatabase.h +++ b/WebCore/platform/graphics/efl/IconEfl.cpp @@ -1,5 +1,9 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,13 +30,37 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FontDatabase_h -#define FontDatabase_h +#include "config.h" + +#include "Icon.h" + +#include "GraphicsContext.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "PassRefPtr.h" +#include "PlatformString.h" namespace WebCore { - void populateFontDatabase(); +Icon::Icon() + : m_icon(0) +{ + notImplemented(); +} + +Icon::~Icon() +{ +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + notImplemented(); + return 0; +} -} // namespace WebCore +void Icon::paint(GraphicsContext* context, const IntRect& rect) +{ + notImplemented(); +} -#endif // !defined(FontDatabase_h) +} diff --git a/WebCore/platform/graphics/efl/ImageEfl.cpp b/WebCore/platform/graphics/efl/ImageEfl.cpp new file mode 100644 index 0000000..112770f --- /dev/null +++ b/WebCore/platform/graphics/efl/ImageEfl.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Kenneth Rohde Christiansen. All rights reserved. + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics + * + * 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 "SharedBuffer.h" + +#include <cairo.h> + +namespace WebCore { + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +static PassRefPtr<SharedBuffer> loadResourceSharedBufferFallback() +{ + return SharedBuffer::create(); // TODO: fallback image? +} + +static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(const char* name) +{ + RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(String::format(DATA_DIR "/webkit-1.0/images/%s.png", name)); + if (buffer) + return buffer.release(); + return loadResourceSharedBufferFallback(); +} + +PassRefPtr<Image> Image::loadPlatformResource(const char* name) +{ + RefPtr<BitmapImage> img = BitmapImage::create(); + RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(name); + img->setData(buffer.release(), true); + return img.release(); +} + +} diff --git a/WebCore/platform/graphics/efl/IntPointEfl.cpp b/WebCore/platform/graphics/efl/IntPointEfl.cpp new file mode 100644 index 0000000..76a25e1 --- /dev/null +++ b/WebCore/platform/graphics/efl/IntPointEfl.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics + * + * 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 "IntPoint.h" + +#include <Evas.h> + +namespace WebCore { + +IntPoint::IntPoint(const Evas_Point& p) + : m_x(p.x) + , m_y(p.y) +{ +} + +IntPoint::operator Evas_Point() const // NOLINT +{ + Evas_Point p = { x(), y() }; + return p; +} + +} diff --git a/WebCore/platform/graphics/efl/IntRectEfl.cpp b/WebCore/platform/graphics/efl/IntRectEfl.cpp new file mode 100644 index 0000000..5ff8626 --- /dev/null +++ b/WebCore/platform/graphics/efl/IntRectEfl.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics + * + * 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 "IntRect.h" + +namespace WebCore { + +IntRect::IntRect(const Eina_Rectangle& r) + : m_location(IntPoint(r.x, r.y)) + , m_size(r.w, r.h) +{ +} + +IntRect::operator Eina_Rectangle() const // NOLINT +{ + Eina_Rectangle r = { x(), y(), width(), height() }; + return r; +} + +} + diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp index 567da74..567da74 100644 --- a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.h b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h index 3e88f63..3e88f63 100644 --- a/WebCore/platform/graphics/gtk/DataSourceGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h diff --git a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp new file mode 100644 index 0000000..1d14b5a --- /dev/null +++ b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU 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 "GOwnPtrGStreamer.h" + +#if ENABLE(VIDEO) +#include <gst/gstelement.h> + +namespace WTF { + +template <> void freeOwnedGPtr<GstElement>(GstElement* ptr) +{ + if (ptr) + gst_object_unref(ptr); +} +#endif + +} diff --git a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h new file mode 100644 index 0000000..6655f38 --- /dev/null +++ b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GOwnPtrGStreamer_h +#define GOwnPtrGStreamer_h + +#include "GOwnPtr.h" + +typedef struct _GstElement GstElement; + +namespace WTF { + +template<> void freeOwnedGPtr<GstElement>(GstElement* ptr); + +} + +#endif diff --git a/WebCore/platform/graphics/gstreamer/ImageGStreamer.h b/WebCore/platform/graphics/gstreamer/ImageGStreamer.h new file mode 100644 index 0000000..2e97b4d --- /dev/null +++ b/WebCore/platform/graphics/gstreamer/ImageGStreamer.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef ImageGStreamer_h +#define ImageGStreamer_h + +#if ENABLE(VIDEO) + +#include "BitmapImage.h" + +#include <gst/gst.h> +#include <gst/video/video.h> +#include <wtf/PassRefPtr.h> + +#if PLATFORM(CAIRO) +#include <cairo.h> +#endif + +namespace WebCore { +class IntSize; + +class ImageGStreamer : public RefCounted<ImageGStreamer> { + public: + static PassRefPtr<ImageGStreamer> createImage(GstBuffer*); + ~ImageGStreamer(); + + PassRefPtr<BitmapImage> image() + { + ASSERT(m_image); + return m_image.get(); + } + + private: + RefPtr<BitmapImage> m_image; + +#if PLATFORM(CAIRO) + ImageGStreamer(GstBuffer*&, IntSize, cairo_format_t&); + cairo_surface_t* m_surface; +#endif + + }; +} + +#endif + +#endif diff --git a/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp b/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp new file mode 100644 index 0000000..6f975a4 --- /dev/null +++ b/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include "GOwnPtr.h" +#include "ImageGStreamer.h" + +using namespace std; + +using namespace WebCore; + +PassRefPtr<ImageGStreamer> ImageGStreamer::createImage(GstBuffer* buffer) +{ + int width = 0, height = 0; + GstCaps* caps = gst_buffer_get_caps(buffer); + GstVideoFormat format; + if (!gst_video_format_parse_caps(caps, &format, &width, &height)) { + gst_caps_unref(caps); + return 0; + } + + gst_caps_unref(caps); + + cairo_format_t cairoFormat; + if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) + cairoFormat = CAIRO_FORMAT_ARGB32; + else + cairoFormat = CAIRO_FORMAT_RGB24; + + return adoptRef(new ImageGStreamer(buffer, IntSize(width, height), cairoFormat)); +} + +ImageGStreamer::ImageGStreamer(GstBuffer*& buffer, IntSize size, cairo_format_t& cairoFormat) + : m_image(0) + , m_surface(0) +{ + m_surface = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), cairoFormat, + size.width(), size.height(), + cairo_format_stride_for_width(cairoFormat, size.width())); + ASSERT(cairo_surface_status(m_surface) == CAIRO_STATUS_SUCCESS); + m_image = BitmapImage::create(m_surface); +} + +ImageGStreamer::~ImageGStreamer() +{ + if (m_image) + m_image.clear(); + + m_image = 0; + + if (m_surface && cairo_surface_get_reference_count(m_surface)) + cairo_surface_destroy(m_surface); + + m_surface = 0; +} diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index e1c9fd2..0afb971 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -28,13 +28,15 @@ #include "MediaPlayerPrivateGStreamer.h" -#include "CString.h" +#include "ColorSpace.h" #include "DataSourceGStreamer.h" #include "Document.h" #include "Frame.h" #include "FrameView.h" -#include "GOwnPtrGtk.h" +#include "GOwnPtrGStreamer.h" #include "GraphicsContext.h" +#include "GraphicsTypes.h" +#include "ImageGStreamer.h" #include "IntRect.h" #include "KURL.h" #include "MIMETypeRegistry.h" @@ -46,14 +48,15 @@ #include "VideoSinkGStreamer.h" #include "WebKitWebSourceGStreamer.h" #include "Widget.h" +#include <wtf/text/CString.h> +#include <GOwnPtr.h> #include <gst/gst.h> #include <gst/interfaces/mixer.h> #include <gst/interfaces/xoverlay.h> #include <gst/video/video.h> #include <limits> #include <math.h> -#include <wtf/gtk/GOwnPtr.h> // GstPlayFlags flags from playbin2. It is the policy of GStreamer to // not publicly expose element-specific enums. That's why this @@ -90,9 +93,10 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo GOwnPtr<GError> err; GOwnPtr<gchar> debug; MediaPlayer::NetworkState error; - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); bool issueError = true; bool attemptNextLocation = false; + GstElement* pipeline = mp->pipeline(); if (message->structure) { const gchar* messageTypeName = gst_structure_get_name(message->structure); @@ -137,7 +141,10 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo mp->didEnd(); break; case GST_MESSAGE_STATE_CHANGED: - mp->updateStates(); + // Ignore state changes from internal elements. They are + // forwarded to playbin2 anyway. + if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(pipeline)) + mp->updateStates(); break; case GST_MESSAGE_BUFFERING: mp->processBufferingStats(message); @@ -156,7 +163,7 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo void mediaPlayerPrivateSourceChangedCallback(GObject *object, GParamSpec *pspec, gpointer data) { - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); GOwnPtr<GstElement> element; g_object_get(mp->m_playBin, "source", &element.outPtr(), NULL); @@ -173,37 +180,17 @@ void mediaPlayerPrivateSourceChangedCallback(GObject *object, GParamSpec *pspec, void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec, gpointer data) { // This is called when playbin receives the notify::volume signal. - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); mp->volumeChanged(); } -gboolean notifyVolumeIdleCallback(gpointer data) -{ - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); - mp->volumeChangedCallback(); - return FALSE; -} - void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, gpointer data) { // This is called when playbin receives the notify::mute signal. - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data); mp->muteChanged(); } -gboolean notifyMuteIdleCallback(gpointer data) -{ - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); - mp->muteChangedCallback(); - return FALSE; -} - -gboolean bufferingTimeoutCallback(gpointer data) -{ - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); - return mp->queryBufferingStats(); -} - static float playbackPosition(GstElement* playbin) { @@ -232,19 +219,19 @@ static float playbackPosition(GstElement* playbin) } -void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate) +void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamer* playerPrivate) { g_return_if_fail(GST_IS_BUFFER(buffer)); gst_buffer_replace(&playerPrivate->m_buffer, buffer); playerPrivate->repaint(); } -MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) +MediaPlayerPrivateInterface* MediaPlayerPrivateGStreamer::create(MediaPlayer* player) { - return new MediaPlayerPrivate(player); + return new MediaPlayerPrivateGStreamer(player); } -void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) +void MediaPlayerPrivateGStreamer::registerMediaEngine(MediaEngineRegistrar registrar) { if (isAvailable()) registrar(create, getSupportedTypes, supportsType); @@ -272,7 +259,7 @@ static bool doGstInit() return gstInitialized; } -bool MediaPlayerPrivate::isAvailable() +bool MediaPlayerPrivateGStreamer::isAvailable() { if (!doGstInit()) return false; @@ -285,7 +272,7 @@ bool MediaPlayerPrivate::isAvailable() return false; } -MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) +MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player) : m_player(player) , m_playBin(0) , m_videoSink(0) @@ -296,7 +283,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_endTime(numeric_limits<float>::infinity()) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) - , m_startedPlaying(false) , m_isStreaming(false) , m_size(IntSize()) , m_buffer(0) @@ -305,36 +291,26 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_resetPipeline(false) , m_paused(true) , m_seeking(false) + , m_buffering(false) , m_playbackRate(1) , m_errorOccured(false) - , m_volumeIdleId(0) , m_mediaDuration(0) - , m_muteIdleId(0) , m_startedBuffering(false) - , m_fillTimeoutId(0) + , m_fillTimer(this, &MediaPlayerPrivateGStreamer::fillTimerFired) , m_maxTimeLoaded(0) - , m_fillStatus(0) + , m_bufferingPercentage(0) + , m_preload(MediaPlayer::Auto) + , m_delayingLoad(false) + , m_mediaDurationKnown(true) { if (doGstInit()) createGSTPlayBin(); } -MediaPlayerPrivate::~MediaPlayerPrivate() +MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer() { - if (m_fillTimeoutId) { - g_source_remove(m_fillTimeoutId); - m_fillTimeoutId = 0; - } - - if (m_volumeIdleId) { - g_source_remove(m_volumeIdleId); - m_volumeIdleId = 0; - } - - if (m_muteIdleId) { - g_source_remove(m_muteIdleId); - m_muteIdleId = 0; - } + if (m_fillTimer.isActive()) + m_fillTimer.stop(); if (m_buffer) gst_buffer_unref(m_buffer); @@ -366,9 +342,28 @@ MediaPlayerPrivate::~MediaPlayerPrivate() } } -void MediaPlayerPrivate::load(const String& url) +void MediaPlayerPrivateGStreamer::load(const String& url) { + g_object_set(m_playBin, "uri", url.utf8().data(), NULL); + LOG_VERBOSE(Media, "Load %s", url.utf8().data()); + + if (m_preload == MediaPlayer::None) { + LOG_VERBOSE(Media, "Delaying load."); + m_delayingLoad = true; + return; + } + + commitLoad(); +} + +void MediaPlayerPrivateGStreamer::commitLoad() +{ + // GStreamer needs to have the pipeline set to a paused state to + // start providing anything useful. + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + + LOG_VERBOSE(Media, "Committing load."); if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; m_player->networkStateChanged(); @@ -377,12 +372,9 @@ void MediaPlayerPrivate::load(const String& url) m_readyState = MediaPlayer::HaveNothing; m_player->readyStateChanged(); } - - g_object_set(m_playBin, "uri", url.utf8().data(), NULL); - pause(); } -bool MediaPlayerPrivate::changePipelineState(GstState newState) +bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState) { ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED); @@ -401,19 +393,27 @@ bool MediaPlayerPrivate::changePipelineState(GstState newState) return true; } -void MediaPlayerPrivate::play() +void MediaPlayerPrivateGStreamer::prepareToPlay() +{ + if (m_delayingLoad) { + m_delayingLoad = false; + commitLoad(); + } +} + +void MediaPlayerPrivateGStreamer::play() { if (changePipelineState(GST_STATE_PLAYING)) LOG_VERBOSE(Media, "Play"); } -void MediaPlayerPrivate::pause() +void MediaPlayerPrivateGStreamer::pause() { if (changePipelineState(GST_STATE_PAUSED)) LOG_VERBOSE(Media, "Pause"); } -float MediaPlayerPrivate::duration() const +float MediaPlayerPrivateGStreamer::duration() const { if (!m_playBin) return 0.0; @@ -421,6 +421,10 @@ float MediaPlayerPrivate::duration() const if (m_errorOccured) return 0.0; + // Media duration query failed already, don't attempt new useless queries. + if (!m_mediaDurationKnown) + return numeric_limits<float>::infinity(); + if (m_mediaDuration) return m_mediaDuration; @@ -438,7 +442,7 @@ float MediaPlayerPrivate::duration() const // FIXME: handle 3.14.9.5 properly } -float MediaPlayerPrivate::currentTime() const +float MediaPlayerPrivateGStreamer::currentTime() const { if (!m_playBin) return 0; @@ -453,7 +457,7 @@ float MediaPlayerPrivate::currentTime() const } -void MediaPlayerPrivate::seek(float time) +void MediaPlayerPrivateGStreamer::seek(float time) { // Avoid useless seeking. if (time == playbackPosition(m_playBin)) @@ -479,33 +483,33 @@ void MediaPlayerPrivate::seek(float time) } } -void MediaPlayerPrivate::startEndPointTimerIfNeeded() +void MediaPlayerPrivateGStreamer::startEndPointTimerIfNeeded() { notImplemented(); } -void MediaPlayerPrivate::cancelSeek() +void MediaPlayerPrivateGStreamer::cancelSeek() { notImplemented(); } -void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*) +void MediaPlayerPrivateGStreamer::endPointTimerFired(Timer<MediaPlayerPrivateGStreamer>*) { notImplemented(); } -bool MediaPlayerPrivate::paused() const +bool MediaPlayerPrivateGStreamer::paused() const { return m_paused; } -bool MediaPlayerPrivate::seeking() const +bool MediaPlayerPrivateGStreamer::seeking() const { return m_seeking; } // Returns the size of the video -IntSize MediaPlayerPrivate::naturalSize() const +IntSize MediaPlayerPrivateGStreamer::naturalSize() const { if (!hasVideo()) return IntSize(); @@ -567,7 +571,7 @@ IntSize MediaPlayerPrivate::naturalSize() const return IntSize(width, height); } -bool MediaPlayerPrivate::hasVideo() const +bool MediaPlayerPrivateGStreamer::hasVideo() const { gint currentVideo = -1; if (m_playBin) @@ -575,7 +579,7 @@ bool MediaPlayerPrivate::hasVideo() const return currentVideo > -1; } -bool MediaPlayerPrivate::hasAudio() const +bool MediaPlayerPrivateGStreamer::hasAudio() const { gint currentAudio = -1; if (m_playBin) @@ -583,7 +587,7 @@ bool MediaPlayerPrivate::hasAudio() const return currentAudio > -1; } -void MediaPlayerPrivate::setVolume(float volume) +void MediaPlayerPrivateGStreamer::setVolume(float volume) { if (!m_playBin) return; @@ -591,21 +595,20 @@ void MediaPlayerPrivate::setVolume(float volume) g_object_set(m_playBin, "volume", static_cast<double>(volume), NULL); } -void MediaPlayerPrivate::volumeChangedCallback() +void MediaPlayerPrivateGStreamer::volumeChangedTimerFired(Timer<MediaPlayerPrivateGStreamer>*) { double volume; g_object_get(m_playBin, "volume", &volume, NULL); m_player->volumeChanged(static_cast<float>(volume)); } -void MediaPlayerPrivate::volumeChanged() +void MediaPlayerPrivateGStreamer::volumeChanged() { - if (m_volumeIdleId) - g_source_remove(m_volumeIdleId); - m_volumeIdleId = g_idle_add((GSourceFunc) notifyVolumeIdleCallback, this); + Timer<MediaPlayerPrivateGStreamer> volumeChangedTimer(this, &MediaPlayerPrivateGStreamer::volumeChangedTimerFired); + volumeChangedTimer.startOneShot(0); } -void MediaPlayerPrivate::setRate(float rate) +void MediaPlayerPrivateGStreamer::setRate(float rate) { // Avoid useless playback rate update. if (m_playbackRate == rate) @@ -658,17 +661,17 @@ void MediaPlayerPrivate::setRate(float rate) g_object_set(m_playBin, "mute", mute, NULL); } -MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const +MediaPlayer::NetworkState MediaPlayerPrivateGStreamer::networkState() const { return m_networkState; } -MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const +MediaPlayer::ReadyState MediaPlayerPrivateGStreamer::readyState() const { return m_readyState; } -PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const { RefPtr<TimeRanges> timeRanges = TimeRanges::create(); float loaded = maxTimeLoaded(); @@ -677,44 +680,56 @@ PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const return timeRanges.release(); } -void MediaPlayerPrivate::processBufferingStats(GstMessage* message) +void MediaPlayerPrivateGStreamer::processBufferingStats(GstMessage* message) { - GstBufferingMode mode; + // This is the immediate buffering that needs to happen so we have + // enough to play right now. + m_buffering = true; + const GstStructure *structure = gst_message_get_structure(message); + gst_structure_get_int(structure, "buffer-percent", &m_bufferingPercentage); + + LOG_VERBOSE(Media, "[Buffering] Buffering: %d%%.", m_bufferingPercentage); + GstBufferingMode mode; gst_message_parse_buffering_stats(message, &mode, 0, 0, 0); - if (mode != GST_BUFFERING_DOWNLOAD) + if (mode != GST_BUFFERING_DOWNLOAD) { + updateStates(); return; + } + // This is on-disk buffering, that allows us to download much more + // than needed for right now. if (!m_startedBuffering) { + LOG_VERBOSE(Media, "[Buffering] Starting on-disk buffering."); + m_startedBuffering = true; - if (m_fillTimeoutId > 0) - g_source_remove(m_fillTimeoutId); + if (m_fillTimer.isActive()) + m_fillTimer.stop(); - m_fillTimeoutId = g_timeout_add(200, (GSourceFunc) bufferingTimeoutCallback, this); + m_fillTimer.startRepeating(0.2); } } -bool MediaPlayerPrivate::queryBufferingStats() +void MediaPlayerPrivateGStreamer::fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*) { GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT); if (!gst_element_query(m_playBin, query)) { gst_query_unref(query); - return TRUE; + return; } gint64 start, stop; + gdouble fillStatus = 100.0; gst_query_parse_buffering_range(query, 0, &start, &stop, 0); gst_query_unref(query); if (stop != -1) - m_fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX; - else - m_fillStatus = 100.0; + fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX; - LOG_VERBOSE(Media, "Download buffer filled up to %f%%", m_fillStatus); + LOG_VERBOSE(Media, "[Buffering] Download buffer filled up to %f%%", fillStatus); if (!m_mediaDuration) durationChanged(); @@ -722,25 +737,27 @@ bool MediaPlayerPrivate::queryBufferingStats() // Update maxTimeLoaded only if the media duration is // available. Otherwise we can't compute it. if (m_mediaDuration) { - m_maxTimeLoaded = static_cast<float>((m_fillStatus * m_mediaDuration) / 100.0); - LOG_VERBOSE(Media, "Updated maxTimeLoaded: %f", m_maxTimeLoaded); + if (fillStatus == 100.0) + m_maxTimeLoaded = m_mediaDuration; + else + m_maxTimeLoaded = static_cast<float>((fillStatus * m_mediaDuration) / 100.0); + LOG_VERBOSE(Media, "[Buffering] Updated maxTimeLoaded: %f", m_maxTimeLoaded); } - if (m_fillStatus != 100.0) { + if (fillStatus != 100.0) { updateStates(); - return TRUE; + return; } // Media is now fully loaded. It will play even if network // connection is cut. Buffering is done, remove the fill source // from the main loop. - m_fillTimeoutId = 0; + m_fillTimer.stop(); m_startedBuffering = false; updateStates(); - return FALSE; } -float MediaPlayerPrivate::maxTimeSeekable() const +float MediaPlayerPrivateGStreamer::maxTimeSeekable() const { if (m_errorOccured) return 0.0; @@ -753,19 +770,19 @@ float MediaPlayerPrivate::maxTimeSeekable() const return maxTimeLoaded(); } -float MediaPlayerPrivate::maxTimeLoaded() const +float MediaPlayerPrivateGStreamer::maxTimeLoaded() const { if (m_errorOccured) return 0.0; float loaded = m_maxTimeLoaded; - if (!loaded && !m_fillTimeoutId) + if (!loaded && !m_fillTimer.isActive()) loaded = duration(); LOG_VERBOSE(Media, "maxTimeLoaded: %f", loaded); return loaded; } -unsigned MediaPlayerPrivate::bytesLoaded() const +unsigned MediaPlayerPrivateGStreamer::bytesLoaded() const { if (!m_playBin) return 0; @@ -778,7 +795,7 @@ unsigned MediaPlayerPrivate::bytesLoaded() const return loaded; } -unsigned MediaPlayerPrivate::totalBytes() const +unsigned MediaPlayerPrivateGStreamer::totalBytes() const { if (!m_source) return 0; @@ -794,7 +811,7 @@ unsigned MediaPlayerPrivate::totalBytes() const return length; } -void MediaPlayerPrivate::cancelLoad() +void MediaPlayerPrivateGStreamer::cancelLoad() { if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) return; @@ -803,12 +820,8 @@ void MediaPlayerPrivate::cancelLoad() gst_element_set_state(m_playBin, GST_STATE_NULL); } -void MediaPlayerPrivate::updateStates() +void MediaPlayerPrivateGStreamer::updateStates() { - // There is no (known) way to get such level of information about - // 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; @@ -832,44 +845,66 @@ void MediaPlayerPrivate::updateStates() m_resetPipeline = state <= GST_STATE_READY; - if (state == GST_STATE_READY) + // Try to figure out ready and network states. + if (state == GST_STATE_READY) { m_readyState = MediaPlayer::HaveNothing; - else if (state == GST_STATE_PAUSED) + m_networkState = MediaPlayer::Empty; + } else if (maxTimeLoaded() == duration()) { + m_networkState = MediaPlayer::Loaded; m_readyState = MediaPlayer::HaveEnoughData; + } else { + m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData; + m_networkState = MediaPlayer::Loading; + } - if (state == GST_STATE_PLAYING) { + if (m_buffering && state != GST_STATE_READY) { + m_readyState = MediaPlayer::HaveCurrentData; + m_networkState = MediaPlayer::Loading; + } + + // Now let's try to get the states in more detail using + // information from GStreamer, while we sync states where + // needed. + if (state == GST_STATE_PAUSED) { + if (m_buffering && m_bufferingPercentage == 100) { + m_buffering = false; + m_bufferingPercentage = 0; + m_readyState = MediaPlayer::HaveEnoughData; + + LOG_VERBOSE(Media, "[Buffering] Complete."); + + if (!m_paused) { + LOG_VERBOSE(Media, "[Buffering] Restarting playback."); + gst_element_set_state(m_playBin, GST_STATE_PLAYING); + } + } else if (!m_buffering && (currentTime() < duration())) { + m_paused = true; + } + } else if (state == GST_STATE_PLAYING) { m_readyState = MediaPlayer::HaveEnoughData; m_paused = false; - m_startedPlaying = true; + if (!m_mediaDuration) { float newDuration = duration(); - if (!isinf(newDuration)) + m_mediaDurationKnown = !isinf(newDuration); + if (m_mediaDurationKnown) m_mediaDuration = newDuration; } + + if (m_buffering) { + m_readyState = MediaPlayer::HaveCurrentData; + m_networkState = MediaPlayer::Loading; + + LOG_VERBOSE(Media, "[Buffering] Pausing stream for buffering."); + + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + } } else m_paused = true; // Is on-disk buffering in progress? - if (m_fillTimeoutId) { + if (m_fillTimer.isActive()) m_networkState = MediaPlayer::Loading; - // Buffering has just started, we should now have enough - // data to restart playback if it was internally paused by - // GStreamer. - if (m_paused && !m_startedPlaying) - gst_element_set_state(m_playBin, GST_STATE_PLAYING); - } - - if (maxTimeLoaded() == duration()) { - m_networkState = MediaPlayer::Loaded; - if (state == GST_STATE_READY) - m_readyState = MediaPlayer::HaveNothing; - else if (state == GST_STATE_PAUSED) - m_readyState = MediaPlayer::HaveEnoughData; - } else - if (state == GST_STATE_READY) - m_readyState = MediaPlayer::HaveNothing; - else if (m_paused) - m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData; if (m_changingRate) { m_player->rateChanged(); @@ -917,20 +952,16 @@ void MediaPlayerPrivate::updateStates() m_paused = true; // Live pipelines go in PAUSED without prerolling. m_isStreaming = true; - } else if (state == GST_STATE_PLAYING) { - m_startedPlaying = true; + } else if (state == GST_STATE_PLAYING) m_paused = false; - } - - if (m_paused && !m_startedPlaying) - gst_element_set_state(m_playBin, GST_STATE_PLAYING); if (m_seeking) { shouldUpdateAfterSeek = true; m_seeking = false; - if (m_paused) + if (!m_paused) gst_element_set_state(m_playBin, GST_STATE_PLAYING); - } + } else if (!m_paused) + gst_element_set_state(m_playBin, GST_STATE_PLAYING); m_networkState = MediaPlayer::Loading; break; @@ -957,7 +988,7 @@ void MediaPlayerPrivate::updateStates() } } -void MediaPlayerPrivate::mediaLocationChanged(GstMessage* message) +void MediaPlayerPrivateGStreamer::mediaLocationChanged(GstMessage* message) { if (m_mediaLocations) gst_structure_free(m_mediaLocations); @@ -970,13 +1001,13 @@ void MediaPlayerPrivate::mediaLocationChanged(GstMessage* message) const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations"); if (locations) - m_mediaLocationCurrentIndex = gst_value_list_get_size(locations) -1; + m_mediaLocationCurrentIndex = static_cast<int>(gst_value_list_get_size(locations)) -1; loadNextLocation(); } } -bool MediaPlayerPrivate::loadNextLocation() +bool MediaPlayerPrivateGStreamer::loadNextLocation() { if (!m_mediaLocations) return false; @@ -1056,23 +1087,23 @@ bool MediaPlayerPrivate::loadNextLocation() } -void MediaPlayerPrivate::loadStateChanged() +void MediaPlayerPrivateGStreamer::loadStateChanged() { updateStates(); } -void MediaPlayerPrivate::sizeChanged() +void MediaPlayerPrivateGStreamer::sizeChanged() { notImplemented(); } -void MediaPlayerPrivate::timeChanged() +void MediaPlayerPrivateGStreamer::timeChanged() { updateStates(); m_player->timeChanged(); } -void MediaPlayerPrivate::didEnd() +void MediaPlayerPrivateGStreamer::didEnd() { // EOS was reached but in case of reverse playback the position is // not always 0. So to not confuse the HTMLMediaElement we @@ -1088,25 +1119,40 @@ void MediaPlayerPrivate::didEnd() timeChanged(); } -void MediaPlayerPrivate::durationChanged() +void MediaPlayerPrivateGStreamer::durationChanged() { // Reset cached media duration m_mediaDuration = 0; // And re-cache it if possible. + GstState state; + gst_element_get_state(m_playBin, &state, 0, 0); float newDuration = duration(); + + if (state <= GST_STATE_READY) { + // Don't set m_mediaDurationKnown yet if the pipeline is not + // paused. This allows duration() query to fail at least once + // before playback starts and duration becomes known. + if (!isinf(newDuration)) + m_mediaDuration = newDuration; + } else { + m_mediaDurationKnown = !isinf(newDuration); + if (m_mediaDurationKnown) + m_mediaDuration = newDuration; + } + if (!isinf(newDuration)) m_mediaDuration = newDuration; m_player->durationChanged(); } -bool MediaPlayerPrivate::supportsMuting() const +bool MediaPlayerPrivateGStreamer::supportsMuting() const { return true; } -void MediaPlayerPrivate::setMuted(bool muted) +void MediaPlayerPrivateGStreamer::setMuted(bool muted) { if (!m_playBin) return; @@ -1114,22 +1160,20 @@ void MediaPlayerPrivate::setMuted(bool muted) g_object_set(m_playBin, "mute", muted, NULL); } -void MediaPlayerPrivate::muteChangedCallback() +void MediaPlayerPrivateGStreamer::muteChangedTimerFired(Timer<MediaPlayerPrivateGStreamer>*) { gboolean muted; g_object_get(m_playBin, "mute", &muted, NULL); m_player->muteChanged(static_cast<bool>(muted)); } -void MediaPlayerPrivate::muteChanged() +void MediaPlayerPrivateGStreamer::muteChanged() { - if (m_muteIdleId) - g_source_remove(m_muteIdleId); - - m_muteIdleId = g_idle_add((GSourceFunc) notifyMuteIdleCallback, this); + Timer<MediaPlayerPrivateGStreamer> muteChangedTimer(this, &MediaPlayerPrivateGStreamer::muteChangedTimerFired); + muteChangedTimer.startOneShot(0); } -void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error) +void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState error) { m_errorOccured = true; if (m_networkState != error) { @@ -1142,21 +1186,21 @@ void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error) } } -void MediaPlayerPrivate::setSize(const IntSize& size) +void MediaPlayerPrivateGStreamer::setSize(const IntSize& size) { m_size = size; } -void MediaPlayerPrivate::setVisible(bool visible) +void MediaPlayerPrivateGStreamer::setVisible(bool visible) { } -void MediaPlayerPrivate::repaint() +void MediaPlayerPrivateGStreamer::repaint() { m_player->repaint(); } -void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) +void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect& rect) { if (context->paintingDisabled()) return; @@ -1166,42 +1210,12 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) if (!m_buffer) return; - int width = 0, height = 0; - GstCaps* caps = gst_buffer_get_caps(m_buffer); - GstVideoFormat format; - - if (!gst_video_format_parse_caps(caps, &format, &width, &height)) { - gst_caps_unref(caps); - return; - } - - cairo_format_t cairoFormat; - if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) - cairoFormat = CAIRO_FORMAT_ARGB32; - else - cairoFormat = CAIRO_FORMAT_RGB24; - - cairo_t* cr = context->platformContext(); - cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(m_buffer), - cairoFormat, - width, height, - 4 * width); - - cairo_save(cr); - - // translate and scale the context to correct size - cairo_translate(cr, rect.x(), rect.y()); - cairo_scale(cr, static_cast<double>(rect.width()) / width, static_cast<double>(rect.height()) / height); - - // And paint it. - cairo_set_source_surface(cr, src, 0, 0); - cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD); - cairo_rectangle(cr, 0, 0, width, height); - cairo_fill(cr); - cairo_restore(cr); + RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_buffer); + if (!gstImage) + return; - cairo_surface_destroy(src); - gst_caps_unref(caps); + context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), sRGBColorSpace, + rect, CompositeCopy, false); } static HashSet<String> mimeTypeCache() @@ -1209,7 +1223,7 @@ static HashSet<String> mimeTypeCache() doGstInit(); - static HashSet<String> cache; + DEFINE_STATIC_LOCAL(HashSet<String>, cache, ()); static bool typeListInitialized = false; if (!typeListInitialized) { @@ -1307,12 +1321,12 @@ static HashSet<String> mimeTypeCache() return cache; } -void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) +void MediaPlayerPrivateGStreamer::getSupportedTypes(HashSet<String>& types) { types = mimeTypeCache(); } -MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) +MediaPlayer::SupportsType MediaPlayerPrivateGStreamer::supportsType(const String& type, const String& codecs) { if (type.isNull() || type.isEmpty()) return MediaPlayer::IsNotSupported; @@ -1323,29 +1337,36 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, c return MediaPlayer::IsNotSupported; } -bool MediaPlayerPrivate::hasSingleSecurityOrigin() const +bool MediaPlayerPrivateGStreamer::hasSingleSecurityOrigin() const { return true; } -bool MediaPlayerPrivate::supportsFullscreen() const +bool MediaPlayerPrivateGStreamer::supportsFullscreen() const { return true; } -void MediaPlayerPrivate::setAutobuffer(bool autoBuffer) +void MediaPlayerPrivateGStreamer::setPreload(MediaPlayer::Preload preload) { ASSERT(m_playBin); + m_preload = preload; + GstPlayFlags flags; g_object_get(m_playBin, "flags", &flags, NULL); - if (autoBuffer) - g_object_set(m_playBin, "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL); - else + if (preload == MediaPlayer::None) g_object_set(m_playBin, "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL); + else + g_object_set(m_playBin, "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL); + + if (m_delayingLoad && m_preload != MediaPlayer::None) { + m_delayingLoad = false; + commitLoad(); + } } -void MediaPlayerPrivate::createGSTPlayBin() +void MediaPlayerPrivateGStreamer::createGSTPlayBin() { ASSERT(!m_playBin); m_playBin = gst_element_factory_make("playbin2", "play"); diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h index e19b686..06519fa 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h @@ -28,7 +28,6 @@ #include "MediaPlayerPrivate.h" #include "Timer.h" -#include <cairo.h> #include <glib.h> #include <gst/gst.h> @@ -47,25 +46,27 @@ class String; gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); void mediaPlayerPrivateVolumeChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); +void mediaPlayerPrivateMuteChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); -class MediaPlayerPrivate : public MediaPlayerPrivateInterface { +class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data); - friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer* buffer, MediaPlayerPrivate* playerPrivate); + friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer* buffer, MediaPlayerPrivateGStreamer* playerPrivate); friend void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data); public: static void registerMediaEngine(MediaEngineRegistrar); - ~MediaPlayerPrivate(); IntSize naturalSize() const; bool hasVideo() const; bool hasAudio() const; void load(const String &url); + void commitLoad(); void cancelLoad(); bool loadNextLocation(); + void prepareToPlay(); void play(); void pause(); @@ -80,15 +81,15 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface { void setVolume(float); void volumeChanged(); - void volumeChangedCallback(); + void volumeChangedTimerFired(Timer<MediaPlayerPrivateGStreamer>*); bool supportsMuting() const; void setMuted(bool); void muteChanged(); - void muteChangedCallback(); + void muteChangedTimerFired(Timer<MediaPlayerPrivateGStreamer>*); - void setAutobuffer(bool); - bool queryBufferingStats(); + void setPreload(MediaPlayer::Preload); + void fillTimerFired(Timer<MediaPlayerPrivateGStreamer>*); MediaPlayer::NetworkState networkState() const; MediaPlayer::ReadyState readyState() const; @@ -116,10 +117,13 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface { bool supportsFullscreen() const; + GstElement* pipeline() const { return m_playBin; } bool pipelineReset() const { return m_resetPipeline; } private: - MediaPlayerPrivate(MediaPlayer*); + MediaPlayerPrivateGStreamer(MediaPlayer*); + ~MediaPlayerPrivateGStreamer(); + static MediaPlayerPrivateInterface* create(MediaPlayer* player); static void getSupportedTypes(HashSet<String>&); @@ -128,7 +132,7 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface { void updateStates(); void cancelSeek(); - void endPointTimerFired(Timer<MediaPlayerPrivate>*); + void endPointTimerFired(Timer<MediaPlayerPrivateGStreamer>*); float maxTimeLoaded() const; void startEndPointTimerIfNeeded(); @@ -149,24 +153,25 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface { bool m_isEndReached; MediaPlayer::NetworkState m_networkState; MediaPlayer::ReadyState m_readyState; - bool m_startedPlaying; mutable bool m_isStreaming; IntSize m_size; GstBuffer* m_buffer; GstStructure* m_mediaLocations; - gint m_mediaLocationCurrentIndex; + int m_mediaLocationCurrentIndex; bool m_resetPipeline; bool m_paused; bool m_seeking; + bool m_buffering; float m_playbackRate; bool m_errorOccured; - guint m_volumeIdleId; gfloat m_mediaDuration; - guint m_muteIdleId; bool m_startedBuffering; - guint m_fillTimeoutId; + Timer<MediaPlayerPrivateGStreamer> m_fillTimer; float m_maxTimeLoaded; - gdouble m_fillStatus; + int m_bufferingPercentage; + MediaPlayer::Preload m_preload; + bool m_delayingLoad; + bool m_mediaDurationKnown; }; } diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp index 5e0f8e2..dd8c3ee 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp @@ -213,8 +213,10 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) buffer = priv->buffer = newBuffer; } - // Use HIGH_IDLE+20 priority, like Gtk+ for redrawing operations. - priv->timeout_id = g_timeout_add_full(G_PRIORITY_HIGH_IDLE + 20, 0, + // This should likely use a lower priority, but glib currently starves + // lower priority sources. + // See: https://bugzilla.gnome.org/show_bug.cgi?id=610830. + priv->timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, webkit_video_sink_timeout_func, gst_object_ref(sink), (GDestroyNotify)gst_object_unref); diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h index 7ea7d91..7ea7d91 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h diff --git a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index 74a7852..daee506 100644 --- a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -19,7 +19,6 @@ #include "config.h" #include "WebKitWebSourceGStreamer.h" -#include "CString.h" #include "Document.h" #include "GOwnPtr.h" #include "GRefPtr.h" @@ -29,6 +28,7 @@ #include "ResourceHandleInternal.h" #include "ResourceRequest.h" #include "ResourceResponse.h" +#include <wtf/text/CString.h> #include <gst/app/gstappsrc.h> #include <gst/pbutils/missing-plugins.h> @@ -255,6 +255,7 @@ static void webkit_web_src_init(WebKitWebSrc* src, // already if the queue is 20% empty, it's much more // likely that libsoup already provides new data before // the queue is really empty. + // This might need tweaking for ports not using libsoup. if (priv->haveAppSrc27) g_object_set(priv->appsrc, "min-percent", 20, NULL); @@ -414,7 +415,7 @@ static bool webKitWebSrcStart(WebKitWebSrc* src) // Needed to use DLNA streaming servers request.setHTTPHeaderField("transferMode.dlna", "Streaming"); - priv->resourceHandle = ResourceHandle::create(request, priv->client, 0, false, false, false); + priv->resourceHandle = ResourceHandle::create(request, priv->client, 0, false, false); if (!priv->resourceHandle) { GST_ERROR_OBJECT(src, "Failed to create ResourceHandle"); return false; @@ -505,17 +506,14 @@ static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri) if (!uri) return TRUE; - SoupURI* soupUri = soup_uri_new(uri); + KURL url(KURL(), uri); - if (!soupUri || !SOUP_URI_VALID_FOR_HTTP(soupUri)) { + if (!url.isValid() || !url.protocolInHTTPFamily()) { GST_ERROR_OBJECT(src, "Invalid URI '%s'", uri); - soup_uri_free(soupUri); return FALSE; } - priv->uri = soup_uri_to_string(soupUri, FALSE); - soup_uri_free(soupUri); - + priv->uri = g_strdup(url.string().utf8().data()); return TRUE; } @@ -535,9 +533,13 @@ static gboolean webKitWebSrcNeedDataMainCb(WebKitWebSrc* src) { WebKitWebSrcPrivate* priv = src->priv; +#if USE(NETWORK_SOUP) ResourceHandleInternal* d = priv->resourceHandle->getInternal(); if (d->m_msg) soup_session_unpause_message(ResourceHandle::defaultSession(), d->m_msg); +#endif + // Ports not using libsoup need to call the unpause/schedule API of their + // underlying network implementation here. priv->paused = FALSE; priv->needDataID = 0; @@ -553,16 +555,20 @@ static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer use if (priv->needDataID || !priv->paused) return; - priv->needDataID = g_timeout_add_full(G_PRIORITY_HIGH, 0, (GSourceFunc) webKitWebSrcNeedDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref); + priv->needDataID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcNeedDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref); } static gboolean webKitWebSrcEnoughDataMainCb(WebKitWebSrc* src) { WebKitWebSrcPrivate* priv = src->priv; +#if USE(NETWORK_SOUP) ResourceHandleInternal* d = priv->resourceHandle->getInternal(); soup_session_pause_message(ResourceHandle::defaultSession(), d->m_msg); - +#endif + // Ports not using libsoup need to call the pause/unschedule API of their + // underlying network implementation here. + priv->paused = TRUE; priv->enoughDataID = 0; return FALSE; @@ -577,7 +583,7 @@ static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData) if (priv->enoughDataID || priv->paused) return; - priv->enoughDataID = g_timeout_add_full(G_PRIORITY_HIGH, 0, (GSourceFunc) webKitWebSrcEnoughDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref); + priv->enoughDataID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcEnoughDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref); } static gboolean webKitWebSrcSeekMainCb(WebKitWebSrc* src) @@ -606,7 +612,7 @@ static gboolean webKitWebSrcSeekDataCb(GstAppSrc* appsrc, guint64 offset, gpoint priv->requestedOffset = offset; if (priv->seekID) g_source_remove(priv->seekID); - priv->seekID = g_timeout_add_full(G_PRIORITY_HIGH, 0, (GSourceFunc) webKitWebSrcSeekMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref); + priv->seekID = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, (GSourceFunc) webKitWebSrcSeekMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref); return TRUE; } diff --git a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h index ae19640..ae19640 100644 --- a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp index 5c320e0..29b83dc 100644 --- a/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -288,7 +288,7 @@ static PangoLayout* getDefaultPangoLayout(const TextRun& run) return layout; } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow*) const { if (run.length() == 0) return 0.0f; diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp index 8a1a5f1..59cd3da 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp +++ b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp @@ -25,9 +25,9 @@ #include "config.h" #include "FontPlatformData.h" -#include "CString.h" #include "PlatformString.h" #include "FontDescription.h" +#include <wtf/text/CString.h> #include <cairo.h> #include <assert.h> @@ -137,7 +137,7 @@ FontPlatformData::FontPlatformData(float size, bool bold, bool italic) { } -FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic) +FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic) : m_context(0) , m_font(0) , m_size(size) diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp index 71b897e..d56b52d 100644 --- a/WebCore/platform/graphics/gtk/IconGtk.cpp +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -30,10 +30,10 @@ #include "config.h" #include "Icon.h" -#include "CString.h" #include "GraphicsContext.h" #include "MIMETypeRegistry.h" #include "PassRefPtr.h" +#include <wtf/text/CString.h> #include <gtk/gtk.h> diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp index c62d988..daa70ef 100644 --- a/WebCore/platform/graphics/gtk/ImageGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -26,12 +26,72 @@ #include "config.h" #include "BitmapImage.h" -#include "CString.h" #include "GOwnPtr.h" - +#include "SharedBuffer.h" +#include <wtf/text/CString.h> #include <cairo.h> #include <gtk/gtk.h> +#ifdef _WIN32 +# include <mbstring.h> +# include <shlobj.h> +/* search for data relative to where we are installed */ + +static HMODULE hmodule; + +#ifdef __cplusplus +extern "C" { +#endif +BOOL WINAPI +DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + hmodule = hinstDLL; + break; + } + + return TRUE; +} +#ifdef __cplusplus +} +#endif + +static char * +get_webkit_datadir(void) +{ + static char retval[1000]; + static int beenhere = 0; + + unsigned char *p; + + if (beenhere) + return retval; + + if (!GetModuleFileName (hmodule, (CHAR *) retval, sizeof(retval) - 10)) + return DATA_DIR; + + p = _mbsrchr((const unsigned char *) retval, '\\'); + *p = '\0'; + p = _mbsrchr((const unsigned char *) retval, '\\'); + if (p) { + if (!stricmp((const char *) (p+1), "bin")) + *p = '\0'; + } + strcat(retval, "\\share"); + + beenhere = 1; + + return retval; +} + +#undef DATA_DIR +#define DATA_DIR get_webkit_datadir () +#endif + + namespace WTF { template <> void freeOwnedGPtr<GtkIconInfo>(GtkIconInfo* info) @@ -96,8 +156,13 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name) CString fileName; if (!strcmp("missingImage", name)) fileName = getThemeIconFileName(GTK_STOCK_MISSING_IMAGE, 16); - if (fileName.isNull()) - fileName = String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, name).utf8(); + if (fileName.isNull()) { + gchar* imagename = g_strdup_printf("%s.png", name); + gchar* glibFileName = g_build_filename(DATA_DIR, "webkit-1.0", "images", imagename, 0); + fileName = glibFileName; + g_free(imagename); + g_free(glibFileName); + } return loadImageFromFile(fileName); } @@ -107,12 +172,12 @@ PassRefPtr<Image> Image::loadPlatformThemeIcon(const char* name, int size) return loadImageFromFile(getThemeIconFileName(name, size)); } -static inline unsigned char* getCairoSurfacePixel(unsigned char* data, uint x, uint y, uint rowStride) +static inline unsigned char* getCairoSurfacePixel(unsigned char* data, unsigned x, unsigned y, unsigned rowStride) { return data + (y * rowStride) + x * 4; } -static inline guchar* getGdkPixbufPixel(guchar* data, uint x, uint y, uint rowStride) +static inline guchar* getGdkPixbufPixel(guchar* data, unsigned x, unsigned y, unsigned rowStride) { return data + (y * rowStride) + x * 4; } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp index 975143e..0ed5393 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp @@ -119,7 +119,7 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = m_platformData.isFixedPitch(); } -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode) const { ASSERT(m_platformData.m_scaledFont); @@ -130,7 +130,10 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const float w = (float)m_spaceWidth; if (cairo_scaled_font_status(m_platformData.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) w = (float)extents.x_advance; - return w; + + GlyphMetrics metrics; + metrics.horizontalAdvance = w; + return metrics; } } diff --git a/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp b/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp index 7ade370..f8c2aa0 100644 --- a/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp +++ b/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de> * * All rights reserved. * @@ -37,7 +38,7 @@ #include "FontPlatformData.h" #include "NotImplemented.h" #include <String.h> - +#include <interface/Font.h> namespace WebCore { @@ -59,10 +60,11 @@ SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font) SimpleFontData* 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 getCachedFontData(fontDescription, defaultString); + font_family family; + font_style style; + be_plain_font->GetFamilyAndStyle(&family, &style); + AtomicString plainFontFamily(family); + return getCachedFontData(fontDescription, plainFontFamily); } FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) diff --git a/WebCore/platform/graphics/haiku/FontHaiku.cpp b/WebCore/platform/graphics/haiku/FontHaiku.cpp index 48744d9..d4622cb 100644 --- a/WebCore/platform/graphics/haiku/FontHaiku.cpp +++ b/WebCore/platform/graphics/haiku/FontHaiku.cpp @@ -94,7 +94,7 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { notImplemented(); return 0; diff --git a/WebCore/platform/graphics/haiku/GradientHaiku.cpp b/WebCore/platform/graphics/haiku/GradientHaiku.cpp index 469a17f..fdc4690 100644 --- a/WebCore/platform/graphics/haiku/GradientHaiku.cpp +++ b/WebCore/platform/graphics/haiku/GradientHaiku.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> All rights reserved. * Copyright (C) 2009 Maxime Simon <simon.maxime@theolliviers.com> + * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,26 +28,45 @@ #include "config.h" #include "Gradient.h" -#include "CSSParser.h" -#include "NotImplemented.h" +#include "GraphicsContext.h" +#include <GradientLinear.h> +#include <GradientRadial.h> +#include <View.h> namespace WebCore { void Gradient::platformDestroy() { - notImplemented(); + delete m_gradient; } PlatformGradient Gradient::platformGradient() { - notImplemented(); - return 0; + if (m_gradient) + return m_gradient; + + if (m_radial) { + // TODO: Support m_r0? + m_gradient = new BGradientRadial(m_p0, m_r1); + } else + m_gradient = new BGradientLinear(m_p0, m_p1); + size_t size = m_stops.size(); + for (size_t i = 0; i < size; i++) { + const ColorStop& stop = m_stops[i]; + rgb_color color; + color.red = static_cast<uint8>(stop.red * 255); + color.green = static_cast<uint8>(stop.green * 255); + color.blue = static_cast<uint8>(stop.blue * 255); + color.alpha = static_cast<uint8>(stop.alpha * 255); + m_gradient->AddColor(color, stop.stop); + } + return m_gradient; } -void Gradient::fill(GraphicsContext*, const FloatRect&) +void Gradient::fill(GraphicsContext* context, const FloatRect& rect) { - notImplemented(); + context->platformContext()->FillRect(rect, *platformGradient()); } } // namespace WebCore diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp index 7ab3a40..8db512c 100644 --- a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp +++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -29,13 +29,13 @@ #include "GraphicsContext.h" #include "AffineTransform.h" -#include "CString.h" #include "Color.h" #include "Font.h" #include "FontData.h" #include "NotImplemented.h" #include "Path.h" #include "Pen.h" +#include <wtf/text/CString.h> #include <GraphicsDefs.h> #include <Region.h> #include <View.h> diff --git a/WebCore/platform/graphics/haiku/ImageHaiku.cpp b/WebCore/platform/graphics/haiku/ImageHaiku.cpp index 976154c..5a55d7c 100644 --- a/WebCore/platform/graphics/haiku/ImageHaiku.cpp +++ b/WebCore/platform/graphics/haiku/ImageHaiku.cpp @@ -39,6 +39,7 @@ #include "ImageObserver.h" #include "NotImplemented.h" #include "PlatformString.h" +#include "SharedBuffer.h" #include "TransformationMatrix.h" #include <Application.h> #include <Bitmap.h> @@ -120,7 +121,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR imageObserver()->didDraw(this); } -void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& srcPoint, ColorSpace, CompositeOperator op, const FloatRect& dstRect) +void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& dstRect) { BBitmap* image = nativeImageForCurrentFrame(); if (!image || !image->IsValid()) // If the image hasn't fully loaded. diff --git a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp index adb7573..f429ab5 100644 --- a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp +++ b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp @@ -93,7 +93,7 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = m_platformData.font() && m_platformData.font()->IsFixed(); } -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode) const { if (!m_platformData.font()) return 0; @@ -103,7 +103,9 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const charUnicodeToUTF8HACK(glyph, charArray); m_platformData.font()->GetEscapements(charArray, 1, escapements); - return escapements[0] * m_platformData.font()->Size(); + GlyphMetrics metrics; + metrics.horizontalAdvance = escapements[0] * m_platformData.font()->Size(); + return metrics; } } // namespace WebCore diff --git a/WebCore/platform/graphics/haiku/StillImageHaiku.cpp b/WebCore/platform/graphics/haiku/StillImageHaiku.cpp new file mode 100644 index 0000000..7f9fb15 --- /dev/null +++ b/WebCore/platform/graphics/haiku/StillImageHaiku.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de> + * + * 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 "StillImageHaiku.h" + +#include "GraphicsContext.h" +#include "IntSize.h" +#include <View.h> + +namespace WebCore { + +StillImage::StillImage(const BBitmap& bitmap) + : m_bitmap(&bitmap) +{ +} + +void StillImage::destroyDecodedData(bool destroyAll) +{ + // This is used for "large" animations to free image data. + // It appears it would not apply to StillImage. +} + +unsigned StillImage::decodedSize() const +{ + // FIXME: It could be wise to return 0 here, since we don't want WebCore + // to think we eat up memory, since we are not freeing any in + // destroyDecodedData() either. + return m_bitmap.BitsLength(); +} + +IntSize StillImage::size() const +{ + return IntSize(m_bitmap.Bounds().IntegerWidth() + 1, m_bitmap.Bounds().IntegerHeight() + 1); +} + +NativeImagePtr StillImage::nativeImageForCurrentFrame() +{ + return &m_bitmap; +} + +void StillImage::draw(GraphicsContext* context, const FloatRect& destRect, + const FloatRect& sourceRect, ColorSpace, CompositeOperator op) +{ + if (!m_bitmap.IsValid()) + return; + + context->save(); + context->setCompositeOperation(op); + context->platformContext()->DrawBitmap(&m_bitmap, sourceRect, destRect); + context->restore(); +} + +} diff --git a/WebCore/platform/graphics/haiku/StillImageHaiku.h b/WebCore/platform/graphics/haiku/StillImageHaiku.h new file mode 100644 index 0000000..f4bcbe1 --- /dev/null +++ b/WebCore/platform/graphics/haiku/StillImageHaiku.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de> + * + * 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 StillImageHaiku_h +#define StillImageHaiku_h + +#include "Image.h" +#include <Bitmap.h> + +namespace WebCore { + +class StillImage : public Image { +public: + static PassRefPtr<StillImage> create(const BBitmap& bitmap) + { + return adoptRef(new StillImage(bitmap)); + } + + virtual void destroyDecodedData(bool destroyAll = true); + virtual unsigned decodedSize() const; + + virtual IntSize size() const; + virtual NativeImagePtr nativeImageForCurrentFrame(); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); + +private: + StillImage(const BBitmap&); + + BBitmap m_bitmap; +}; + +} // namespace WebCore + +#endif // StillImageHaiku_h diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.h b/WebCore/platform/graphics/mac/Canvas3DLayer.h index 122ef39..4609010 100644 --- a/WebCore/platform/graphics/mac/Canvas3DLayer.h +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.h @@ -32,16 +32,18 @@ namespace WebCore { class GraphicsLayer; + class GraphicsContext3D; } @interface Canvas3DLayer : CAOpenGLLayer { WebCore::GraphicsLayer* m_layerOwner; + WebCore::GraphicsContext3D* m_context; CGLContextObj m_contextObj; GLuint m_texture; } -- (id)initWithContext:(CGLContextObj)context texture:(GLuint)texture; +- (id)initWithContext:(WebCore::GraphicsContext3D*)context; - (CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace; diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.mm b/WebCore/platform/graphics/mac/Canvas3DLayer.mm index 59a7384..22a0a10 100644 --- a/WebCore/platform/graphics/mac/Canvas3DLayer.mm +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.mm @@ -41,10 +41,11 @@ using namespace WebCore; @implementation Canvas3DLayer --(id)initWithContext:(CGLContextObj)context texture:(GLuint)texture +-(id)initWithContext:(GraphicsContext3D*)context { - m_contextObj = context; - m_texture = texture; + m_context = context; + m_contextObj = static_cast<CGLContextObj>(context->platformGraphicsContext3D()); + m_texture = static_cast<GLuint>(context->platformTexture()); self = [super init]; return self; } @@ -70,8 +71,8 @@ using namespace WebCore; -(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { - CGLSetCurrentContext(m_contextObj); - glFinish(); + m_context->prepareTexture(); + CGLSetCurrentContext(glContext); CGRect frame = [self frame]; diff --git a/WebCore/platform/graphics/mac/ComplexTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp index 543d885..b501293 100644 --- a/WebCore/platform/graphics/mac/ComplexTextController.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -68,6 +68,10 @@ ComplexTextController::ComplexTextController(const Font* font, const TextRun& ru , m_characterInCurrentGlyph(0) , m_finalRoundingWidth(0) , m_fallbackFonts(fallbackFonts) + , m_minGlyphBoundingBoxX(numeric_limits<float>::max()) + , m_maxGlyphBoundingBoxX(numeric_limits<float>::min()) + , m_minGlyphBoundingBoxY(numeric_limits<float>::max()) + , m_maxGlyphBoundingBoxY(numeric_limits<float>::min()) , m_lastRoundingGlyph(0) { m_padding = m_run.padding(); @@ -394,7 +398,12 @@ void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) // FIXME: Instead of dividing the glyph's advance equially between the characters, this // could use the glyph's "ligature carets". However, there is no Core Text API to get the // ligature carets. - m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset); + if (glyphStartOffset == glyphEndOffset) { + // When there are multiple glyphs per character we need to advance by the full width of the glyph. + ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph); + m_runWidthSoFar += adjustedAdvance.width; + } else + m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset); if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter) return; @@ -433,6 +442,7 @@ void ComplexTextController::adjustGlyphsAndAdvances() CGFloat roundedSpaceWidth = roundCGFloat(fontData->spaceWidth()); bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances(); bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled(); + CGPoint glyphOrigin = CGPointZero; CFIndex lastCharacterIndex = m_run.ltr() ? numeric_limits<CFIndex>::min() : numeric_limits<CFIndex>::max(); bool isMonotonic = true; @@ -536,6 +546,16 @@ void ComplexTextController::adjustGlyphsAndAdvances() advance.height *= -1; m_adjustedAdvances.append(advance); m_adjustedGlyphs.append(glyph); + + GlyphMetrics glyphMetrics = fontData->metricsForGlyph(glyph); + glyphMetrics.boundingBox.move(glyphOrigin.x, glyphOrigin.y); + m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphMetrics.boundingBox.x()); + m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphMetrics.boundingBox.right()); + m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphMetrics.boundingBox.y()); + m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphMetrics.boundingBox.bottom()); + glyphOrigin.x += advance.width; + glyphOrigin.y += advance.height; + lastCharacterIndex = characterIndex; } if (!isMonotonic) diff --git a/WebCore/platform/graphics/mac/ComplexTextController.h b/WebCore/platform/graphics/mac/ComplexTextController.h index 53e8f7a..280327f 100644 --- a/WebCore/platform/graphics/mac/ComplexTextController.h +++ b/WebCore/platform/graphics/mac/ComplexTextController.h @@ -62,6 +62,11 @@ public: // Extra width to the left of the leftmost glyph. float finalRoundingWidth() const { return m_finalRoundingWidth; } + float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; } + float maxGlyphBoundingBoxX() const { return m_maxGlyphBoundingBoxX; } + float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; } + float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; } + private: class ComplexTextRun : public RefCounted<ComplexTextRun> { public: @@ -173,6 +178,11 @@ private: HashSet<const SimpleFontData*>* m_fallbackFonts; + float m_minGlyphBoundingBoxX; + float m_maxGlyphBoundingBoxX; + float m_minGlyphBoundingBoxY; + float m_maxGlyphBoundingBoxY; + unsigned m_lastRoundingGlyph; }; diff --git a/WebCore/platform/graphics/mac/FontComplexTextMac.cpp b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp index 0db2601..b7ed0e9 100644 --- a/WebCore/platform/graphics/mac/FontComplexTextMac.cpp +++ b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp @@ -33,6 +33,8 @@ #include "SimpleFontData.h" #include <wtf/MathExtras.h> +using namespace std; + namespace WebCore { FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, @@ -83,9 +85,15 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F drawGlyphBuffer(context, glyphBuffer, run, startPoint); } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { ComplexTextController controller(this, run, true, fallbackFonts); + if (glyphOverflow) { + glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent()); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent()); + glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); + glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth())); + } return controller.totalWidth(); } diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index bb9561e..87057fa 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -47,6 +47,28 @@ bool Font::canReturnFallbackFontsForComplexText() return true; } +static void showGlyphsWithAdvances(const FontPlatformData& font, CGContextRef context, const CGGlyph* glyphs, const CGSize* advances, size_t count) +{ + if (!font.isColorBitmapFont()) + CGContextShowGlyphsWithAdvances(context, glyphs, advances, count); +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + else { + if (!count) + return; + + Vector<CGPoint, 256> positions(count); + CGAffineTransform matrix = CGAffineTransformInvert(CGContextGetTextMatrix(context)); + positions[0] = CGPointZero; + for (size_t i = 1; i < count; ++i) { + CGSize advance = CGSizeApplyAffineTransform(advances[i - 1], matrix); + positions[i].x = positions[i - 1].x + advance.width; + positions[i].y = positions[i - 1].y + advance.height; + } + CTFontDrawGlyphs(toCTFontRef(font.font()), glyphs, positions.data(), count, context); + } +#endif +} + void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = context->platformContext(); @@ -98,7 +120,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons CGContextSetFont(cgContext, platformData.cgFont()); CGAffineTransform matrix = CGAffineTransformIdentity; - if (drawFont) + if (drawFont && !platformData.isColorBitmapFont()) memcpy(&matrix, [drawFont matrix], sizeof(matrix)); matrix.b = -matrix.b; matrix.d = -matrix.d; @@ -112,13 +134,14 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } else CGContextSetFontSize(cgContext, platformData.m_size); + IntSize shadowSize; int shadowBlur; Color shadowColor; ColorSpace fillColorSpace = context->fillColorSpace(); context->getShadow(shadowSize, shadowBlur, shadowColor); - bool hasSimpleShadow = context->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; + bool hasSimpleShadow = context->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur && !platformData.isColorBitmapFont(); if (hasSimpleShadow) { // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. context->clearShadow(); @@ -126,19 +149,19 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); context->setFillColor(shadowFillColor, fillColorSpace); CGContextSetTextPosition(cgContext, point.x() + shadowSize.width(), point.y() + shadowSize.height()); - CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + showGlyphsWithAdvances(platformData, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + shadowSize.height()); - CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + showGlyphsWithAdvances(platformData, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } context->setFillColor(fillColor, fillColorSpace); } CGContextSetTextPosition(cgContext, point.x(), point.y()); - CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + showGlyphsWithAdvances(platformData, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + font->syntheticBoldOffset(), point.y()); - CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + showGlyphsWithAdvances(platformData, cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } if (hasSimpleShadow) diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h index faf5f2e..23016e7 100644 --- a/WebCore/platform/graphics/mac/FontPlatformData.h +++ b/WebCore/platform/graphics/mac/FontPlatformData.h @@ -61,6 +61,7 @@ struct FontPlatformData { #ifdef BUILDING_ON_TIGER , m_cgFont(0) #endif + , m_isColorBitmapFont(false) { } @@ -73,6 +74,7 @@ struct FontPlatformData { , m_size(size) , m_font(0) , m_cgFont(cgFont) + , m_isColorBitmapFont(false) { } @@ -113,6 +115,7 @@ struct FontPlatformData { bool roundsGlyphAdvances() const; bool allowsLigatures() const; + bool isColorBitmapFont() const { return m_isColorBitmapFont; } #ifndef BUILDING_ON_TIGER CGFontRef cgFont() const { return m_cgFont.get(); } @@ -133,6 +136,8 @@ private: #else CGFontRef m_cgFont; // It is not necessary to refcount this, since either an NSFont owns it or some CachedFont has it referenced. #endif + + bool m_isColorBitmapFont; }; } diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm index 0118c8b..53b0282 100644 --- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm +++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm @@ -1,7 +1,7 @@ /* * This file is part of the internal font implementation. * - * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -33,6 +33,11 @@ FontPlatformData::FontPlatformData(NSFont *nsFont, bool syntheticBold, bool synt : m_syntheticBold(syntheticBold) , m_syntheticOblique(syntheticOblique) , m_font(nsFont) +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + , m_isColorBitmapFont(CTFontGetSymbolicTraits(toCTFontRef(nsFont)) & kCTFontColorGlyphsTrait) +#else + , m_isColorBitmapFont(false) +#endif { if (nsFont) CFRetain(nsFont); @@ -54,6 +59,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& f) m_size = f.m_size; m_cgFont = f.m_cgFont; m_atsuFontID = f.m_atsuFontID; + m_isColorBitmapFont = f.m_isColorBitmapFont; } FontPlatformData:: ~FontPlatformData() @@ -76,6 +82,7 @@ const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& f) if (m_font && m_font != reinterpret_cast<NSFont *>(-1)) CFRelease(m_font); m_font = f.m_font; + m_isColorBitmapFont = f.m_isColorBitmapFont; return *this; } @@ -96,6 +103,9 @@ void FontPlatformData::setFont(NSFont *font) m_cgFont = wkGetCGFontFromNSFont(font); m_atsuFontID = wkGetNSFontATSUFontId(font); #endif +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + m_isColorBitmapFont = CTFontGetSymbolicTraits(toCTFontRef(font)) & kCTFontColorGlyphsTrait; +#endif } bool FontPlatformData::roundsGlyphAdvances() const diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp index 096cdbd..82c314e 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -30,14 +30,13 @@ #include "GraphicsContext3D.h" #include "CanvasObject.h" -#include "CString.h" #include "ImageBuffer.h" #include "NotImplemented.h" #include "WebGLActiveInfo.h" #include "WebGLArray.h" #include "WebGLBuffer.h" -#include "WebGLFramebuffer.h" #include "WebGLFloatArray.h" +#include "WebGLFramebuffer.h" #include "WebGLIntArray.h" #include "WebGLProgram.h" #include "WebGLRenderbuffer.h" @@ -46,7 +45,9 @@ #include "WebGLUnsignedByteArray.h" #include <CoreGraphics/CGBitmapContext.h> #include <OpenGL/CGLRenderers.h> +#include <OpenGL/gl.h> #include <wtf/UnusedParam.h> +#include <wtf/text/CString.h> namespace WebCore { @@ -75,28 +76,26 @@ static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBi attribs.append(static_cast<CGLPixelFormatAttribute>(0)); } -PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs) +PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow) { - OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs)); + OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs, hostWindow)); return context->m_contextObj ? context.release() : 0; } -GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs) - : m_attrs(attrs) +GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow) + : m_currentWidth(0) + , m_currentHeight(0) + , m_attrs(attrs) , m_contextObj(0) , m_texture(0) , m_fbo(0) - , m_depthBuffer(0) -{ - // FIXME: we need to take into account the user's requested - // context creation attributes, in particular stencil and - // antialias, and determine which could and could not be honored - // based on the capabilities of the OpenGL implementation. - m_attrs.alpha = true; - m_attrs.depth = true; - m_attrs.stencil = false; - m_attrs.antialias = false; - m_attrs.premultipliedAlpha = true; + , m_depthStencilBuffer(0) + , m_boundFBO(0) + , m_multisampleFBO(0) + , m_multisampleDepthStencilBuffer(0) + , m_multisampleColorBuffer(0) +{ + UNUSED_PARAM(hostWindow); Vector<CGLPixelFormatAttribute> attribs; CGLPixelFormatObj pixelFormatObj = 0; @@ -145,6 +144,8 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs) // Set the current context to the one given to us. CGLSetCurrentContext(m_contextObj); + validateAttributes(); + // create a texture to render into ::glGenTextures(1, &m_texture); ::glBindTexture(GL_TEXTURE_2D, m_texture); @@ -152,21 +153,27 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs) ::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); + m_boundFBO = m_fbo; + if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) + ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer); + + // create an multisample FBO + if (m_attrs.antialias) { + ::glGenFramebuffersEXT(1, &m_multisampleFBO); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); + m_boundFBO = m_multisampleFBO; + ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer); + if (m_attrs.stencil || m_attrs.depth) + ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); + } + ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); ::glClearColor(0, 0, 0, 0); } @@ -174,14 +181,46 @@ GraphicsContext3D::~GraphicsContext3D() { if (m_contextObj) { CGLSetCurrentContext(m_contextObj); - ::glDeleteRenderbuffersEXT(1, & m_depthBuffer); ::glDeleteTextures(1, &m_texture); + if (m_attrs.antialias) { + ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer); + if (m_attrs.stencil || m_attrs.depth) + ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); + ::glDeleteFramebuffersEXT(1, &m_multisampleFBO); + } else { + if (m_attrs.stencil || m_attrs.depth) + ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer); + } ::glDeleteFramebuffersEXT(1, &m_fbo); CGLSetCurrentContext(0); CGLDestroyContext(m_contextObj); } } +void GraphicsContext3D::validateAttributes() +{ + const char* extensions = reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS)); + if (m_attrs.stencil) { + if (std::strstr(extensions, "GL_EXT_packed_depth_stencil")) { + if (!m_attrs.depth) + m_attrs.depth = true; + } else + m_attrs.stencil = false; + } + if (m_attrs.antialias) { + bool isValidVendor = true; + // Currently in Mac we only turn on antialias if vendor is NVIDIA. + const char* vendor = reinterpret_cast<const char*>(::glGetString(GL_VENDOR)); + if (!std::strstr(vendor, "NVIDIA")) + isValidVendor = false; + if (!isValidVendor || !std::strstr(extensions, "GL_EXT_framebuffer_multisample")) + m_attrs.antialias = false; + } + // FIXME: instead of enforcing premultipliedAlpha = true, implement the + // correct behavior when premultipliedAlpha = false is requested. + m_attrs.premultipliedAlpha = true; +} + void GraphicsContext3D::makeContextCurrent() { CGLSetCurrentContext(m_contextObj); @@ -206,24 +245,86 @@ void GraphicsContext3D::reshape(int width, int height) CGLSetCurrentContext(m_contextObj); + GLuint internalColorFormat, colorFormat, internalDepthStencilFormat = 0; + if (m_attrs.alpha) { + internalColorFormat = GL_RGBA8; + colorFormat = GL_RGBA; + } else { + internalColorFormat = GL_RGB8; + colorFormat = GL_RGB; + } + if (m_attrs.stencil || m_attrs.depth) { + // We don't allow the logic where stencil is required and depth is not. + // See GraphicsContext3D constructor. + if (m_attrs.stencil && m_attrs.depth) + internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT; + else + internalDepthStencilFormat = GL_DEPTH_COMPONENT; + } + + bool mustRestoreFBO = false; + + // resize multisample FBO + if (m_attrs.antialias) { + GLint maxSampleCount; + ::glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount); + GLint sampleCount = std::min(8, maxSampleCount); + if (sampleCount > maxSampleCount) + sampleCount = maxSampleCount; + if (m_boundFBO != m_multisampleFBO) { + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); + mustRestoreFBO = true; + } + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); + ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalColorFormat, width, height); + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); + if (m_attrs.stencil || m_attrs.depth) { + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); + ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height); + if (m_attrs.stencil) + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); + if (m_attrs.depth) + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); + } + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { + // FIXME: cleanup. + notImplemented(); + } + } + + // resize regular FBO + if (m_boundFBO != m_fbo) { + mustRestoreFBO = true; + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + } ::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); - + ::glTexImage2D(GL_TEXTURE_2D, 0, internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 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) { + ::glBindTexture(GL_TEXTURE_2D, 0); + if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) { + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer); + ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height); + if (m_attrs.stencil) + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); + if (m_attrs.depth) + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + } + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { // FIXME: cleanup notImplemented(); } - ::glClear(GL_COLOR_BUFFER_BIT); + if (mustRestoreFBO) + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); + + GLenum clearMask = GL_COLOR_BUFFER_BIT; + if (m_attrs.depth) + clearMask |= GL_DEPTH_BUFFER_BIT; + if (m_attrs.stencil) + clearMask |= GL_STENCIL_BUFFER_BIT; + ::glClear(clearMask); ::glFlush(); } @@ -237,6 +338,18 @@ static inline void ensureContext(CGLContextObj context) CGLSetCurrentContext(context); } +void GraphicsContext3D::prepareTexture() +{ + if (m_attrs.antialias) { + ensureContext(m_contextObj); + ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); + ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); + ::glBlitFramebufferEXT(0, 0, m_currentWidth, m_currentHeight, 0, 0, m_currentWidth, m_currentHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); + } + ::glFinish(); +} + void GraphicsContext3D::activeTexture(unsigned long texture) { ensureContext(m_contextObj); @@ -268,7 +381,15 @@ void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer) void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer) { ensureContext(m_contextObj); - ::glBindFramebufferEXT(target, (buffer && buffer->object()) ? (GLuint) buffer->object() : m_fbo); + GLuint fbo; + if (buffer && buffer->object()) + fbo = (GLuint)buffer->object(); + else + fbo = (m_attrs.antialias ? m_multisampleFBO : m_fbo); + if (fbo != m_boundFBO) { + ::glBindFramebufferEXT(target, fbo); + m_boundFBO = fbo; + } } void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer) @@ -384,13 +505,29 @@ void GraphicsContext3D::compileShader(WebGLShader* shader) 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); + if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) { + ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); + ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); + ::glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + } ::glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); + if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); } 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); + if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) { + ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); + ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); + ::glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + } ::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); + if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); } void GraphicsContext3D::cullFace(unsigned long mode) @@ -476,7 +613,12 @@ void GraphicsContext3D::flush() void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer) { ensureContext(m_contextObj); - ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer ? (GLuint) buffer->object() : 0); + GLuint renderbuffer = (buffer ? (GLuint) buffer->object() : 0); + if (attachment == DEPTH_STENCIL_ATTACHMENT) { + ::glFramebufferRenderbufferEXT(target, DEPTH_ATTACHMENT, renderbuffertarget, renderbuffer); + ::glFramebufferRenderbufferEXT(target, STENCIL_ATTACHMENT, renderbuffertarget, renderbuffer); + } else + ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, renderbuffer); } void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level) @@ -665,20 +807,22 @@ void GraphicsContext3D::polygonOffset(double factor, double units) ::glPolygonOffset(static_cast<float>(factor), static_cast<float>(units)); } -PassRefPtr<WebGLArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type) +void GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* data) { + // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e., + // all previous rendering calls should be done before reading pixels. ensureContext(m_contextObj); - - // FIXME: For now we only accept GL_UNSIGNED_BYTE/GL_RGBA. In reality OpenGL ES 2.0 accepts that pair and one other - // as specified by GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE. But for now we will - // not accept those. - // FIXME: Also, we should throw when an unacceptable value is passed - if (type != GL_UNSIGNED_BYTE || format != GL_RGBA) - return 0; - - RefPtr<WebGLUnsignedByteArray> array = WebGLUnsignedByteArray::create(width * height * 4); - ::glReadPixels(x, y, width, height, format, type, (GLvoid*) array->data()); - return array; + ::glFlush(); + if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) { + ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); + ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); + ::glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + ::glFlush(); + } + ::glReadPixels(x, y, width, height, format, type, data); + if (m_attrs.antialias && m_boundFBO == m_multisampleFBO) + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); } void GraphicsContext3D::releaseShaderCompiler() @@ -691,6 +835,10 @@ void GraphicsContext3D::releaseShaderCompiler() void GraphicsContext3D::renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height) { ensureContext(m_contextObj); + if (internalformat == DEPTH_STENCIL) + internalformat = GL_DEPTH24_STENCIL8_EXT; + else if (internalformat == DEPTH_COMPONENT16) + internalformat = GL_DEPTH_COMPONENT; ::glRenderbufferStorageEXT(target, internalformat, width, height); } @@ -986,6 +1134,8 @@ void GraphicsContext3D::getFloatv(unsigned long pname, float* value) void GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value) { ensureContext(m_contextObj); + if (attachment == DEPTH_STENCIL_ATTACHMENT) + attachment = DEPTH_ATTACHMENT; // Or STENCIL_ATTACHMENT, either works. ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value); } diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index 5362562..49aebba 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -340,6 +340,7 @@ private: RetainPtr<WebAnimationDelegate> m_animationDelegate; + RetainPtr<CGImageRef> m_uncorrectedContentsImage; RetainPtr<CGImageRef> m_pendingContentsImage; struct LayerAnimation { diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index 22e39f5..294c82f 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -34,7 +34,6 @@ #if ENABLE(3D_CANVAS) #import "Canvas3DLayer.h" #endif -#import "CString.h" #import "FloatConversion.h" #import "FloatRect.h" #import "Image.h" @@ -769,7 +768,17 @@ void GraphicsLayerCA::pauseAnimation(const String& keyframesName, double timeOff void GraphicsLayerCA::setContentsToImage(Image* image) { if (image) { - m_pendingContentsImage = image->nativeImageForCurrentFrame(); + CGImageRef newImage = image->nativeImageForCurrentFrame(); + if (!newImage) + return; + + // Check to see if the image changed; we have to do this because the call to + // CGImageCreateCopyWithColorSpace() below can create a new image every time. + if (m_uncorrectedContentsImage && m_uncorrectedContentsImage.get() == newImage) + return; + + m_uncorrectedContentsImage = newImage; + m_pendingContentsImage = newImage; CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get()); static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); @@ -783,6 +792,7 @@ void GraphicsLayerCA::setContentsToImage(Image* image) if (!m_contentsLayer) noteSublayersChanged(); } else { + m_uncorrectedContentsImage = 0; m_pendingContentsImage = 0; m_contentsLayerPurpose = NoContentsLayer; if (m_contentsLayer) @@ -1716,7 +1726,7 @@ void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* gr 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)]); + m_contentsLayer.adoptNS([[Canvas3DLayer alloc] initWithContext:const_cast<GraphicsContext3D*>(graphicsContext3D)]); #ifndef NDEBUG [m_contentsLayer.get() setName:@"3D Layer"]; #endif @@ -1859,12 +1869,28 @@ void GraphicsLayerCA::setupAnimation(CAPropertyAnimation* propertyAnim, const An else if (anim->direction() == Animation::AnimationDirectionAlternate) repeatCount /= 2; + NSString* fillMode = 0; + switch (anim->fillMode()) { + case AnimationFillModeNone: + fillMode = kCAFillModeForwards; // Use "forwards" rather than "removed" because the style system will remove the animation when it is finished. This avoids a flash. + break; + case AnimationFillModeBackwards: + fillMode = kCAFillModeBoth; // Use "both" rather than "backwards" because the style system will remove the animation when it is finished. This avoids a flash. + break; + case AnimationFillModeForwards: + fillMode = kCAFillModeForwards; + break; + case AnimationFillModeBoth: + fillMode = kCAFillModeBoth; + break; + } + [propertyAnim setDuration:duration]; [propertyAnim setRepeatCount:repeatCount]; [propertyAnim setAutoreverses:anim->direction()]; [propertyAnim setRemovedOnCompletion:NO]; [propertyAnim setAdditive:additive]; - [propertyAnim setFillMode:@"extended"]; + [propertyAnim setFillMode:fillMode]; [propertyAnim setDelegate:m_animationDelegate.get()]; } @@ -2226,6 +2252,7 @@ void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer) { // Turn off implicit animations on the inner layer. [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; + [contentsLayer setMasksToBounds:YES]; if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) { CATransform3D flipper = { diff --git a/WebCore/platform/graphics/mac/ImageMac.mm b/WebCore/platform/graphics/mac/ImageMac.mm index 672c3c8..96b93be 100644 --- a/WebCore/platform/graphics/mac/ImageMac.mm +++ b/WebCore/platform/graphics/mac/ImageMac.mm @@ -30,6 +30,7 @@ #import "FoundationExtras.h" #import "GraphicsContext.h" #import "PlatformString.h" +#import "SharedBuffer.h" @interface WebCoreBundleFinder : NSObject @end diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 355aa68..2636aeb 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -59,7 +59,6 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface { public: static void registerMediaEngine(MediaEngineRegistrar); - ~MediaPlayerPrivate(); void repaint(); void loadStateChanged(); @@ -70,6 +69,7 @@ public: private: MediaPlayerPrivate(MediaPlayer*); + ~MediaPlayerPrivate(); // engine support static MediaPlayerPrivateInterface* create(MediaPlayer* player); @@ -89,9 +89,12 @@ private: void load(const String& url); void cancelLoad(); + void loadInternal(const String& url); + void resumeLoad(); void play(); void pause(); + void prepareToPlay(); bool paused() const; bool seeking() const; @@ -107,6 +110,8 @@ private: bool hasClosedCaptions() const; void setClosedCaptionsVisible(bool); + void setPreload(MediaPlayer::Preload); + MediaPlayer::NetworkState networkState() const { return m_networkState; } MediaPlayer::ReadyState readyState() const { return m_readyState; } @@ -172,6 +177,7 @@ private: RetainPtr<QTMovieView> m_qtMovieView; RetainPtr<QTVideoRendererWebKitOnly> m_qtVideoRenderer; RetainPtr<WebCoreMovieObserver> m_objcObserver; + String m_movieURL; float m_seekTo; Timer<MediaPlayerPrivate> m_seekTimer; MediaPlayer::NetworkState m_networkState; @@ -184,11 +190,13 @@ private: float m_cachedDuration; float m_timeToRestore; RetainPtr<QTMovieLayer> m_qtVideoLayer; + MediaPlayer::Preload m_preload; bool m_startedPlaying; bool m_isStreaming; bool m_visible; bool m_hasUnsupportedTracks; bool m_videoFrameHasDrawn; + bool m_delayingLoad; #if DRAW_FRAME_RATE int m_frameCountWhilePlaying; double m_timeStartedPlaying; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index 2b90f7a..c837b51 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -211,6 +211,7 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_reportedDuration(-1) , m_cachedDuration(-1) , m_timeToRestore(-1) + , m_preload(MediaPlayer::Auto) , m_startedPlaying(false) , m_isStreaming(false) , m_visible(false) @@ -549,8 +550,30 @@ QTTime MediaPlayerPrivate::createQTTime(float time) const return QTMakeTime(time * timeScale, timeScale); } +void MediaPlayerPrivate::resumeLoad() +{ + m_delayingLoad = false; + + if (m_movieURL) + loadInternal(m_movieURL); +} + void MediaPlayerPrivate::load(const String& url) { + m_movieURL = url; + + // If the element is not supposed to load any data return immediately because QTKit + // doesn't have API to throttle loading. + if (m_preload == MediaPlayer::None) { + m_delayingLoad = true; + return; + } + + loadInternal(url); +} + +void MediaPlayerPrivate::loadInternal(const String& url) +{ if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; m_player->networkStateChanged(); @@ -570,6 +593,12 @@ void MediaPlayerPrivate::load(const String& url) [m_objcObserver.get() setDelayCallbacks:NO]; } +void MediaPlayerPrivate::prepareToPlay() +{ + if (!m_qtMovie || m_delayingLoad) + resumeLoad(); +} + PlatformMedia MediaPlayerPrivate::platformMedia() const { PlatformMedia plaftformMedia = { m_qtMovie.get() }; @@ -910,6 +939,7 @@ void MediaPlayerPrivate::updateStates() loadState = QTMovieLoadStateError; if (loadState != QTMovieLoadStateError) { + wkQTMovieSelectPreferredAlternates(m_qtMovie.get()); cacheMovieScale(); MediaPlayer::MovieLoadType movieType = movieLoadType(); m_isStreaming = movieType == MediaPlayer::StoredStream || movieType == MediaPlayer::LiveStream; @@ -1437,6 +1467,12 @@ MediaPlayer::MovieLoadType MediaPlayerPrivate::movieLoadType() const return movieType; } +void MediaPlayerPrivate::setPreload(MediaPlayer::Preload preload) +{ + m_preload = preload; + if (m_delayingLoad && m_preload != MediaPlayer::None) + resumeLoad(); +} } // namespace WebCore diff --git a/WebCore/platform/graphics/mac/MediaPlayerProxy.h b/WebCore/platform/graphics/mac/MediaPlayerProxy.h index 6060484..cc7ec95 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerProxy.h +++ b/WebCore/platform/graphics/mac/MediaPlayerProxy.h @@ -40,8 +40,8 @@ enum MediaPlayerProxyNotificationType { MediaPlayerNotificationStartUsingNetwork, MediaPlayerNotificationStopUsingNetwork, - MediaPlayerNotificationEnteredFullScreen, - MediaPlayerNotificationExitedFullScreen, + MediaPlayerNotificationEnteredFullscreen, + MediaPlayerNotificationExitedFullscreen, MediaPlayerNotificationReadyForInspection, MediaPlayerNotificationReadyForPlayback, diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index 09947d8..562f56e 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -407,17 +407,29 @@ void SimpleFontData::determinePitch() [name caseInsensitiveCompare:@"MonotypeCorsiva"] != NSOrderedSame; } -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode metricsMode) const { - NSFont* font = m_platformData.font(); - float pointSize = m_platformData.m_size; + NSFont* font = platformData().font(); + float pointSize = platformData().m_size; CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize); CGSize advance; - if (!wkGetGlyphTransformedAdvances(m_platformData.cgFont(), font, &m, &glyph, &advance)) { + if (!wkGetGlyphTransformedAdvances(platformData().cgFont(), font, &m, &glyph, &advance)) { LOG_ERROR("Unable to cache glyph widths for %@ %f", [font displayName], pointSize); advance.width = 0; } - return advance.width + m_syntheticBoldOffset; + GlyphMetrics metrics; + metrics.horizontalAdvance = advance.width + m_syntheticBoldOffset; + if (metricsMode == GlyphBoundingBox) { +#ifndef BUILDING_ON_TIGER + CGRect boundingBox; + CGFontGetGlyphBBoxes(platformData().cgFont(), &glyph, 1, &boundingBox); + CGFloat scale = pointSize / unitsPerEm(); + metrics.boundingBox = CGRectApplyAffineTransform(boundingBox, CGAffineTransformMakeScale(scale, -scale)); + if (m_syntheticBoldOffset) + metrics.boundingBox.setWidth(metrics.boundingBox.width() + m_syntheticBoldOffset); +#endif + } + return metrics; } #if USE(ATSUI) diff --git a/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp b/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp index 3c7eaf2..d681d75 100644 --- a/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp +++ b/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.cpp @@ -263,6 +263,30 @@ EGLSurface EGLDisplayOpenVG::createPbufferSurface(const IntSize& size, const EGL return surface; } +EGLSurface EGLDisplayOpenVG::createPbufferFromClientBuffer( + EGLClientBuffer clientBuffer, EGLenum bufferType, const EGLConfig& config, EGLint* errorCode) +{ + EGLSurface surface = eglCreatePbufferFromClientBuffer(m_display, + bufferType, clientBuffer, config, 0 /* attribList */); + + if (errorCode) + *errorCode = eglGetError(); + else + ASSERT_EGL_NO_ERROR(); + + if (surface == EGL_NO_SURFACE) + return EGL_NO_SURFACE; + + EGLint surfaceConfigId; + EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId); + ASSERT(success == EGL_TRUE); + ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE); + + ASSERT(!m_surfaceConfigIds.contains(surface)); + m_surfaceConfigIds.set(surface, surfaceConfigId); + return surface; +} + EGLSurface EGLDisplayOpenVG::surfaceForWindow(EGLNativeWindowType wId, const EGLConfig& config) { if (m_windowSurfaces.contains(wId)) diff --git a/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h b/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h index fd8353d..0dff6c9 100644 --- a/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h +++ b/WebCore/platform/graphics/openvg/EGLDisplayOpenVG.h @@ -51,6 +51,7 @@ public: * If no surface could be created and errorCode is zero, this method * will trigger an assertion by itself. */ EGLSurface createPbufferSurface(const IntSize&, const EGLConfig&, EGLint* errorCode = 0); + EGLSurface createPbufferFromClientBuffer(EGLClientBuffer, EGLenum bufferType, const EGLConfig&, EGLint* errorCode = 0); EGLSurface surfaceForWindow(EGLNativeWindowType, const EGLConfig&); diff --git a/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp b/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp index 5ed892c..54cc7ee 100644 --- a/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp +++ b/WebCore/platform/graphics/openvg/GraphicsContextOpenVG.cpp @@ -20,11 +20,12 @@ #include "config.h" #include "GraphicsContext.h" +#include "AffineTransform.h" #include "GraphicsContextPrivate.h" +#include "KURL.h" #include "NotImplemented.h" #include "PainterOpenVG.h" #include "SurfaceOpenVG.h" -#include "TransformationMatrix.h" #include <wtf/Assertions.h> #include <wtf/MathExtras.h> @@ -69,12 +70,12 @@ PlatformGraphicsContext* GraphicsContext::platformContext() const return m_data->baseSurface(); } -TransformationMatrix GraphicsContext::getCTM() const +AffineTransform GraphicsContext::getCTM() const { if (paintingDisabled()) - return TransformationMatrix(); + return AffineTransform(); - return m_data->transformationMatrix(); + return m_data->transformation(); } void GraphicsContext::savePlatformState() @@ -143,7 +144,7 @@ void GraphicsContext::fillPath() if (paintingDisabled()) return; - notImplemented(); + m_data->drawPath(VG_FILL_PATH, m_common->state.fillRule); } void GraphicsContext::strokePath() @@ -151,7 +152,15 @@ void GraphicsContext::strokePath() if (paintingDisabled()) return; - notImplemented(); + m_data->drawPath(VG_STROKE_PATH, m_common->state.fillRule); +} + +void GraphicsContext::drawPath() +{ + if (paintingDisabled()) + return; + + m_data->drawPath(VG_FILL_PATH | VG_STROKE_PATH, m_common->state.fillRule); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -193,7 +202,7 @@ void GraphicsContext::beginPath() if (paintingDisabled()) return; - notImplemented(); + m_data->beginPath(); } void GraphicsContext::addPath(const Path& path) @@ -201,7 +210,7 @@ void GraphicsContext::addPath(const Path& path) if (paintingDisabled()) return; - notImplemented(); + m_data->addPath(path); } void GraphicsContext::clip(const FloatRect& rect) @@ -217,8 +226,7 @@ void GraphicsContext::clipPath(WindRule clipRule) if (paintingDisabled()) return; - notImplemented(); - UNUSED_PARAM(clipRule); + m_data->clipPath(*(m_data->currentPath()), PainterOpenVG::IntersectClip, clipRule); } void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) @@ -281,7 +289,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) if (paintingDisabled()) return FloatRect(); - return FloatRect(enclosingIntRect(m_data->transformationMatrix().mapRect(rect))); + return FloatRect(enclosingIntRect(m_data->transformation().mapRect(rect))); } void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace) @@ -404,8 +412,7 @@ void GraphicsContext::clip(const Path& path) if (paintingDisabled()) return; - notImplemented(); - UNUSED_PARAM(path); + m_data->clipPath(path, PainterOpenVG::IntersectClip, m_common->state.fillRule); } void GraphicsContext::canvasClip(const Path& path) @@ -418,8 +425,7 @@ void GraphicsContext::clipOut(const Path& path) if (paintingDisabled()) return; - notImplemented(); - UNUSED_PARAM(path); + m_data->clipPath(path, PainterOpenVG::SubtractClip, m_common->state.fillRule); } void GraphicsContext::scale(const FloatSize& scaleFactors) @@ -451,8 +457,8 @@ IntPoint GraphicsContext::origin() if (paintingDisabled()) return IntPoint(); - TransformationMatrix matrix = m_data->transformationMatrix(); - return IntPoint(roundf(matrix.m41()), roundf(matrix.m42())); + AffineTransform transformation = m_data->transformation(); + return IntPoint(roundf(transformation.e()), roundf(transformation.f())); } void GraphicsContext::clipOut(const IntRect& rect) @@ -460,8 +466,9 @@ void GraphicsContext::clipOut(const IntRect& rect) if (paintingDisabled()) return; - notImplemented(); - UNUSED_PARAM(rect); + Path path; + path.addRect(rect); + m_data->clipPath(path, PainterOpenVG::SubtractClip, m_common->state.fillRule); } void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) @@ -469,8 +476,9 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) if (paintingDisabled()) return; - notImplemented(); - UNUSED_PARAM(rect); + Path path; + path.addEllipse(rect); + m_data->clipPath(path, PainterOpenVG::SubtractClip, m_common->state.fillRule); } void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer) @@ -488,17 +496,20 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness if (paintingDisabled()) return; - notImplemented(); - UNUSED_PARAM(rect); - UNUSED_PARAM(thickness); + Path path; + path.addEllipse(rect); + path.addEllipse(FloatRect(rect.x() + thickness, rect.y() + thickness, + rect.width() - (thickness * 2), rect.height() - (thickness * 2))); + + m_data->clipPath(path, PainterOpenVG::IntersectClip, m_common->state.fillRule); } -void GraphicsContext::concatCTM(const TransformationMatrix& transform) +void GraphicsContext::concatCTM(const AffineTransform& transformation) { if (paintingDisabled()) return; - m_data->concatTransformationMatrix(transform); + m_data->concatTransformation(transformation); } void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) diff --git a/WebCore/platform/graphics/openvg/PainterOpenVG.cpp b/WebCore/platform/graphics/openvg/PainterOpenVG.cpp index 3b7cf85..5842afd 100644 --- a/WebCore/platform/graphics/openvg/PainterOpenVG.cpp +++ b/WebCore/platform/graphics/openvg/PainterOpenVG.cpp @@ -20,6 +20,7 @@ #include "config.h" #include "PainterOpenVG.h" +#include "AffineTransform.h" #include "Color.h" #include "DashArray.h" #include "FloatPoint.h" @@ -28,8 +29,8 @@ #include "IntRect.h" #include "IntSize.h" #include "NotImplemented.h" +#include "PlatformPathOpenVG.h" #include "SurfaceOpenVG.h" -#include "TransformationMatrix.h" #include "VGUtils.h" #if PLATFORM(EGL) @@ -43,12 +44,9 @@ namespace WebCore { -static bool isNonRotatedAffineTransformation(const TransformationMatrix& matrix) +static bool isNonRotatedAffineTransformation(const AffineTransform& t) { - return matrix.m12() <= FLT_EPSILON && matrix.m13() <= FLT_EPSILON && matrix.m14() <= FLT_EPSILON - && matrix.m21() <= FLT_EPSILON && matrix.m23() <= FLT_EPSILON && matrix.m24() <= FLT_EPSILON - && matrix.m31() <= FLT_EPSILON && matrix.m32() <= FLT_EPSILON && matrix.m34() <= FLT_EPSILON - && matrix.m44() >= 1 - FLT_EPSILON; + return t.b() <= FLT_EPSILON && t.c() <= FLT_EPSILON; } static VGCapStyle toVGCapStyle(LineCap lineCap) @@ -103,12 +101,16 @@ static void setVGSolidColor(VGPaintMode paintMode, const Color& color) struct PlatformPainterState { - TransformationMatrix surfaceTransformationMatrix; + AffineTransform surfaceTransformation; CompositeOperator compositeOperation; float opacity; bool scissoringEnabled; FloatRect scissorRect; +#ifdef OPENVG_VERSION_1_1 + bool maskingChangedAndEnabled; + VGMaskLayer mask; +#endif Color fillColor; StrokeStyle strokeStyle; @@ -120,12 +122,17 @@ struct PlatformPainterState { DashArray strokeDashArray; float strokeDashOffset; + int textDrawingMode; bool antialiasingEnabled; PlatformPainterState() : compositeOperation(CompositeSourceOver) , opacity(1.0) , scissoringEnabled(false) +#ifdef OPENVG_VERSION_1_1 + , maskingChangedAndEnabled(false) + , mask(VG_INVALID_HANDLE) +#endif , fillColor(Color::black) , strokeStyle(NoStroke) , strokeThickness(0.0) @@ -133,19 +140,40 @@ struct PlatformPainterState { , strokeLineJoin(MiterJoin) , strokeMiterLimit(4.0) , strokeDashOffset(0.0) + , textDrawingMode(cTextFill) , antialiasingEnabled(true) { } + ~PlatformPainterState() + { +#ifdef OPENVG_VERSION_1_1 + if (maskingChangedAndEnabled && mask != VG_INVALID_HANDLE) { + vgDestroyMaskLayer(mask); + ASSERT_VG_NO_ERROR(); + mask = VG_INVALID_HANDLE; + } +#endif + } + PlatformPainterState(const PlatformPainterState& state) { - surfaceTransformationMatrix = state.surfaceTransformationMatrix; + surfaceTransformation = state.surfaceTransformation; scissoringEnabled = state.scissoringEnabled; scissorRect = state.scissorRect; +#ifdef OPENVG_VERSION_1_1 + maskingChangedAndEnabled = false; + mask = state.mask; +#endif copyPaintState(&state); } + inline bool maskingEnabled() + { + return maskingChangedAndEnabled || mask != VG_INVALID_HANDLE; + } + void copyPaintState(const PlatformPainterState* other) { compositeOperation = other->compositeOperation; @@ -161,6 +189,7 @@ struct PlatformPainterState { strokeDashArray = other->strokeDashArray; strokeDashOffset = other->strokeDashOffset; + textDrawingMode = other->textDrawingMode; antialiasingEnabled = other->antialiasingEnabled; } @@ -184,8 +213,18 @@ struct PlatformPainterState { applyBlending(painter); applyStrokeStyle(); - applyTransformationMatrix(painter); + applyTransformation(painter); applyScissorRect(); + +#ifdef OPENVG_VERSION_1_1 + if (maskingEnabled()) { + vgSeti(VG_MASKING, VG_TRUE); + if (mask != VG_INVALID_HANDLE) + vgMask(mask, VG_SET_MASK, 0, 0, painter->surface()->width(), painter->surface()->height()); + } else + vgSeti(VG_MASKING, VG_FALSE); +#endif + ASSERT_VG_NO_ERROR(); } void applyBlending(PainterOpenVG* painter) @@ -267,12 +306,12 @@ struct PlatformPainterState { ASSERT_VG_NO_ERROR(); } - void applyTransformationMatrix(PainterOpenVG* painter) + void applyTransformation(PainterOpenVG* painter) { // There are *five* separate transforms that can be applied to OpenVG as of 1.1 // but it is not clear that we need to set them separately. Instead we set them // all right here and let this be a call to essentially set the world transformation! - VGMatrix vgMatrix(surfaceTransformationMatrix); + VGMatrix vgMatrix(surfaceTransformation); const VGfloat* vgFloatArray = vgMatrix.toVGfloat(); vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); @@ -337,18 +376,36 @@ struct PlatformPainterState { { return (compositeOperation == CompositeSourceOver && !fillColor.alpha()); } + + void saveMaskIfNecessary(PainterOpenVG* painter) + { +#ifdef OPENVG_VERSION_1_1 + if (maskingChangedAndEnabled) { + if (mask != VG_INVALID_HANDLE) { + vgDestroyMaskLayer(mask); + ASSERT_VG_NO_ERROR(); + } + mask = vgCreateMaskLayer(painter->surface()->width(), painter->surface()->height()); + ASSERT(mask != VG_INVALID_HANDLE); + vgCopyMask(mask, 0, 0, 0, 0, painter->surface()->width(), painter->surface()->height()); + ASSERT_VG_NO_ERROR(); + } +#endif + } }; PainterOpenVG::PainterOpenVG() : m_state(0) , m_surface(0) + , m_currentPath(0) { } PainterOpenVG::PainterOpenVG(SurfaceOpenVG* surface) : m_state(0) , m_surface(0) + , m_currentPath(0) { ASSERT(surface); begin(surface); @@ -357,6 +414,7 @@ PainterOpenVG::PainterOpenVG(SurfaceOpenVG* surface) PainterOpenVG::~PainterOpenVG() { end(); + delete m_currentPath; } void PainterOpenVG::begin(SurfaceOpenVG* surface) @@ -417,31 +475,53 @@ void PainterOpenVG::blitToSurface() m_surface->flush(); } -TransformationMatrix PainterOpenVG::transformationMatrix() const +AffineTransform PainterOpenVG::transformation() const { ASSERT(m_state); - return m_state->surfaceTransformationMatrix; + return m_state->surfaceTransformation; } -void PainterOpenVG::concatTransformationMatrix(const TransformationMatrix& matrix) +void PainterOpenVG::concatTransformation(const AffineTransform& transformation) { ASSERT(m_state); m_surface->makeCurrent(); - // We do the multiplication ourself using WebCore's TransformationMatrix rather than - // offloading this to VG via vgMultMatrix to keep things simple and so we can maintain - // state ourselves. - m_state->surfaceTransformationMatrix.multLeft(matrix); - m_state->applyTransformationMatrix(this); + // We do the multiplication ourself using WebCore's AffineTransform rather + // than offloading this to VG via vgMultMatrix() to keep things simple and + // so we can maintain state ourselves. + m_state->surfaceTransformation.multLeft(transformation); + m_state->applyTransformation(this); } -void PainterOpenVG::setTransformationMatrix(const TransformationMatrix& matrix) +void PainterOpenVG::setTransformation(const AffineTransform& transformation) { ASSERT(m_state); m_surface->makeCurrent(); - m_state->surfaceTransformationMatrix = matrix; - m_state->applyTransformationMatrix(this); + m_state->surfaceTransformation = transformation; + m_state->applyTransformation(this); +} + +void PainterOpenVG::transformPath(VGPath dst, VGPath src, const AffineTransform& transformation) +{ + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + + // Save the transform state + VGfloat currentMatrix[9]; + vgGetMatrix(currentMatrix); + ASSERT_VG_NO_ERROR(); + + // Load the new transform + vgLoadMatrix(VGMatrix(transformation).toVGfloat()); + ASSERT_VG_NO_ERROR(); + + // Apply the new transform + vgTransformPath(dst, src); + ASSERT_VG_NO_ERROR(); + + // Restore the transform state + vgLoadMatrix(currentMatrix); + ASSERT_VG_NO_ERROR(); } CompositeOperator PainterOpenVG::compositeOperation() const @@ -575,6 +655,18 @@ void PainterOpenVG::setFillColor(const Color& color) setVGSolidColor(VG_FILL_PATH, color); } +int PainterOpenVG::textDrawingMode() const +{ + ASSERT(m_state); + return m_state->textDrawingMode; +} + +void PainterOpenVG::setTextDrawingMode(int mode) +{ + ASSERT(m_state); + m_state->textDrawingMode = mode; +} + bool PainterOpenVG::antialiasingEnabled() const { ASSERT(m_state); @@ -599,9 +691,9 @@ void PainterOpenVG::scale(const FloatSize& scaleFactors) ASSERT(m_state); m_surface->makeCurrent(); - TransformationMatrix matrix = m_state->surfaceTransformationMatrix; - matrix.scaleNonUniform(scaleFactors.width(), scaleFactors.height()); - setTransformationMatrix(matrix); + AffineTransform transformation = m_state->surfaceTransformation; + transformation.scaleNonUniform(scaleFactors.width(), scaleFactors.height()); + setTransformation(transformation); } void PainterOpenVG::rotate(float radians) @@ -609,9 +701,9 @@ void PainterOpenVG::rotate(float radians) ASSERT(m_state); m_surface->makeCurrent(); - TransformationMatrix matrix = m_state->surfaceTransformationMatrix; - matrix.rotate(rad2deg(radians)); - setTransformationMatrix(matrix); + AffineTransform transformation = m_state->surfaceTransformation; + transformation.rotate(rad2deg(radians)); + setTransformation(transformation); } void PainterOpenVG::translate(float dx, float dy) @@ -619,9 +711,50 @@ void PainterOpenVG::translate(float dx, float dy) ASSERT(m_state); m_surface->makeCurrent(); - TransformationMatrix matrix = m_state->surfaceTransformationMatrix; - matrix.translate(dx, dy); - setTransformationMatrix(matrix); + AffineTransform transformation = m_state->surfaceTransformation; + transformation.translate(dx, dy); + setTransformation(transformation); +} + +void PainterOpenVG::beginPath() +{ + delete m_currentPath; + m_currentPath = new Path(); +} + +void PainterOpenVG::addPath(const Path& path) +{ + m_currentPath->platformPath()->makeCompatibleContextCurrent(); + + vgAppendPath(m_currentPath->platformPath()->vgPath(), path.platformPath()->vgPath()); + ASSERT_VG_NO_ERROR(); +} + +Path* PainterOpenVG::currentPath() const +{ + return m_currentPath; +} + +void PainterOpenVG::drawPath(VGbitfield specifiedPaintModes, WindRule fillRule) +{ + ASSERT(m_state); + + VGbitfield paintModes = 0; + if (!m_state->strokeDisabled()) + paintModes |= VG_STROKE_PATH; + if (!m_state->fillDisabled()) + paintModes |= VG_FILL_PATH; + + paintModes &= specifiedPaintModes; + + if (!paintModes) + return; + + m_surface->makeCurrent(); + + vgSeti(VG_FILL_RULE, toVGFillRule(fillRule)); + vgDrawPath(m_currentPath->platformPath()->vgPath(), paintModes); + ASSERT_VG_NO_ERROR(); } void PainterOpenVG::intersectScissorRect(const FloatRect& rect) @@ -649,7 +782,7 @@ void PainterOpenVG::intersectClipRect(const FloatRect& rect) ASSERT(m_state); m_surface->makeCurrent(); - if (m_state->surfaceTransformationMatrix.isIdentity()) { + if (m_state->surfaceTransformation.isIdentity()) { // No transformation required, skip all the complex stuff. intersectScissorRect(rect); return; @@ -660,16 +793,49 @@ void PainterOpenVG::intersectClipRect(const FloatRect& rect) // (potentially more expensive) path clipping. Note that scissoring is not // subject to transformations, so we need to do the transformation to // surface coordinates by ourselves. - FloatQuad effectiveScissorQuad = - m_state->surfaceTransformationMatrix.mapQuad(FloatQuad(rect)); + FloatQuad effectiveScissorQuad = m_state->surfaceTransformation.mapQuad(FloatQuad(rect)); if (effectiveScissorQuad.isRectilinear()) intersectScissorRect(effectiveScissorQuad.boundingBox()); else { // The transformed scissorRect cannot be represented as FloatRect - // anymore, so we need to perform masking instead. Not yet implemented. - notImplemented(); + // anymore, so we need to perform masking instead. + Path scissorRectPath; + scissorRectPath.addRect(rect); + clipPath(scissorRectPath, PainterOpenVG::IntersectClip); + } +} + +void PainterOpenVG::clipPath(const Path& path, PainterOpenVG::ClipOperation maskOp, WindRule clipRule) +{ +#ifdef OPENVG_VERSION_1_1 + ASSERT(m_state); + m_surface->makeCurrent(); + + if (m_state->mask != VG_INVALID_HANDLE && !m_state->maskingChangedAndEnabled) { + // The parent's mask has been inherited - dispose the handle so that + // it won't be overwritten. + m_state->maskingChangedAndEnabled = true; + m_state->mask = VG_INVALID_HANDLE; + } else if (!m_state->maskingEnabled()) { + // None of the parent painter states had a mask enabled yet. + m_state->maskingChangedAndEnabled = true; + vgSeti(VG_MASKING, VG_TRUE); + // Make sure not to inherit previous mask state from previously written + // (but disabled) masks. For VG_FILL_MASK the first argument is ignored, + // we pass VG_INVALID_HANDLE which is what the OpenVG spec suggests. + vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, m_surface->width(), m_surface->height()); } + + // Intersect the path from the mask, or subtract it from there. + // (In either case we always decrease the visible area, never increase it, + // which means masking never has to modify scissor rectangles.) + vgSeti(VG_FILL_RULE, toVGFillRule(clipRule)); + vgRenderToMask(path.platformPath()->vgPath(), VG_FILL_PATH, (VGMaskOperation) maskOp); + ASSERT_VG_NO_ERROR(); +#elseif + notImplemented(); +#endif } void PainterOpenVG::drawRect(const FloatRect& rect, VGbitfield specifiedPaintModes) @@ -919,6 +1085,58 @@ void PainterOpenVG::drawPolygon(size_t numPoints, const FloatPoint* points, VGbi ASSERT_VG_NO_ERROR(); } +#ifdef OPENVG_VERSION_1_1 +void PainterOpenVG::drawText(VGFont vgFont, Vector<VGuint>& characters, VGfloat* adjustmentsX, VGfloat* adjustmentsY, const FloatPoint& point) +{ + ASSERT(m_state); + + VGbitfield paintModes = 0; + + if (m_state->textDrawingMode & cTextClip) + return; // unsupported for every port except CG at the time of writing + if (m_state->textDrawingMode & cTextFill && !m_state->fillDisabled()) + paintModes |= VG_FILL_PATH; + if (m_state->textDrawingMode & cTextStroke && !m_state->strokeDisabled()) + paintModes |= VG_STROKE_PATH; + + m_surface->makeCurrent(); + + FloatPoint effectivePoint = m_state->surfaceTransformation.mapPoint(point); + FloatPoint p = point; + AffineTransform* originalTransformation = 0; + + // In case the font isn't drawn at a pixel-exact baseline and we can easily + // fix that (which is the case for non-rotated affine transforms), let's + // align the starting point to the pixel boundary in order to prevent + // font rendering issues such as glyphs that appear off by a pixel. + // This causes us to have inconsistent spacing between baselines in a + // larger paragraph, but that seems to be the least of all evils. + if ((fmod(effectivePoint.x() + 0.01, 1.0) > 0.02 || fmod(effectivePoint.y() + 0.01, 1.0) > 0.02) + && isNonRotatedAffineTransformation(m_state->surfaceTransformation)) + { + originalTransformation = new AffineTransform(m_state->surfaceTransformation); + setTransformation(AffineTransform( + m_state->surfaceTransformation.a(), 0, + 0, m_state->surfaceTransformation.d(), + roundf(effectivePoint.x()), roundf(effectivePoint.y()))); + p = FloatPoint(); + } + + const VGfloat vgPoint[2] = { p.x(), p.y() }; + vgSetfv(VG_GLYPH_ORIGIN, 2, vgPoint); + ASSERT_VG_NO_ERROR(); + + vgDrawGlyphs(vgFont, characters.size(), characters.data(), + adjustmentsX, adjustmentsY, paintModes, VG_TRUE /* allow autohinting */); + ASSERT_VG_NO_ERROR(); + + if (originalTransformation) { + setTransformation(*originalTransformation); + delete originalTransformation; + } +} +#endif + void PainterOpenVG::save(PainterOpenVG::SaveMode saveMode) { ASSERT(m_state); @@ -930,15 +1148,18 @@ void PainterOpenVG::save(PainterOpenVG::SaveMode saveMode) m_surface->makeCurrent(SurfaceOpenVG::DontSaveOrApplyPainterState); if (saveMode == PainterOpenVG::CreateNewState) { + m_state->saveMaskIfNecessary(this); PlatformPainterState* state = new PlatformPainterState(*m_state); m_stateStack.append(state); m_state = m_stateStack.last(); - } else { // if (saveMode == PainterOpenVG::CreateNewStateWithPaintStateOnly) { + } else if (saveMode == PainterOpenVG::CreateNewStateWithPaintStateOnly) { + m_state->saveMaskIfNecessary(this); PlatformPainterState* state = new PlatformPainterState(); state->copyPaintState(m_state); m_stateStack.append(state); m_state = m_stateStack.last(); - } + } else // if (saveMode == PainterOpenVG::KeepCurrentState) + m_state->saveMaskIfNecessary(this); } void PainterOpenVG::restore() diff --git a/WebCore/platform/graphics/openvg/PainterOpenVG.h b/WebCore/platform/graphics/openvg/PainterOpenVG.h index 6936eee..30cdf31 100644 --- a/WebCore/platform/graphics/openvg/PainterOpenVG.h +++ b/WebCore/platform/graphics/openvg/PainterOpenVG.h @@ -26,17 +26,17 @@ #include <openvg.h> #include <wtf/Noncopyable.h> -#include <wtf/Platform.h> #include <wtf/Vector.h> namespace WebCore { +class AffineTransform; class FloatPoint; class FloatRect; class IntRect; class IntSize; +class Path; class SurfaceOpenVG; -class TransformationMatrix; struct PlatformPainterState; @@ -47,8 +47,13 @@ public: enum SaveMode { CreateNewState, + KeepCurrentState, CreateNewStateWithPaintStateOnly // internal usage only, do not use outside PainterOpenVG }; + enum ClipOperation { + IntersectClip = VG_INTERSECT_MASK, + SubtractClip = VG_SUBTRACT_MASK + }; PainterOpenVG(); PainterOpenVG(SurfaceOpenVG*); @@ -57,9 +62,11 @@ public: void begin(SurfaceOpenVG*); void end(); - TransformationMatrix transformationMatrix() const; - void setTransformationMatrix(const TransformationMatrix&); - void concatTransformationMatrix(const TransformationMatrix&); + AffineTransform transformation() const; + void setTransformation(const AffineTransform&); + void concatTransformation(const AffineTransform&); + + static void transformPath(VGPath dst, VGPath src, const AffineTransform&); CompositeOperator compositeOperation() const; void setCompositeOperation(CompositeOperator); @@ -82,6 +89,9 @@ public: Color fillColor() const; void setFillColor(const Color&); + int textDrawingMode() const; + void setTextDrawingMode(int mode); + bool antialiasingEnabled() const; void setAntialiasingEnabled(bool); @@ -91,12 +101,21 @@ public: void drawArc(const IntRect& ellipseBounds, int startAngle, int angleSpan, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH)); void drawEllipse(const IntRect& bounds, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH)); void drawPolygon(size_t numPoints, const FloatPoint* points, VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH)); +#ifdef OPENVG_VERSION_1_1 + void drawText(VGFont, Vector<VGuint>& characters, VGfloat* adjustmentsX, VGfloat* adjustmentsY, const FloatPoint&); +#endif void scale(const FloatSize& scaleFactors); void rotate(float radians); void translate(float dx, float dy); + void beginPath(); + void addPath(const Path&); + Path* currentPath() const; + void drawPath(VGbitfield paintModes = (VG_STROKE_PATH | VG_FILL_PATH), WindRule fillRule = RULE_NONZERO); + void intersectClipRect(const FloatRect&); + void clipPath(const Path&, PainterOpenVG::ClipOperation, WindRule clipRule = RULE_NONZERO); void save(PainterOpenVG::SaveMode saveMode = CreateNewState); void restore(); @@ -114,6 +133,7 @@ private: Vector<PlatformPainterState*> m_stateStack; PlatformPainterState* m_state; SurfaceOpenVG* m_surface; + Path* m_currentPath; }; } diff --git a/WebCore/platform/graphics/openvg/PathOpenVG.cpp b/WebCore/platform/graphics/openvg/PathOpenVG.cpp new file mode 100644 index 0000000..2c366ee --- /dev/null +++ b/WebCore/platform/graphics/openvg/PathOpenVG.cpp @@ -0,0 +1,502 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Path.h" + +#include "AffineTransform.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "PainterOpenVG.h" +#include "PlatformPathOpenVG.h" +#include "PlatformString.h" +#include "StrokeStyleApplier.h" +#include "VGUtils.h" + +#include <openvg.h> +#include <wtf/MathExtras.h> + +#define WEBKIT_VG_PATH_CAPABILITIES VG_PATH_CAPABILITY_ALL + +#define FUZZY_COMPARE(number, reference, delta) \ + (number >= (reference - delta) && number <= (reference + delta)) + +namespace WebCore { + +PlatformPathOpenVG::PlatformPathOpenVG() + : SharedResourceOpenVG() +{ + createPath(); +} + +PlatformPathOpenVG::PlatformPathOpenVG(const PlatformPathOpenVG& other) + : SharedResourceOpenVG() + , m_currentPoint(other.m_currentPoint) + , m_subpathStartPoint(other.m_subpathStartPoint) +{ + createPath(); + // makeCompatibleContextCurrent() is called by createPath(), so not necessary here. + vgAppendPath(m_vgPath, other.m_vgPath); + ASSERT_VG_NO_ERROR(); +} + +PlatformPathOpenVG& PlatformPathOpenVG::operator=(const PlatformPathOpenVG& other) +{ + if (&other != this) { + clear(); + // makeCompatibleContextCurrent() is called by clear(), so not necessary here. + vgAppendPath(m_vgPath, other.m_vgPath); + ASSERT_VG_NO_ERROR(); + } + return *this; +} + +PlatformPathOpenVG::~PlatformPathOpenVG() +{ + makeCompatibleContextCurrent(); + + vgDestroyPath(m_vgPath); + ASSERT_VG_NO_ERROR(); +} + +void PlatformPathOpenVG::clear() +{ + makeCompatibleContextCurrent(); + + vgClearPath(m_vgPath, WEBKIT_VG_PATH_CAPABILITIES); + ASSERT_VG_NO_ERROR(); + + m_subpathStartPoint.setX(0); + m_subpathStartPoint.setY(0); + m_currentPoint = m_subpathStartPoint; +} + +void PlatformPathOpenVG::createPath() +{ + makeSharedContextCurrent(); + + m_vgPath = vgCreatePath( + VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, + 1.0 /* scale */, 0.0 /* bias */, + 0 /* expected number of segments */, + 0 /* expected number of total coordinates */, + WEBKIT_VG_PATH_CAPABILITIES); + ASSERT_VG_NO_ERROR(); +} + + +Path::Path() +{ + m_path = new PlatformPathOpenVG(); +} + +Path::~Path() +{ + delete m_path; +} + +Path::Path(const Path& other) +{ + m_path = new PlatformPathOpenVG(*(other.m_path)); +} + +Path& Path::operator=(const Path& other) +{ + *m_path = *(other.m_path); + return *this; +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + notImplemented(); + + // OpenVG has no path-contains function, so for now we approximate by + // using the bounding rect of the path. + return boundingRect().contains(point); +} + +bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const +{ + notImplemented(); + + // OpenVG has no path-contains function, so for now we approximate by + // using the stroke bounding rect of the path. + return (const_cast<Path*>(this))->strokeBoundingRect().contains(point); +} + +void Path::translate(const FloatSize& size) +{ + AffineTransform transformation; + transformation.translate(size.width(), size.height()); + transform(transformation); +} + +FloatRect Path::boundingRect() const +{ + VGfloat minX; + VGfloat minY; + VGfloat width; + VGfloat height; + + m_path->makeCompatibleContextCurrent(); + vgPathBounds(m_path->vgPath(), &minX, &minY, &width, &height); + ASSERT_VG_NO_ERROR(); + + return FloatRect(FloatPoint(minX, minY), FloatSize(width, height)); +} + +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + notImplemented(); + + // vgPathBounds() ignores stroke parameters, and we don't currently have + // an approximation that takes stroke parameters into account. + return boundingRect(); +} + +void Path::moveTo(const FloatPoint& point) +{ + static const VGubyte pathSegments[] = { VG_MOVE_TO_ABS }; + const VGfloat pathData[] = { point.x(), point.y() }; + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); + + m_path->m_currentPoint = m_path->m_subpathStartPoint = point; +} + +void Path::addLineTo(const FloatPoint& point) +{ + static const VGubyte pathSegments[] = { VG_LINE_TO_ABS }; + const VGfloat pathData[] = { point.x(), point.y() }; + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); + + m_path->m_currentPoint = point; +} + +void Path::addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& endPoint) +{ + static const VGubyte pathSegments[] = { VG_QUAD_TO_ABS }; + const VGfloat pathData[] = { controlPoint.x(), controlPoint.y(), endPoint.x(), endPoint.y() }; + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); + + m_path->m_currentPoint = endPoint; +} + +void Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& endPoint) +{ + static const VGubyte pathSegments[] = { VG_CUBIC_TO_ABS }; + const VGfloat pathData[] = { controlPoint1.x(), controlPoint1.y(), controlPoint2.x(), controlPoint2.y(), endPoint.x(), endPoint.y() }; + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); + + m_path->m_currentPoint = endPoint; +} + +void Path::addArcTo(const FloatPoint& point1, const FloatPoint& point2, float radius) +{ + // See http://philip.html5.org/tests/canvas/suite/tests/spec.html#arcto. + + const FloatPoint& point0 = m_path->m_currentPoint; + if (!radius || point0 == point1 || point1 == point2) { + addLineTo(point1); + return; + } + + FloatSize v01 = point0 - point1; + FloatSize v21 = point2 - point1; + + // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A) + double cross = v01.width() * v21.height() - v01.height() * v21.width(); + + if (fabs(cross) < 1E-10) { + // on one line + addLineTo(point1); + return; + } + + double d01 = hypot(v01.width(), v01.height()); + double d21 = hypot(v21.width(), v21.height()); + double angle = (piDouble - fabs(asin(cross / (d01 * d21)))) * 0.5; + double span = radius * tan(angle); + double rate = span / d01; + FloatPoint startPoint = FloatPoint(point1.x() + v01.width() * rate, + point1.y() + v01.height() * rate); + rate = span / d21; + FloatPoint endPoint = FloatPoint(point1.x() + v21.width() * rate, + point1.y() + v21.height() * rate); + + // Fa: large arc flag, makes the difference between SCWARC_TO and LCWARC_TO + // respectively SCCWARC_TO and LCCWARC_TO arcs. We always use small + // arcs for arcTo(), as the arc is defined as the "shortest arc" of the + // circle specified in HTML 5. + + // Fs: sweep flag, specifying whether the arc is drawn in increasing (true) + // or decreasing (0) direction. + const bool anticlockwise = cross < 0; + + // Translate the large arc and sweep flags into an OpenVG segment command. + const VGubyte segmentCommand = anticlockwise ? VG_SCCWARC_TO_ABS : VG_SCWARC_TO_ABS; + + const VGubyte pathSegments[] = { + VG_LINE_TO_ABS, + segmentCommand + }; + const VGfloat pathData[] = { + startPoint.x(), startPoint.y(), + radius, radius, 0, endPoint.x(), endPoint.y() + }; + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 2, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); + + m_path->m_currentPoint = endPoint; +} + +void Path::closeSubpath() +{ + static const VGubyte pathSegments[] = { VG_CLOSE_PATH }; + // pathData must not be 0, but certain compilers also don't create + // zero-size arrays. So let's use a random aligned value (sizeof(VGfloat)), + // it won't be accessed anyways as VG_CLOSE_PATH doesn't take coordinates. + static const VGfloat* pathData = reinterpret_cast<VGfloat*>(sizeof(VGfloat)); + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); + + m_path->m_currentPoint = m_path->m_subpathStartPoint; +} + +void Path::addArc(const FloatPoint& center, float radius, float startAngle, float endAngle, bool anticlockwise) +{ + // The OpenVG spec says nothing about inf as radius or start/end angle. + // WebKit seems to pass those (e.g. https://bugs.webkit.org/show_bug.cgi?id=16449), + // so abort instead of risking undefined behavior. + if (!isfinite(radius) || !isfinite(startAngle) || !isfinite(endAngle)) + return; + + // For some reason, the HTML 5 spec defines the angle as going clockwise + // from the positive X axis instead of going standard anticlockwise. + // So let's make it a proper angle in order to keep sanity. + startAngle = fmod((2.0 * piDouble) - startAngle, 2.0 * piDouble); + endAngle = fmod((2.0 * piDouble) - endAngle, 2.0 * piDouble); + + // Make it so that endAngle > startAngle. fmod() above takes care of + // keeping the difference below 360 degrees. + if (endAngle <= startAngle) + endAngle += 2.0 * piDouble; + + const VGfloat angleDelta = anticlockwise + ? (endAngle - startAngle) + : (startAngle - endAngle + (2.0 * piDouble)); + + // OpenVG uses endpoint parameterization while this method receives its + // values in center parameterization. It lacks an ellipse rotation + // parameter so we use 0 for that, and also the radius is only a single + // value which makes for rh == rv. In order to convert from endpoint to + // center parameterization, we use the formulas from the OpenVG/SVG specs: + + // (x,y) = (cos rot, -sin rot; sin rot, -cos rot) * (rh * cos angle, rv * sin angle) + (center.x, center.y) + // rot is 0, which simplifies this a bit: + // (x,y) = (1, 0; 0, -1) * (rh * cos angle, rv * sin angle) + (center.x, center.y) + // = (1 * rh * cos angle + 0 * rv * sin angle, 0 * rh * cos angle + -1 * rv * sin angle) + (center.x, center.y) + // = (rh * cos angle, -rv * sin angle) + (center.x, center.y) + // (Set angle = {startAngle, endAngle} to retrieve the respective endpoints.) + + const VGfloat startX = radius * cos(startAngle) + center.x(); + const VGfloat startY = -radius * sin(startAngle) + center.y(); + const VGfloat endX = radius * cos(endAngle) + center.x(); + const VGfloat endY = -radius * sin(endAngle) + center.y(); + + // Fa: large arc flag, makes the difference between SCWARC_TO and LCWARC_TO + // respectively SCCWARC_TO and LCCWARC_TO arcs. + const bool largeArc = (angleDelta > piDouble); + + // Fs: sweep flag, specifying whether the arc is drawn in increasing (true) + // or decreasing (0) direction. No need to calculate this value, as it + // we already get it passed as a parameter (Fs == !anticlockwise). + + // Translate the large arc and sweep flags into an OpenVG segment command. + // As OpenVG thinks of everything upside down, we need to reverse the + // anticlockwise parameter in order to get the specified rotation. + const VGubyte segmentCommand = !anticlockwise + ? (largeArc ? VG_LCCWARC_TO_ABS : VG_SCCWARC_TO_ABS) + : (largeArc ? VG_LCWARC_TO_ABS : VG_SCWARC_TO_ABS); + + // So now, we've got all the parameters in endpoint parameterization format + // as OpenVG requires it. Which means we can just pass it like this. + const VGubyte pathSegments[] = { + hasCurrentPoint() ? VG_LINE_TO_ABS : VG_MOVE_TO_ABS, + segmentCommand + }; + const VGfloat pathData[] = { + startX, startY, + radius, radius, 0, endX, endY + }; + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 2, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); + + m_path->m_currentPoint.setX(endX); + m_path->m_currentPoint.setY(endY); +} + +void Path::addRect(const FloatRect& rect) +{ + static const VGubyte pathSegments[] = { + VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_VLINE_TO_REL, + VG_HLINE_TO_REL, + VG_CLOSE_PATH + }; + const VGfloat pathData[] = { + rect.x(), rect.y(), + rect.width(), + rect.height(), + -rect.width() + }; + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 5, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); + + m_path->m_currentPoint = m_path->m_subpathStartPoint = rect.location(); +} + +void Path::addEllipse(const FloatRect& rect) +{ + static const VGubyte pathSegments[] = { + VG_MOVE_TO_ABS, + VG_SCCWARC_TO_REL, + VG_SCCWARC_TO_REL, + VG_CLOSE_PATH + }; + const VGfloat pathData[] = { + rect.x() + rect.width() / 2.0, rect.y(), + rect.width() / 2.0, rect.height() / 2.0, 0, 0, rect.height(), + rect.width() / 2.0, rect.height() / 2.0, 0, 0, -rect.height() + }; + + m_path->makeCompatibleContextCurrent(); + vgAppendPathData(m_path->vgPath(), 4, pathSegments, pathData); + ASSERT_VG_NO_ERROR(); +} + +void Path::clear() +{ + m_path->clear(); +} + +bool Path::isEmpty() const +{ + m_path->makeCompatibleContextCurrent(); + return !vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS); +} + +bool Path::hasCurrentPoint() const +{ + m_path->makeCompatibleContextCurrent(); + return vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS) > 0; +} + +String Path::debugString() const +{ + String debugString = ""; + + // OpenVG provides no means to retrieve path segment information. + // This is a bit unfortunate, we might need to store the segments in + // memory if we want to implement this function properly. + notImplemented(); + + return debugString; +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + // OpenVG provides no means to retrieve path segment information. + // This is *very* unfortunate, we might need to store the segments in + // memory if we want to implement this function properly. + // See http://www.khronos.org/message_boards/viewtopic.php?f=6&t=1887 + notImplemented(); +} + +void Path::transform(const AffineTransform& transformation) +{ + PlatformPathOpenVG* dst = new PlatformPathOpenVG(); + // dst->makeCompatibleContextCurrent() is called by the platform path + // constructor, therefore not necessary to call it again here. + PainterOpenVG::transformPath(dst->vgPath(), m_path->vgPath(), transformation); + delete m_path; + m_path = dst; + + m_path->m_currentPoint = transform.mapPoint(m_path->m_currentPoint); + m_path->m_subpathStartPoint = transform.mapPoint(m_path->m_subpathStartPoint); +} + + +// Path::length(), Path::pointAtLength() and Path::normalAngleAtLength() are +// reimplemented here instead of in Path.cpp, because OpenVG has its own +// functions and Path::apply() doesn't really work as long as we rely on VGPath +// as primary path storage. + +float Path::length() +{ + m_path->makeCompatibleContextCurrent(); + VGfloat length = vgPathLength(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS)); + ASSERT_VG_NO_ERROR(); + return length; +} + +FloatPoint Path::pointAtLength(float length, bool& ok) +{ + VGfloat x = 0, y = 0; + m_path->makeCompatibleContextCurrent(); + + vgPointAlongPath(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS), + length, &x, &y, 0, 0); + ok = (vgGetError() == VG_NO_ERROR); + return FloatPoint(x, y); +} + +float Path::normalAngleAtLength(float length, bool& ok) +{ + VGfloat tangentX, tangentY; + m_path->makeCompatibleContextCurrent(); + + vgPointAlongPath(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS), + length, 0, 0, &tangentX, &tangentY); + ok = (vgGetError() == VG_NO_ERROR); + return atan2f(tangentY, tangentX) * 180.0 / piFloat; // convert to degrees +} + +} diff --git a/WebCore/platform/graphics/openvg/PlatformPathOpenVG.h b/WebCore/platform/graphics/openvg/PlatformPathOpenVG.h new file mode 100644 index 0000000..286da53 --- /dev/null +++ b/WebCore/platform/graphics/openvg/PlatformPathOpenVG.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PlatformPathOpenVG_h +#define PlatformPathOpenVG_h + +#include "FloatPoint.h" +#include "SharedResourceOpenVG.h" + +#include <openvg.h> + +namespace WebCore { + +class PlatformPathOpenVG : public SharedResourceOpenVG { +public: + PlatformPathOpenVG(); + PlatformPathOpenVG(const PlatformPathOpenVG&); + ~PlatformPathOpenVG(); + + PlatformPathOpenVG& operator=(const PlatformPathOpenVG&); + + VGPath vgPath() { return m_vgPath; } + void clear(); + +public: + FloatPoint m_currentPoint; + FloatPoint m_subpathStartPoint; + +private: + void createPath(); + + VGPath m_vgPath; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/openvg/SharedResourceOpenVG.cpp b/WebCore/platform/graphics/openvg/SharedResourceOpenVG.cpp new file mode 100644 index 0000000..a843db5 --- /dev/null +++ b/WebCore/platform/graphics/openvg/SharedResourceOpenVG.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) Research In Motion Limited 2009. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "SharedResourceOpenVG.h" + +#include "SurfaceOpenVG.h" + +#if PLATFORM(EGL) +#include "EGLDisplayOpenVG.h" +#endif + +namespace WebCore { + +void SharedResourceOpenVG::makeSharedContextCurrent() +{ +#if PLATFORM(EGL) + EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); +#endif +} + +void SharedResourceOpenVG::makeCompatibleContextCurrent() +{ +#if PLATFORM(EGL) + EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCompatibleCurrent(); +#endif +} + +} diff --git a/WebCore/platform/graphics/openvg/SharedResourceOpenVG.h b/WebCore/platform/graphics/openvg/SharedResourceOpenVG.h new file mode 100644 index 0000000..436ae90 --- /dev/null +++ b/WebCore/platform/graphics/openvg/SharedResourceOpenVG.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) Research In Motion Limited 2009. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SharedResourceOpenVG_h +#define SharedResourceOpenVG_h + +namespace WebCore { + +class SharedResourceOpenVG { +public: + void makeSharedContextCurrent(); + void makeCompatibleContextCurrent(); +}; + +} + +#endif diff --git a/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp b/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp index 9539f2c..6700c6f 100644 --- a/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp +++ b/WebCore/platform/graphics/openvg/SurfaceOpenVG.cpp @@ -64,6 +64,25 @@ SurfaceOpenVG::SurfaceOpenVG(const IntSize& size, const EGLDisplay& display, EGL EGLDisplayOpenVG::registerPlatformSurface(this); } +SurfaceOpenVG::SurfaceOpenVG(EGLClientBuffer buffer, EGLenum bufferType, const EGLDisplay& display, EGLConfig* confPtr, EGLint* errorCode) + : m_activePainter(0) + , m_eglDisplay(display) + , m_eglSurface(EGL_NO_SURFACE) + , m_eglContext(EGL_NO_CONTEXT) +{ + ASSERT(m_eglDisplay != EGL_NO_DISPLAY); + + EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay); + EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultPbufferConfig(); + m_eglSurface = displayManager->createPbufferFromClientBuffer(buffer, bufferType, config, errorCode); + + if (m_eglSurface == EGL_NO_SURFACE) + return; + + m_eglContext = displayManager->contextForSurface(m_eglSurface); + EGLDisplayOpenVG::registerPlatformSurface(this); +} + SurfaceOpenVG::SurfaceOpenVG(EGLNativeWindowType window, const EGLDisplay& display, EGLConfig* confPtr) : m_activePainter(0) , m_eglDisplay(display) @@ -173,6 +192,11 @@ void SurfaceOpenVG::makeCurrent(MakeCurrentMode mode) ASSERT_EGL_NO_ERROR(); if (currentSurface != m_eglSurface) { + // Save other context before switching over. + if (s_currentPainter && mode != DontSaveOrApplyPainterState + && s_currentPainter->surface()->m_eglSurface == currentSurface) + s_currentPainter->save(PainterOpenVG::KeepCurrentState); + eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); ASSERT_EGL_NO_ERROR(); s_currentPainter = 0; @@ -202,6 +226,10 @@ void SurfaceOpenVG::makeCompatibleCurrent() s_currentPainter = m_activePainter; } } else if (!EGLDisplayOpenVG::forDisplay(m_eglDisplay)->surfacesCompatible(currentSurface, m_eglSurface)) { + // Save other context before switching over. + if (s_currentPainter && s_currentPainter->surface()->m_eglSurface == currentSurface) + s_currentPainter->save(PainterOpenVG::KeepCurrentState); + eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); ASSERT_EGL_NO_ERROR(); s_currentPainter = 0; diff --git a/WebCore/platform/graphics/openvg/SurfaceOpenVG.h b/WebCore/platform/graphics/openvg/SurfaceOpenVG.h index dc288dd..46d1646 100644 --- a/WebCore/platform/graphics/openvg/SurfaceOpenVG.h +++ b/WebCore/platform/graphics/openvg/SurfaceOpenVG.h @@ -25,7 +25,6 @@ #endif #include <wtf/Noncopyable.h> -#include <wtf/Platform.h> namespace WebCore { @@ -48,6 +47,7 @@ public: enum MakeCurrentMode { ApplyPainterStateOnSurfaceSwitch, DontApplyPainterState, + DontSaveOrApplyPainterState }; static SurfaceOpenVG* currentSurface(); @@ -68,6 +68,26 @@ public: SurfaceOpenVG(const IntSize& size, const EGLDisplay& display, EGLConfig* config = 0, EGLint* errorCode = 0); /** + * Create a new EGL pbuffer surface that will be bound to the given + * client buffer (read: VGImage), with the specified config on the + * given display. If config is not specified, the display's default + * pbuffer config is used. + * + * After the surface is created, you will only be able to access the + * client buffer image if the surface is not current. The recommended way + * to ensure this is to call surface->sharedSurface()->makeCurrent() if you + * simply want to access the image's pixel contents, or if you intend to + * draw the image directly, making the draw target surface current. + * + * This constructor will trigger an assertion if creation of the surface + * fails, unless you pledge to manually process the error code by passing + * a non-zero pointer as errorCode parameter. The error code returned by + * eglGetError() will be written to that variable. + */ + SurfaceOpenVG(EGLClientBuffer buffer, EGLenum bufferType, + const EGLDisplay& display, EGLConfig* config = 0, EGLint* errorCode = 0); + + /** * Create a new EGL window surface with the specified native window handle * and config on the given display. If config is not specified, the * display's default window config is used. diff --git a/WebCore/platform/graphics/openvg/VGUtils.cpp b/WebCore/platform/graphics/openvg/VGUtils.cpp index 72ba5b2..ce9bcd2 100644 --- a/WebCore/platform/graphics/openvg/VGUtils.cpp +++ b/WebCore/platform/graphics/openvg/VGUtils.cpp @@ -20,6 +20,7 @@ #include "config.h" #include "VGUtils.h" +#include "AffineTransform.h" #include "FloatRect.h" #include "TransformationMatrix.h" @@ -38,6 +39,19 @@ VGMatrix::VGMatrix(const VGfloat data[9]) m_data[8] = data[8]; } +VGMatrix::VGMatrix(const AffineTransform& transformation) +{ + m_data[0] = transformation.a(); + m_data[1] = transformation.b(); + m_data[2] = 0; + m_data[3] = transformation.c(); + m_data[4] = transformation.d(); + m_data[5] = 0; + m_data[6] = transformation.e(); + m_data[7] = transformation.f(); + m_data[8] = 1; +} + VGMatrix::VGMatrix(const TransformationMatrix& matrix) { m_data[0] = matrix.m11(); @@ -51,21 +65,30 @@ VGMatrix::VGMatrix(const TransformationMatrix& matrix) m_data[8] = matrix.m44(); } +VGMatrix::operator AffineTransform() const +{ + AffineTransform transformation( + m_data[0], m_data[1], + m_data[3], m_data[4], + m_data[6], m_data[7]); + return transformation; +} + VGMatrix::operator TransformationMatrix() const { - TransformationMatrix matrix; - matrix.setM11(m_data[0]); - matrix.setM12(m_data[1]); - matrix.setM14(m_data[2]); - matrix.setM21(m_data[3]); - matrix.setM22(m_data[4]); - matrix.setM24(m_data[5]); - matrix.setM41(m_data[6]); - matrix.setM42(m_data[7]); - matrix.setM44(m_data[8]); + TransformationMatrix matrix( + m_data[0], m_data[1], 0, m_data[2], + m_data[3], m_data[4], 0, m_data[5], + 0, 0, 1, 0, + m_data[6], m_data[7], 0, m_data[8]); return matrix; } +AffineTransform::operator VGMatrix() const +{ + return VGMatrix(*this); +} + TransformationMatrix::operator VGMatrix() const { return VGMatrix(*this); diff --git a/WebCore/platform/graphics/openvg/VGUtils.h b/WebCore/platform/graphics/openvg/VGUtils.h index 083c15a..3a290cb 100644 --- a/WebCore/platform/graphics/openvg/VGUtils.h +++ b/WebCore/platform/graphics/openvg/VGUtils.h @@ -59,14 +59,17 @@ static inline const char* toVGErrorConstant(VGErrorCode error) namespace WebCore { +class AffineTransform; class FloatRect; class TransformationMatrix; class VGMatrix { public: VGMatrix(const VGfloat data[9]); + VGMatrix(const AffineTransform&); VGMatrix(const TransformationMatrix&); const VGfloat* toVGfloat() const { return m_data; } + operator AffineTransform() const; operator TransformationMatrix() const; private: VGfloat m_data[9]; diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp index 0a1075f..0565deb 100644 --- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp +++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -58,6 +58,9 @@ FontPlatformData::FontPlatformData(const FontDescription& description, const Ato font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); const bool smallCaps = description.smallCaps(); font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + font.setStyleStrategy(QFont::ForceIntegerMetrics); +#endif m_data->bold = font.bold(); m_data->size = font.pointSizeF(); diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index 9ff7c1a..974c179 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - Copyright (C) 2008 Holger Hans Peter Freyther + Copyright (C) 2008, 2010 Holger Hans Peter Freyther Copyright (C) 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or @@ -134,7 +134,7 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float clip.adjust(dx1, dx2, dy1, dy2); } p->save(); - p->setClipRect(clip.toRect()); + p->setClipRect(clip.toRect(), Qt::IntersectClip); QPointF pt(point.x(), point.y() - ascent); if (hasShadow) { p->save(); @@ -169,17 +169,24 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float p->drawText(pt, string, flags, run.padding()); } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const { if (!run.length()) return 0; + if (run.length() == 1 && treatAsSpace(run[0])) + return QFontMetrics(font()).width(run[0]) - m_wordSpacing + run.padding(); + String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) + int w = int(line.horizontalAdvance()); +#else int w = int(line.naturalTextWidth()); +#endif // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; @@ -216,8 +223,10 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& QFont Font::font() const { QFont f = primaryFont()->getQtFont(); - f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing); - f.setWordSpacing(m_wordSpacing); + if (m_letterSpacing != 0) + f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing); + if (m_wordSpacing != 0) + f.setWordSpacing(m_wordSpacing); return f; } diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp index 9b9acc2..8b9e2d7 100644 --- a/WebCore/platform/graphics/qt/GradientQt.cpp +++ b/WebCore/platform/graphics/qt/GradientQt.cpp @@ -51,6 +51,8 @@ QGradient* Gradient::platformGradient() else m_gradient = new QLinearGradient(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y()); + sortStopsIfNecessary(); + QColor stopColor; Vector<ColorStop>::iterator stopIterator = m_stops.begin(); qreal lastStop(0.0); @@ -64,9 +66,17 @@ QGradient* Gradient::platformGradient() if (m_radial && m_r0) lastStop = m_r0 / m_r1 + lastStop * (1.0f - m_r0 / m_r1); m_gradient->setColorAt(lastStop, stopColor); + // Keep the lastStop as orginal value, since the following stopColor depend it + lastStop = stopIterator->stop; ++stopIterator; } + if (m_stops.isEmpty()) { + // The behavior of QGradient with no stops is defined differently from HTML5 spec, + // where the latter requires the gradient to be transparent black. + m_gradient->setColorAt(0.0, QColor(0, 0, 0, 0)); + } + switch (m_spreadMethod) { case SpreadMethodPad: m_gradient->setSpread(QGradient::PadSpread); diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp new file mode 100644 index 0000000..b0dd289 --- /dev/null +++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -0,0 +1,1651 @@ +/* + Copyright (C) 2010 Tieto Corporation. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "config.h" + +#include "GraphicsContext3D.h" + +#include "CanvasObject.h" +#include "GraphicsContext.h" +#include "HTMLCanvasElement.h" +#include "HostWindow.h" +#include "ImageBuffer.h" +#include "NotImplemented.h" +#include "QWebPageClient.h" +#include "WebGLActiveInfo.h" +#include "WebGLArray.h" +#include "WebGLBuffer.h" +#include "WebGLFloatArray.h" +#include "WebGLFramebuffer.h" +#include "WebGLIntArray.h" +#include "WebGLProgram.h" +#include "WebGLRenderbuffer.h" +#include "WebGLRenderingContext.h" +#include "WebGLShader.h" +#include "WebGLTexture.h" +#include "WebGLUnsignedByteArray.h" +#include <QAbstractScrollArea> +#include <wtf/UnusedParam.h> +#include <wtf/text/CString.h> + +#if ENABLE(3D_CANVAS) + +namespace WebCore { + +#if !defined(GLchar) +typedef char GLchar; +#endif + +#if !defined(APIENTRY) +#define APIENTRY +#endif + +typedef ptrdiff_t GLsizeiptrType; +typedef ptrdiff_t GLintptrType; + +typedef void (APIENTRY* glActiveTextureType) (GLenum); +typedef void (APIENTRY* glAttachShaderType) (GLuint, GLuint); +typedef void (APIENTRY* glBindAttribLocationType) (GLuint, GLuint, const char*); +typedef void (APIENTRY* glBindBufferType) (GLenum, GLuint); +typedef void (APIENTRY* glBindFramebufferType) (GLenum, GLuint); +typedef void (APIENTRY* glBindRenderbufferType) (GLenum, GLuint); +typedef void (APIENTRY* glBlendColorType) (GLclampf, GLclampf, GLclampf, GLclampf); +typedef void (APIENTRY* glBlendEquationType) (GLenum); +typedef void (APIENTRY* glBlendEquationSeparateType)(GLenum, GLenum); +typedef void (APIENTRY* glBlendFuncSeparateType)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (APIENTRY* glBufferDataType) (GLenum, GLsizeiptrType, const GLvoid*, GLenum); +typedef void (APIENTRY* glBufferSubDataType) (GLenum, GLintptrType, GLsizeiptrType, const GLvoid*); +typedef GLenum (APIENTRY* glCheckFramebufferStatusType) (GLenum); +typedef void (APIENTRY* glCompileShaderType) (GLuint); +typedef GLuint (APIENTRY* glCreateProgramType) (); +typedef GLuint (APIENTRY* glCreateShaderType) (GLenum); +typedef void (APIENTRY* glDeleteBuffersType) (GLsizei, const GLuint*); +typedef void (APIENTRY* glDeleteFramebuffersType) (GLsizei n, const GLuint*); +typedef void (APIENTRY* glDeleteProgramType) (GLuint); +typedef void (APIENTRY* glDeleteRenderbuffersType) (GLsizei n, const GLuint*); +typedef void (APIENTRY* glDeleteShaderType) (GLuint); +typedef void (APIENTRY* glDetachShaderType) (GLuint, GLuint); +typedef void (APIENTRY* glDisableVertexAttribArrayType) (GLuint); +typedef void (APIENTRY* glEnableVertexAttribArrayType) (GLuint); +typedef void (APIENTRY* glFramebufferRenderbufferType) (GLenum, GLenum, GLenum, GLuint); +typedef void (APIENTRY* glFramebufferTexture2DType) (GLenum, GLenum, GLenum, GLuint, GLint); +typedef void (APIENTRY* glGenBuffersType) (GLsizei, GLuint*); +typedef void (APIENTRY* glGenerateMipmapType) (GLenum target); +typedef void (APIENTRY* glGenFramebuffersType) (GLsizei, GLuint*); +typedef void (APIENTRY* glGenRenderbuffersType) (GLsizei, GLuint*); +typedef void (APIENTRY* glGetActiveAttribType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +typedef void (APIENTRY* glGetActiveUniformType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +typedef GLint (APIENTRY* glGetAttribLocationType) (GLuint, const char*); +typedef void (APIENTRY* glGetBufferParameterivType) (GLenum, GLenum, GLint*); +typedef void (APIENTRY* glGetFramebufferAttachmentParameterivType) (GLenum, GLenum, GLenum, GLint* params); +typedef void (APIENTRY* glGetProgramInfoLogType) (GLuint, GLsizei, GLsizei*, char*); +typedef void (APIENTRY* glGetProgramivType) (GLuint, GLenum, GLint*); +typedef void (APIENTRY* glGetRenderbufferParameterivType) (GLenum, GLenum, GLint*); +typedef void (APIENTRY* glGetShaderInfoLogType) (GLuint, GLsizei, GLsizei*, char*); +typedef void (APIENTRY* glGetShaderivType) (GLuint, GLenum, GLint*); +typedef void (APIENTRY* glGetShaderSourceType) (GLuint, GLsizei, GLsizei*, char*); +typedef GLint (APIENTRY* glGetUniformLocationType) (GLuint, const char*); +typedef void (APIENTRY* glGetUniformfvType) (GLuint, GLint, GLfloat*); +typedef void (APIENTRY* glGetUniformivType) (GLuint, GLint, GLint*); +typedef void (APIENTRY* glGetVertexAttribfvType) (GLuint, GLenum, GLfloat*); +typedef void (APIENTRY* glGetVertexAttribivType) (GLuint, GLenum, GLint*); +typedef void (APIENTRY* glGetVertexAttribPointervType) (GLuint, GLenum, GLvoid**); +typedef GLboolean (APIENTRY* glIsBufferType) (GLuint); +typedef GLboolean (APIENTRY* glIsFramebufferType) (GLuint); +typedef GLboolean (APIENTRY* glIsProgramType) (GLuint); +typedef GLboolean (APIENTRY* glIsRenderbufferType) (GLuint); +typedef GLboolean (APIENTRY* glIsShaderType) (GLuint); +typedef void (APIENTRY* glLinkProgramType) (GLuint); +typedef void (APIENTRY* glRenderbufferStorageType) (GLenum, GLenum, GLsizei, GLsizei); +typedef void (APIENTRY* glSampleCoverageType) (GLclampf, GLboolean); +typedef void (APIENTRY* glShaderSourceType) (GLuint, GLsizei, const char**, const GLint*); +typedef void (APIENTRY* glStencilFuncSeparateType) (GLenum, GLenum, GLint, GLuint); +typedef void (APIENTRY* glStencilMaskSeparateType) (GLenum, GLuint); +typedef void (APIENTRY* glStencilOpSeparateType) (GLenum, GLenum, GLenum, GLenum); +typedef void (APIENTRY* glUniform1fType) (GLint, GLfloat); +typedef void (APIENTRY* glUniform1fvType) (GLint, GLsizei, const GLfloat*); +typedef void (APIENTRY* glUniform1iType) (GLint, GLint); +typedef void (APIENTRY* glUniform1ivType) (GLint, GLsizei, const GLint*); +typedef void (APIENTRY* glUniform2fType) (GLint, GLfloat, GLfloat); +typedef void (APIENTRY* glUniform2fvType) (GLint, GLsizei, const GLfloat*); +typedef void (APIENTRY* glUniform2iType) (GLint, GLint, GLint); +typedef void (APIENTRY* glUniform2ivType) (GLint, GLsizei, const GLint*); +typedef void (APIENTRY* glUniform3fType) (GLint, GLfloat, GLfloat, GLfloat); +typedef void (APIENTRY* glUniform3fvType) (GLint, GLsizei, const GLfloat*); +typedef void (APIENTRY* glUniform3iType) (GLint, GLint, GLint, GLint); +typedef void (APIENTRY* glUniform3ivType) (GLint, GLsizei, const GLint*); +typedef void (APIENTRY* glUniform4fType) (GLint, GLfloat, GLfloat, GLfloat, GLfloat); +typedef void (APIENTRY* glUniform4fvType) (GLint, GLsizei, const GLfloat*); +typedef void (APIENTRY* glUniform4iType) (GLint, GLint, GLint, GLint, GLint); +typedef void (APIENTRY* glUniform4ivType) (GLint, GLsizei, const GLint*); +typedef void (APIENTRY* glUniformMatrix2fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (APIENTRY* glUniformMatrix3fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (APIENTRY* glUniformMatrix4fvType) (GLint, GLsizei, GLboolean, const GLfloat*); +typedef void (APIENTRY* glUseProgramType) (GLuint); +typedef void (APIENTRY* glValidateProgramType) (GLuint); +typedef void (APIENTRY* glVertexAttrib1fType) (GLuint, const GLfloat); +typedef void (APIENTRY* glVertexAttrib1fvType) (GLuint, const GLfloat*); +typedef void (APIENTRY* glVertexAttrib2fType) (GLuint, const GLfloat, const GLfloat); +typedef void (APIENTRY* glVertexAttrib2fvType) (GLuint, const GLfloat*); +typedef void (APIENTRY* glVertexAttrib3fType) (GLuint, const GLfloat, const GLfloat, const GLfloat); +typedef void (APIENTRY* glVertexAttrib3fvType) (GLuint, const GLfloat*); +typedef void (APIENTRY* glVertexAttrib4fType) (GLuint, const GLfloat, const GLfloat, const GLfloat, const GLfloat); +typedef void (APIENTRY* glVertexAttrib4fvType) (GLuint, const GLfloat*); +typedef void (APIENTRY* glVertexAttribPointerType) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*); + +class GraphicsContext3DInternal { +public: + GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow); + ~GraphicsContext3DInternal(); + + bool isContextValid() { return m_contextValid; } + + + + glActiveTextureType activeTexture; + glAttachShaderType attachShader; + glBindAttribLocationType bindAttribLocation; + glBindBufferType bindBuffer; + glBindFramebufferType bindFramebuffer; + glBindRenderbufferType bindRenderbuffer; + glBlendColorType blendColor; + glBlendEquationType blendEquation; + glBlendEquationSeparateType blendEquationSeparate; + glBlendFuncSeparateType blendFuncSeparate; + glBufferDataType bufferData; + glBufferSubDataType bufferSubData; + glCheckFramebufferStatusType checkFramebufferStatus; + glCompileShaderType compileShader; + glCreateProgramType createProgram; + glCreateShaderType createShader; + glDeleteBuffersType deleteBuffers; + glDeleteFramebuffersType deleteFramebuffers; + glDeleteProgramType deleteProgram; + glDeleteRenderbuffersType deleteRenderbuffers; + glDeleteShaderType deleteShader; + glDetachShaderType detachShader; + glDisableVertexAttribArrayType disableVertexAttribArray; + glEnableVertexAttribArrayType enableVertexAttribArray; + glFramebufferRenderbufferType framebufferRenderbuffer; + glFramebufferTexture2DType framebufferTexture2D; + glGenBuffersType genBuffers; + glGenerateMipmapType generateMipmap; + glGenFramebuffersType genFramebuffers; + glGenRenderbuffersType genRenderbuffers; + glGetActiveAttribType getActiveAttrib; + glGetActiveUniformType getActiveUniform; + glGetAttribLocationType getAttribLocation; + glGetBufferParameterivType getBufferParameteriv; + glGetFramebufferAttachmentParameterivType getFramebufferAttachmentParameteriv; + glGetProgramInfoLogType getProgramInfoLog; + glGetProgramivType getProgramiv; + glGetRenderbufferParameterivType getRenderbufferParameteriv; + glGetShaderInfoLogType getShaderInfoLog; + glGetShaderivType getShaderiv; + glGetShaderSourceType getShaderSource; + glGetUniformfvType getUniformfv; + glGetUniformivType getUniformiv; + glGetUniformLocationType getUniformLocation; + glGetVertexAttribfvType getVertexAttribfv; + glGetVertexAttribivType getVertexAttribiv; + glGetVertexAttribPointervType getVertexAttribPointerv; + glIsBufferType isBuffer; + glIsFramebufferType isFramebuffer; + glIsProgramType isProgram; + glIsRenderbufferType isRenderbuffer; + glIsShaderType isShader; + glLinkProgramType linkProgram; + glRenderbufferStorageType renderbufferStorage; + glSampleCoverageType sampleCoverage; + glShaderSourceType shaderSource; + glStencilFuncSeparateType stencilFuncSeparate; + glStencilMaskSeparateType stencilMaskSeparate; + glStencilOpSeparateType stencilOpSeparate; + glUniform1fType uniform1f; + glUniform1fvType uniform1fv; + glUniform1iType uniform1i; + glUniform1ivType uniform1iv; + glUniform2fType uniform2f; + glUniform2fvType uniform2fv; + glUniform2iType uniform2i; + glUniform2ivType uniform2iv; + glUniform3fType uniform3f; + glUniform3fvType uniform3fv; + glUniform3iType uniform3i; + glUniform3ivType uniform3iv; + glUniform4fType uniform4f; + glUniform4fvType uniform4fv; + glUniform4iType uniform4i; + glUniform4ivType uniform4iv; + glUniformMatrix2fvType uniformMatrix2fv; + glUniformMatrix3fvType uniformMatrix3fv; + glUniformMatrix4fvType uniformMatrix4fv; + glUseProgramType useProgram; + glValidateProgramType validateProgram; + glVertexAttrib1fType vertexAttrib1f; + glVertexAttrib1fvType vertexAttrib1fv; + glVertexAttrib2fType vertexAttrib2f; + glVertexAttrib2fvType vertexAttrib2fv; + glVertexAttrib3fType vertexAttrib3f; + glVertexAttrib3fvType vertexAttrib3fv; + glVertexAttrib4fType vertexAttrib4f; + glVertexAttrib4fvType vertexAttrib4fv; + glVertexAttribPointerType vertexAttribPointer; + + GraphicsContext3D::Attributes m_attrs; + QGLWidget* m_glWidget; + GLuint m_texture; + GLuint m_mainFbo; + GLuint m_currentFbo; + GLuint m_depthBuffer; + QImage m_pixels; + ListHashSet<unsigned long> m_syntheticErrors; + +private: + + QGLWidget* getOwnerGLWidget(QWebPageClient* webPageClient); + void* getProcAddress(const String& proc); + bool m_contextValid; +}; + +#if defined (QT_OPENGL_ES_2) +#define GET_PROC_ADDRESS(Proc) Proc +#else +#define GET_PROC_ADDRESS(Proc) reinterpret_cast<Proc##Type>(getProcAddress(#Proc)); +#endif + +GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow) + : m_attrs(attrs) + , m_glWidget(0) + , m_texture(0) + , m_mainFbo(0) + , m_currentFbo(0) + , m_depthBuffer(0) + , m_contextValid(true) +{ + QWebPageClient* webPageClient = hostWindow->platformPageClient(); + QGLWidget* ownerGLWidget = getOwnerGLWidget(webPageClient); + + if (ownerGLWidget) + m_glWidget = new QGLWidget(0, ownerGLWidget); + else { + QGLFormat format; + format.setDepth(true); + format.setSampleBuffers(true); + format.setStencil(false); + + m_glWidget = new QGLWidget(format); + } + + if (!m_glWidget->isValid()) { + LOG_ERROR("GraphicsContext3D: QGLWidget does not have a valid context"); + m_contextValid = false; + return; + } + + QGLFormat format = m_glWidget->format(); + + m_attrs.alpha = format.alpha(); + m_attrs.depth = format.depth(); + m_attrs.stencil = format.stencil(); + m_attrs.antialias = false; + m_attrs.premultipliedAlpha = true; + + m_glWidget->makeCurrent(); + + activeTexture = GET_PROC_ADDRESS(glActiveTexture); + attachShader = GET_PROC_ADDRESS(glAttachShader); + bindAttribLocation = GET_PROC_ADDRESS(glBindAttribLocation); + bindBuffer = GET_PROC_ADDRESS(glBindBuffer); + bindFramebuffer = GET_PROC_ADDRESS(glBindFramebuffer); + bindRenderbuffer = GET_PROC_ADDRESS(glBindRenderbuffer); + blendColor = GET_PROC_ADDRESS(glBlendColor); + blendEquation = GET_PROC_ADDRESS(glBlendEquation); + blendEquationSeparate = GET_PROC_ADDRESS(glBlendEquationSeparate); + blendFuncSeparate = GET_PROC_ADDRESS(glBlendFuncSeparate); + bufferData = GET_PROC_ADDRESS(glBufferData); + bufferSubData = GET_PROC_ADDRESS(glBufferSubData); + checkFramebufferStatus = GET_PROC_ADDRESS(glCheckFramebufferStatus); + compileShader = GET_PROC_ADDRESS(glCompileShader); + createProgram = GET_PROC_ADDRESS(glCreateProgram); + createShader = GET_PROC_ADDRESS(glCreateShader); + deleteBuffers = GET_PROC_ADDRESS(glDeleteBuffers); + deleteFramebuffers = GET_PROC_ADDRESS(glDeleteFramebuffers); + deleteProgram = GET_PROC_ADDRESS(glDeleteProgram); + deleteRenderbuffers = GET_PROC_ADDRESS(glDeleteRenderbuffers); + deleteShader = GET_PROC_ADDRESS(glDeleteShader); + detachShader = GET_PROC_ADDRESS(glDetachShader); + disableVertexAttribArray = GET_PROC_ADDRESS(glDisableVertexAttribArray); + enableVertexAttribArray = GET_PROC_ADDRESS(glEnableVertexAttribArray); + framebufferRenderbuffer = GET_PROC_ADDRESS(glFramebufferRenderbuffer); + framebufferTexture2D = GET_PROC_ADDRESS(glFramebufferTexture2D); + genBuffers = GET_PROC_ADDRESS(glGenBuffers); + generateMipmap = GET_PROC_ADDRESS(glGenerateMipmap); + genFramebuffers = GET_PROC_ADDRESS(glGenFramebuffers); + genRenderbuffers = GET_PROC_ADDRESS(glGenRenderbuffers); + getActiveAttrib = GET_PROC_ADDRESS(glGetActiveAttrib); + getActiveUniform = GET_PROC_ADDRESS(glGetActiveUniform); + getAttribLocation = GET_PROC_ADDRESS(glGetAttribLocation); + getBufferParameteriv = GET_PROC_ADDRESS(glGetBufferParameteriv); + getFramebufferAttachmentParameteriv = GET_PROC_ADDRESS(glGetFramebufferAttachmentParameteriv); + getProgramInfoLog = GET_PROC_ADDRESS(glGetProgramInfoLog); + getProgramiv = GET_PROC_ADDRESS(glGetProgramiv); + getRenderbufferParameteriv = GET_PROC_ADDRESS(glGetRenderbufferParameteriv); + getShaderInfoLog = GET_PROC_ADDRESS(glGetShaderInfoLog); + getShaderiv = GET_PROC_ADDRESS(glGetShaderiv); + getShaderSource = GET_PROC_ADDRESS(glGetShaderSource); + getUniformfv = GET_PROC_ADDRESS(glGetUniformfv); + getUniformiv = GET_PROC_ADDRESS(glGetUniformiv); + getUniformLocation = GET_PROC_ADDRESS(glGetUniformLocation); + getVertexAttribfv = GET_PROC_ADDRESS(glGetVertexAttribfv); + getVertexAttribiv = GET_PROC_ADDRESS(glGetVertexAttribiv); + getVertexAttribPointerv = GET_PROC_ADDRESS(glGetVertexAttribPointerv); + isBuffer = GET_PROC_ADDRESS(glIsBuffer); + isFramebuffer = GET_PROC_ADDRESS(glIsFramebuffer); + isProgram = GET_PROC_ADDRESS(glIsProgram); + isRenderbuffer = GET_PROC_ADDRESS(glIsRenderbuffer); + isShader = GET_PROC_ADDRESS(glIsShader); + linkProgram = GET_PROC_ADDRESS(glLinkProgram); + renderbufferStorage = GET_PROC_ADDRESS(glRenderbufferStorage); + sampleCoverage = GET_PROC_ADDRESS(glSampleCoverage); + shaderSource = GET_PROC_ADDRESS(glShaderSource); + stencilFuncSeparate = GET_PROC_ADDRESS(glStencilFuncSeparate); + stencilMaskSeparate = GET_PROC_ADDRESS(glStencilMaskSeparate); + stencilOpSeparate = GET_PROC_ADDRESS(glStencilOpSeparate); + uniform1f = GET_PROC_ADDRESS(glUniform1f); + uniform1fv = GET_PROC_ADDRESS(glUniform1fv); + uniform1i = GET_PROC_ADDRESS(glUniform1i); + uniform1iv = GET_PROC_ADDRESS(glUniform1iv); + uniform2f = GET_PROC_ADDRESS(glUniform2f); + uniform2fv = GET_PROC_ADDRESS(glUniform2fv); + uniform2i = GET_PROC_ADDRESS(glUniform2i); + uniform2iv = GET_PROC_ADDRESS(glUniform2iv); + uniform3f = GET_PROC_ADDRESS(glUniform3f); + uniform3fv = GET_PROC_ADDRESS(glUniform3fv); + uniform3i = GET_PROC_ADDRESS(glUniform3i); + uniform3iv = GET_PROC_ADDRESS(glUniform3iv); + uniform4f = GET_PROC_ADDRESS(glUniform4f); + uniform4fv = GET_PROC_ADDRESS(glUniform4fv); + uniform4i = GET_PROC_ADDRESS(glUniform4i); + uniform4iv = GET_PROC_ADDRESS(glUniform4iv); + uniformMatrix2fv = GET_PROC_ADDRESS(glUniformMatrix2fv); + uniformMatrix3fv = GET_PROC_ADDRESS(glUniformMatrix3fv); + uniformMatrix4fv = GET_PROC_ADDRESS(glUniformMatrix4fv); + useProgram = GET_PROC_ADDRESS(glUseProgram); + validateProgram = GET_PROC_ADDRESS(glValidateProgram); + vertexAttrib1f = GET_PROC_ADDRESS(glVertexAttrib1f); + vertexAttrib1fv = GET_PROC_ADDRESS(glVertexAttrib1fv); + vertexAttrib2f = GET_PROC_ADDRESS(glVertexAttrib2f); + vertexAttrib2fv = GET_PROC_ADDRESS(glVertexAttrib2fv); + vertexAttrib3f = GET_PROC_ADDRESS(glVertexAttrib3f); + vertexAttrib3fv = GET_PROC_ADDRESS(glVertexAttrib3fv); + vertexAttrib4f = GET_PROC_ADDRESS(glVertexAttrib4f); + vertexAttrib4fv = GET_PROC_ADDRESS(glVertexAttrib4fv); + vertexAttribPointer = GET_PROC_ADDRESS(glVertexAttribPointer); + + if (!m_contextValid) { + LOG_ERROR("GraphicsContext3D: All needed OpenGL extensions are not available"); + m_contextValid = false; + return; + } + + glGenTextures(1, &m_texture); + glBindTexture(GraphicsContext3D::TEXTURE_2D, m_texture); + glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); + glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); + glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); + glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); + glTexImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0); + glBindTexture(GraphicsContext3D::TEXTURE_2D, 0); + + genFramebuffers(/* count */ 1, &m_mainFbo); + m_currentFbo = m_mainFbo; + + bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_mainFbo); + + genRenderbuffers(/* count */ 1, &m_depthBuffer); + bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBuffer); +#if defined(QT_OPENGL_ES_2) + renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, /* width */ 1, /* height */ 1); +#else + renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, /* width */ 1, /* height */ 1); +#endif + + bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); + + framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_texture, 0); + framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer); + glClearColor(/* red */ 0, /* green */ 0, /* blue */ 0, /* alpha */ 0); + + if (checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { + LOG_ERROR("GraphicsContext3D: Wasn't able to create the main framebuffer"); + m_contextValid = false; + } +} + +GraphicsContext3DInternal::~GraphicsContext3DInternal() +{ + delete m_glWidget; + m_glWidget = 0; +} + +QGLWidget* GraphicsContext3DInternal::getOwnerGLWidget(QWebPageClient* webPageClient) +{ + QAbstractScrollArea* scrollArea = qobject_cast<QAbstractScrollArea*>(webPageClient->ownerWidget()); + + if (scrollArea) + return qobject_cast<QGLWidget*>(scrollArea->viewport()); + + return 0; +} + +void* GraphicsContext3DInternal::getProcAddress(const String& proc) +{ + String ext[3] = { "", "ARB", "EXT" }; + + for (int i = 0; i < 3; i++) { + String nameWithExt = proc + ext[i]; + + void* addr = m_glWidget->context()->getProcAddress(nameWithExt.utf8().data()); + if (addr) + return addr; + } + + LOG_ERROR("GraphicsContext3D: Did not find GL function %s", proc.utf8().data()); + m_contextValid = false; + return 0; +} + +PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow) +{ + OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs, hostWindow)); + return context->m_internal ? context.release() : 0; +} + +GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow) + : m_internal(new GraphicsContext3DInternal(attrs, hostWindow)) +{ + if (!m_internal->isContextValid()) + m_internal = 0; +} + +GraphicsContext3D::~GraphicsContext3D() +{ +} + +PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() +{ + return m_internal->m_glWidget; +} + +Platform3DObject GraphicsContext3D::platformTexture() const +{ + return m_internal->m_texture; +} + +void GraphicsContext3D::makeContextCurrent() +{ + m_internal->m_glWidget->makeCurrent(); +} + +void GraphicsContext3D::beginPaint(WebGLRenderingContext* context) +{ + m_internal->m_glWidget->makeCurrent(); + + HTMLCanvasElement* canvas = context->canvas(); + ImageBuffer* imageBuffer = canvas->buffer(); + + m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_mainFbo); + + glReadPixels(/* x */ 0, /* y */ 0, m_currentWidth, m_currentHeight, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, m_internal->m_pixels.bits()); + + QPainter* p = imageBuffer->context()->platformContext(); + p->drawImage(/* x */ 0, /* y */ 0, m_internal->m_pixels.transformed(QMatrix().rotate(180))); + + m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_currentFbo); +} + +void GraphicsContext3D::endPaint() +{ +} + +void GraphicsContext3D::reshape(int width, int height) +{ + if (((width == m_currentWidth) && (height == m_currentHeight)) || (!m_internal)) + return; + + m_currentWidth = width; + m_currentHeight = height; + + m_internal->m_pixels = QImage(m_currentWidth, m_currentHeight, QImage::Format_ARGB32); + + m_internal->m_glWidget->makeCurrent(); + + glBindTexture(GraphicsContext3D::TEXTURE_2D, m_internal->m_texture); + glTexImage2D(GraphicsContext3D::TEXTURE_2D, /* level */ 0, GraphicsContext3D::RGBA, width, height, /* border */ 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, /* data */ 0); + glBindTexture(GraphicsContext3D::TEXTURE_2D, 0); + + m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_mainFbo); + m_internal->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_internal->m_depthBuffer); +#if defined(QT_OPENGL_ES_2) + renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, width, height); +#else + renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, width, height); +#endif + m_internal->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); + + m_internal->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_internal->m_texture, 0); + m_internal->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_internal->m_depthBuffer); + + GLenum status = m_internal->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER); + if (status != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { + LOG_ERROR("GraphicsContext3D: Wasn't able to reshape the main framebuffer"); + notImplemented(); + } + + glClear(GraphicsContext3D::COLOR_BUFFER_BIT); + glFlush(); +} + +void GraphicsContext3D::activeTexture(unsigned long texture) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->activeTexture(texture); +} + +void GraphicsContext3D::attachShader(WebGLProgram* program, WebGLShader* shader) +{ + ASSERT(program); + ASSERT(shader); + m_internal->m_glWidget->makeCurrent(); + m_internal->attachShader((GLuint) program->object(), (GLuint) shader->object()); +} + +void GraphicsContext3D::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name) +{ + ASSERT(program); + m_internal->m_glWidget->makeCurrent(); + m_internal->bindAttribLocation((GLuint) program->object(), index, name.utf8().data()); +} + +void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->bindBuffer(target, buffer ? (GLuint) buffer->object() : 0); +} + +void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->m_currentFbo = (buffer && buffer->object()) ? (GLuint) buffer->object() : m_internal->m_mainFbo; + m_internal->bindFramebuffer(target, m_internal->m_currentFbo); +} + +void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->bindRenderbuffer(target, renderbuffer ? (GLuint) renderbuffer->object() : 0); +} + +void GraphicsContext3D::bindTexture(unsigned long target, WebGLTexture* texture) +{ + m_internal->m_glWidget->makeCurrent(); + glBindTexture(target, texture ? (GLuint) texture->object() : 0); +} + +void GraphicsContext3D::blendColor(double red, double green, double blue, double alpha) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->blendColor(static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue), static_cast<float>(alpha)); +} + +void GraphicsContext3D::blendEquation(unsigned long mode) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->blendEquation(mode); +} + +void GraphicsContext3D::blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->blendEquationSeparate(modeRGB, modeAlpha); +} + +void GraphicsContext3D::blendFunc(unsigned long sfactor, unsigned long dfactor) +{ + m_internal->m_glWidget->makeCurrent(); + glBlendFunc(sfactor, dfactor); +} + +void GraphicsContext3D::blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long usage) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->bufferData(target, size, /* data */ 0, usage); +} + +void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage) +{ + if (!array || !array->length()) + return; + + m_internal->m_glWidget->makeCurrent(); + m_internal->bufferData(target, array->byteLength(), array->baseAddress(), usage); +} + +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array) +{ + if (!array || !array->length()) + return; + + m_internal->m_glWidget->makeCurrent(); + m_internal->bufferSubData(target, offset, array->byteLength(), array->baseAddress()); +} + +unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target) +{ + m_internal->m_glWidget->makeCurrent(); + return m_internal->checkFramebufferStatus(target); +} + +void GraphicsContext3D::clearColor(double r, double g, double b, double a) +{ + m_internal->m_glWidget->makeCurrent(); + glClearColor(static_cast<float>(r), static_cast<float>(g), static_cast<float>(b), static_cast<float>(a)); +} + +void GraphicsContext3D::clear(unsigned long mask) +{ + m_internal->m_glWidget->makeCurrent(); + glClear(mask); +} + +void GraphicsContext3D::clearDepth(double depth) +{ + m_internal->m_glWidget->makeCurrent(); +#if defined(QT_OPENGL_ES_2) + glClearDepthf(depth); +#else + glClearDepth(depth); +#endif +} + +void GraphicsContext3D::clearStencil(long s) +{ + m_internal->m_glWidget->makeCurrent(); + glClearStencil(s); +} + +void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha) +{ + m_internal->m_glWidget->makeCurrent(); + glColorMask(red, green, blue, alpha); +} + +void GraphicsContext3D::compileShader(WebGLShader* shader) +{ + ASSERT(shader); + m_internal->m_glWidget->makeCurrent(); + m_internal->compileShader((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) +{ + m_internal->m_glWidget->makeCurrent(); + 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) +{ + m_internal->m_glWidget->makeCurrent(); + glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); +} + +void GraphicsContext3D::cullFace(unsigned long mode) +{ + m_internal->m_glWidget->makeCurrent(); + glCullFace(mode); +} + +void GraphicsContext3D::depthFunc(unsigned long func) +{ + m_internal->m_glWidget->makeCurrent(); + glDepthFunc(func); +} + +void GraphicsContext3D::depthMask(bool flag) +{ + m_internal->m_glWidget->makeCurrent(); + glDepthMask(flag); +} + +void GraphicsContext3D::depthRange(double zNear, double zFar) +{ + m_internal->m_glWidget->makeCurrent(); +#if defined(QT_OPENGL_ES_2) + glDepthRangef(zNear, zFar); +#else + glDepthRange(zNear, zFar); +#endif +} + +void GraphicsContext3D::detachShader(WebGLProgram* program, WebGLShader* shader) +{ + ASSERT(program); + ASSERT(shader); + m_internal->m_glWidget->makeCurrent(); + m_internal->detachShader((GLuint) program->object(), (GLuint) shader->object()); +} + +void GraphicsContext3D::disable(unsigned long cap) +{ + m_internal->m_glWidget->makeCurrent(); + glDisable(cap); +} + +void GraphicsContext3D::disableVertexAttribArray(unsigned long index) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->disableVertexAttribArray(index); +} + +void GraphicsContext3D::drawArrays(unsigned long mode, long first, long count) +{ + m_internal->m_glWidget->makeCurrent(); + glDrawArrays(mode, first, count); +} + +void GraphicsContext3D::drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset) +{ + m_internal->m_glWidget->makeCurrent(); + glDrawElements(mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::enable(unsigned long cap) +{ + m_internal->m_glWidget->makeCurrent(); + glEnable(cap); +} + +void GraphicsContext3D::enableVertexAttribArray(unsigned long index) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->enableVertexAttribArray(index); +} + +void GraphicsContext3D::finish() +{ + m_internal->m_glWidget->makeCurrent(); + glFinish(); +} + +void GraphicsContext3D::flush() +{ + m_internal->m_glWidget->makeCurrent(); + glFlush(); +} + +void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->framebufferRenderbuffer(target, attachment, renderbuffertarget, buffer ? (GLuint) buffer->object() : 0); +} + +void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->framebufferTexture2D(target, attachment, textarget, texture ? (GLuint) texture->object() : 0, level); +} + +void GraphicsContext3D::frontFace(unsigned long mode) +{ + m_internal->m_glWidget->makeCurrent(); + glFrontFace(mode); +} + +void GraphicsContext3D::generateMipmap(unsigned long target) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->generateMipmap(target); +} + +bool GraphicsContext3D::getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo& info) +{ + if (!program->object()) { + synthesizeGLError(INVALID_VALUE); + return false; + } + + m_internal->m_glWidget->makeCurrent(); + + GLint maxLength; + m_internal->getProgramiv(static_cast<GLuint>(program->object()), GraphicsContext3D::ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength); + + GLchar* name = (GLchar*) fastMalloc(maxLength); + GLsizei nameLength; + GLint size; + GLenum type; + + m_internal->getActiveAttrib(static_cast<GLuint>(program->object()), index, maxLength, &nameLength, &size, &type, name); + + if (!nameLength) { + fastFree(name); + return false; + } + + info.name = String(name, nameLength); + info.type = type; + info.size = size; + + fastFree(name); + return true; +} + +bool GraphicsContext3D::getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo& info) +{ + if (!program->object()) { + synthesizeGLError(INVALID_VALUE); + return false; + } + + m_internal->m_glWidget->makeCurrent(); + + GLint maxLength; + m_internal->getProgramiv(static_cast<GLuint>(program->object()), GraphicsContext3D::ACTIVE_UNIFORM_MAX_LENGTH, &maxLength); + + GLchar* name = (GLchar*) fastMalloc(maxLength); + GLsizei nameLength; + GLint size; + GLenum type; + + m_internal->getActiveUniform(static_cast<GLuint>(program->object()), index, maxLength, &nameLength, &size, &type, name); + + if (!nameLength) { + fastFree(name); + return false; + } + + info.name = String(name, nameLength); + info.type = type; + info.size = size; + + fastFree(name); + return true; +} + +int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& name) +{ + if (!program) + return -1; + + m_internal->m_glWidget->makeCurrent(); + return m_internal->getAttribLocation((GLuint) program->object(), name.utf8().data()); +} + +GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes() +{ + return m_internal->m_attrs; +} + +unsigned long GraphicsContext3D::getError() +{ + if (m_internal->m_syntheticErrors.size() > 0) { + ListHashSet<unsigned long>::iterator iter = m_internal->m_syntheticErrors.begin(); + unsigned long err = *iter; + m_internal->m_syntheticErrors.remove(iter); + return err; + } + + m_internal->m_glWidget->makeCurrent(); + return glGetError(); +} + +String GraphicsContext3D::getString(unsigned long name) +{ + m_internal->m_glWidget->makeCurrent(); + return String((const char*) glGetString(name)); +} + +void GraphicsContext3D::hint(unsigned long target, unsigned long mode) +{ + m_internal->m_glWidget->makeCurrent(); + glHint(target, mode); +} + +bool GraphicsContext3D::isBuffer(WebGLBuffer* buffer) +{ + if (!buffer) + return false; + + m_internal->m_glWidget->makeCurrent(); + return m_internal->isBuffer((GLuint) buffer->object()); +} + +bool GraphicsContext3D::isEnabled(unsigned long cap) +{ + m_internal->m_glWidget->makeCurrent(); + return glIsEnabled(cap); +} + +bool GraphicsContext3D::isFramebuffer(WebGLFramebuffer* framebuffer) +{ + if (!framebuffer) + return false; + + m_internal->m_glWidget->makeCurrent(); + return m_internal->isFramebuffer((GLuint) framebuffer->object()); +} + +bool GraphicsContext3D::isProgram(WebGLProgram* program) +{ + if (!program) + return false; + + m_internal->m_glWidget->makeCurrent(); + return m_internal->isProgram((GLuint) program->object()); +} + +bool GraphicsContext3D::isRenderbuffer(WebGLRenderbuffer* renderbuffer) +{ + if (!renderbuffer) + return false; + + m_internal->m_glWidget->makeCurrent(); + return m_internal->isRenderbuffer((GLuint) renderbuffer->object()); +} + +bool GraphicsContext3D::isShader(WebGLShader* shader) +{ + if (!shader) + return false; + + m_internal->m_glWidget->makeCurrent(); + return m_internal->isShader((GLuint) shader->object()); +} + +bool GraphicsContext3D::isTexture(WebGLTexture* texture) +{ + if (!texture) + return false; + + m_internal->m_glWidget->makeCurrent(); + return glIsTexture((GLuint) texture->object()); +} + +void GraphicsContext3D::lineWidth(double width) +{ + m_internal->m_glWidget->makeCurrent(); + glLineWidth(static_cast<float>(width)); +} + +void GraphicsContext3D::linkProgram(WebGLProgram* program) +{ + ASSERT(program); + m_internal->m_glWidget->makeCurrent(); + m_internal->linkProgram((GLuint) program->object()); +} + +void GraphicsContext3D::pixelStorei(unsigned long paramName, long param) +{ + m_internal->m_glWidget->makeCurrent(); + glPixelStorei(paramName, param); +} + +void GraphicsContext3D::polygonOffset(double factor, double units) +{ + m_internal->m_glWidget->makeCurrent(); + glPolygonOffset(static_cast<float>(factor), static_cast<float>(units)); +} + +void GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* data) +{ + m_internal->m_glWidget->makeCurrent(); + + if (type != GraphicsContext3D::UNSIGNED_BYTE || format != GraphicsContext3D::RGBA) + return; + + glReadPixels(x, y, width, height, format, type, (GLvoid*) data); +} + +void GraphicsContext3D::releaseShaderCompiler() +{ + m_internal->m_glWidget->makeCurrent(); + notImplemented(); +} + +void GraphicsContext3D::renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->renderbufferStorage(target, internalformat, width, height); +} + +void GraphicsContext3D::sampleCoverage(double value, bool invert) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->sampleCoverage(static_cast<float>(value), invert); +} + +void GraphicsContext3D::scissor(long x, long y, unsigned long width, unsigned long height) +{ + m_internal->m_glWidget->makeCurrent(); + glScissor(x, y, width, height); +} + +void GraphicsContext3D::shaderSource(WebGLShader* shader, const String& source) +{ + ASSERT(shader); + + m_internal->m_glWidget->makeCurrent(); + + CString sourceCS = source.utf8(); + const char* data = sourceCS.data(); + int length = source.length(); + m_internal->shaderSource((GLuint) shader->object(), /* count */ 1, &data, &length); +} + +void GraphicsContext3D::stencilFunc(unsigned long func, long ref, unsigned long mask) +{ + m_internal->m_glWidget->makeCurrent(); + glStencilFunc(func, ref, mask); +} + +void GraphicsContext3D::stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->stencilFuncSeparate(face, func, ref, mask); +} + +void GraphicsContext3D::stencilMask(unsigned long mask) +{ + m_internal->m_glWidget->makeCurrent(); + glStencilMask(mask); +} + +void GraphicsContext3D::stencilMaskSeparate(unsigned long face, unsigned long mask) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->stencilMaskSeparate(face, mask); +} + +void GraphicsContext3D::stencilOp(unsigned long fail, unsigned long zfail, unsigned long zpass) +{ + m_internal->m_glWidget->makeCurrent(); + glStencilOp(fail, zfail, zpass); +} + +void GraphicsContext3D::stencilOpSeparate(unsigned long face, unsigned long fail, unsigned long zfail, unsigned long zpass) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->stencilOpSeparate(face, fail, zfail, zpass); +} + +void GraphicsContext3D::texParameterf(unsigned target, unsigned paramName, float value) +{ + m_internal->m_glWidget->makeCurrent(); + glTexParameterf(target, paramName, static_cast<float>(value)); +} + +void GraphicsContext3D::texParameteri(unsigned target, unsigned paramName, int value) +{ + m_internal->m_glWidget->makeCurrent(); + glTexParameteri(target, paramName, static_cast<float>(value)); +} + +void GraphicsContext3D::uniform1f(long location, float v0) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform1f(location, v0); +} + +void GraphicsContext3D::uniform1fv(long location, float* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform1fv(location, size, array); +} + +void GraphicsContext3D::uniform2f(long location, float v0, float v1) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform2f(location, v0, v1); +} + +void GraphicsContext3D::uniform2fv(long location, float* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform2fv(location, size, array); +} + +void GraphicsContext3D::uniform3f(long location, float v0, float v1, float v2) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform3f(location, v0, v1, v2); +} + +void GraphicsContext3D::uniform3fv(long location, float* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform3fv(location, size, array); +} + +void GraphicsContext3D::uniform4f(long location, float v0, float v1, float v2, float v3) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform4f(location, v0, v1, v2, v3); +} + +void GraphicsContext3D::uniform4fv(long location, float* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform4fv(location, size, array); +} + +void GraphicsContext3D::uniform1i(long location, int v0) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform1i(location, v0); +} + +void GraphicsContext3D::uniform1iv(long location, int* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform1iv(location, size, array); +} + +void GraphicsContext3D::uniform2i(long location, int v0, int v1) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform2i(location, v0, v1); +} + +void GraphicsContext3D::uniform2iv(long location, int* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform2iv(location, size, array); +} + +void GraphicsContext3D::uniform3i(long location, int v0, int v1, int v2) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform3i(location, v0, v1, v2); +} + +void GraphicsContext3D::uniform3iv(long location, int* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform3iv(location, size, array); +} + +void GraphicsContext3D::uniform4i(long location, int v0, int v1, int v2, int v3) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform4i(location, v0, v1, v2, v3); +} + +void GraphicsContext3D::uniform4iv(long location, int* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniform4iv(location, size, array); +} + +void GraphicsContext3D::uniformMatrix2fv(long location, bool transpose, float* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniformMatrix2fv(location, size, transpose, array); +} + +void GraphicsContext3D::uniformMatrix3fv(long location, bool transpose, float* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniformMatrix3fv(location, size, transpose, array); +} + +void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* array, int size) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->uniformMatrix4fv(location, size, transpose, array); +} + +void GraphicsContext3D::useProgram(WebGLProgram* program) +{ + ASSERT(program); + + m_internal->m_glWidget->makeCurrent(); + m_internal->useProgram((GLuint) program->object()); +} + +void GraphicsContext3D::validateProgram(WebGLProgram* program) +{ + ASSERT(program); + + m_internal->m_glWidget->makeCurrent(); + m_internal->validateProgram((GLuint) program->object()); +} + +void GraphicsContext3D::vertexAttrib1f(unsigned long indx, float v0) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttrib1f(indx, v0); +} + +void GraphicsContext3D::vertexAttrib1fv(unsigned long indx, float* array) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttrib1fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib2f(unsigned long indx, float v0, float v1) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttrib2f(indx, v0, v1); +} + +void GraphicsContext3D::vertexAttrib2fv(unsigned long indx, float* array) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttrib2fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib3f(unsigned long indx, float v0, float v1, float v2) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttrib3f(indx, v0, v1, v2); +} + +void GraphicsContext3D::vertexAttrib3fv(unsigned long indx, float* array) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttrib3fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib4f(unsigned long indx, float v0, float v1, float v2, float v3) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttrib4f(indx, v0, v1, v2, v3); +} + +void GraphicsContext3D::vertexAttrib4fv(unsigned long indx, float* array) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttrib4fv(indx, array); +} + +void GraphicsContext3D::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, unsigned long stride, unsigned long offset) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->vertexAttribPointer(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) +{ + m_internal->m_glWidget->makeCurrent(); + glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height)); +} + +void GraphicsContext3D::getBooleanv(unsigned long paramName, unsigned char* value) +{ + m_internal->m_glWidget->makeCurrent(); + glGetBooleanv(paramName, value); +} + +void GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long paramName, int* value) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->getBufferParameteriv(target, paramName, value); +} + +void GraphicsContext3D::getFloatv(unsigned long paramName, float* value) +{ + m_internal->m_glWidget->makeCurrent(); + glGetFloatv(paramName, value); +} + +void GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long paramName, int* value) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->getFramebufferAttachmentParameteriv(target, attachment, paramName, value); +} + +void GraphicsContext3D::getIntegerv(unsigned long paramName, int* value) +{ + m_internal->m_glWidget->makeCurrent(); + glGetIntegerv(paramName, value); +} + +void GraphicsContext3D::getProgramiv(WebGLProgram* program, unsigned long paramName, int* value) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->getProgramiv((GLuint) program->object(), paramName, value); +} + +String GraphicsContext3D::getProgramInfoLog(WebGLProgram* program) +{ + m_internal->m_glWidget->makeCurrent(); + + GLint length; + m_internal->getProgramiv((GLuint) program->object(), GraphicsContext3D::INFO_LOG_LENGTH, &length); + + GLsizei size; + + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + + m_internal->getProgramInfoLog((GLuint) program->object(), length, &size, info); + + String result(info); + fastFree(info); + + return result; +} + +void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long paramName, int* value) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->getRenderbufferParameteriv(target, paramName, value); +} + +void GraphicsContext3D::getShaderiv(WebGLShader* shader, unsigned long paramName, int* value) +{ + ASSERT(shader); + m_internal->m_glWidget->makeCurrent(); + m_internal->getShaderiv((GLuint) shader->object(), paramName, value); +} + +String GraphicsContext3D::getShaderInfoLog(WebGLShader* shader) +{ + m_internal->m_glWidget->makeCurrent(); + + GLint length; + m_internal->getShaderiv((GLuint) shader->object(), GraphicsContext3D::INFO_LOG_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + + m_internal->getShaderInfoLog((GLuint) shader->object(), length, &size, info); + + String result(info); + fastFree(info); + + return result; +} + +String GraphicsContext3D::getShaderSource(WebGLShader* shader) +{ + m_internal->m_glWidget->makeCurrent(); + + GLint length; + m_internal->getShaderiv((GLuint) shader->object(), GraphicsContext3D::SHADER_SOURCE_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + + m_internal->getShaderSource((GLuint) shader->object(), length, &size, info); + + String result(info); + fastFree(info); + + return result; +} + +void GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long paramName, float* value) +{ + m_internal->m_glWidget->makeCurrent(); + glGetTexParameterfv(target, paramName, value); +} + +void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long paramName, int* value) +{ + m_internal->m_glWidget->makeCurrent(); + glGetTexParameteriv(target, paramName, value); +} + +void GraphicsContext3D::getUniformfv(WebGLProgram* program, long location, float* value) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->getUniformfv((GLuint) program->object(), location, value); +} + +void GraphicsContext3D::getUniformiv(WebGLProgram* program, long location, int* value) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->getUniformiv((GLuint) program->object(), location, value); +} + +long GraphicsContext3D::getUniformLocation(WebGLProgram* program, const String& name) +{ + ASSERT(program); + + m_internal->m_glWidget->makeCurrent(); + return m_internal->getUniformLocation((GLuint) program->object(), name.utf8().data()); +} + +void GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long paramName, float* value) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->getVertexAttribfv(index, paramName, value); +} + +void GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long paramName, int* value) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->getVertexAttribiv(index, paramName, value); +} + +long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long paramName) +{ + m_internal->m_glWidget->makeCurrent(); + + void* pointer; + m_internal->getVertexAttribPointerv(index, paramName, &pointer); + return reinterpret_cast<long>(pointer); +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels) +{ + glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + return 0; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha) +{ + ASSERT(image); + + m_internal->m_glWidget->makeCurrent(); + + Vector<uint8_t> imageData; + GLuint format; + GLuint internalFormat; + + if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat)) { + LOG_ERROR("GraphicsContext3D::texImage2D: could not extract Image data"); + return -1; + } + + glTexImage2D(target, level, internalFormat, image->width(), image->height(), + /* border */ 0, format, GraphicsContext3D::UNSIGNED_BYTE, imageData.data()); + + return 0; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, void* pixels) +{ + glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels); + return 0; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, Image* image, bool flipY, bool premultiplyAlpha) +{ + ASSERT(image); + + Vector<uint8_t> imageData; + GLuint format; + GLuint internalFormat; + + if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat)) { + LOG_ERROR("GraphicsContext3D::texSubImage2D: could not extract Image data"); + return -1; + } + + glTexSubImage2D(target, level, xoff, yoff, image->width(), image->height(), + format, GraphicsContext3D::UNSIGNED_BYTE, imageData.data()); + + return 0; +} + +unsigned GraphicsContext3D::createBuffer() +{ + m_internal->m_glWidget->makeCurrent(); + GLuint handle; + m_internal->genBuffers(/* count */ 1, &handle); + return handle; +} + +unsigned GraphicsContext3D::createFramebuffer() +{ + m_internal->m_glWidget->makeCurrent(); + GLuint handle; + m_internal->genFramebuffers(/* count */ 1, &handle); + return handle; +} + +unsigned GraphicsContext3D::createProgram() +{ + m_internal->m_glWidget->makeCurrent(); + return m_internal->createProgram(); +} + +unsigned GraphicsContext3D::createRenderbuffer() +{ + m_internal->m_glWidget->makeCurrent(); + GLuint handle; + m_internal->genRenderbuffers(/* count */ 1, &handle); + return handle; +} + +unsigned GraphicsContext3D::createShader(unsigned long type) +{ + m_internal->m_glWidget->makeCurrent(); + return m_internal->createShader((type == FRAGMENT_SHADER) ? GraphicsContext3D::FRAGMENT_SHADER : GraphicsContext3D::VERTEX_SHADER); +} + +unsigned GraphicsContext3D::createTexture() +{ + m_internal->m_glWidget->makeCurrent(); + GLuint handle; + glGenTextures(1, &handle); + return handle; +} + +void GraphicsContext3D::deleteBuffer(unsigned buffer) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->deleteBuffers(1, &buffer); +} + +void GraphicsContext3D::deleteFramebuffer(unsigned framebuffer) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->deleteFramebuffers(1, &framebuffer); +} + +void GraphicsContext3D::deleteProgram(unsigned program) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->deleteProgram(program); +} + +void GraphicsContext3D::deleteRenderbuffer(unsigned renderbuffer) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->deleteRenderbuffers(1, &renderbuffer); +} + +void GraphicsContext3D::deleteShader(unsigned shader) +{ + m_internal->m_glWidget->makeCurrent(); + m_internal->deleteShader(shader); +} + +void GraphicsContext3D::deleteTexture(unsigned texture) +{ + m_internal->m_glWidget->makeCurrent(); + glDeleteTextures(1, &texture); +} + +int GraphicsContext3D::sizeInBytes(int type) +{ + switch (type) { + case GraphicsContext3D::BYTE: + return sizeof(GLbyte); + case GraphicsContext3D::UNSIGNED_BYTE: + return sizeof(GLubyte); + case GraphicsContext3D::SHORT: + return sizeof(GLshort); + case GraphicsContext3D::UNSIGNED_SHORT: + return sizeof(GLushort); + case GraphicsContext3D::INT: + return sizeof(GLint); + case GraphicsContext3D::UNSIGNED_INT: + return sizeof(GLuint); + case GraphicsContext3D::FLOAT: + return sizeof(GLfloat); + default: + return 0; + } +} + +void GraphicsContext3D::synthesizeGLError(unsigned long error) +{ + m_internal->m_syntheticErrors.add(error); +} + +bool GraphicsContext3D::getImageData(Image* image, + Vector<uint8_t>& outputVector, + bool premultiplyAlpha, + bool* hasAlphaChannel, + AlphaOp* neededAlphaOp, + unsigned int* format) +{ + QImage::Format imageFormat = (!premultiplyAlpha) ? + QImage::Format_ARGB32 : + QImage::Format_ARGB32_Premultiplied; + + QPixmap* nativePixmap = image->nativeImageForCurrentFrame(); + + *hasAlphaChannel = true; + *neededAlphaOp = kAlphaDoNothing; + *format = GraphicsContext3D::RGBA; + + QImage nativeImage = nativePixmap->toImage().convertToFormat(imageFormat); + outputVector.append(nativeImage.bits(), nativeImage.byteCount()); + + return true; +} + +} + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 8bcda2e..edac268 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -312,14 +312,16 @@ void GraphicsContext::drawRect(const IntRect& rect) 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)); + if (m_common->state.shadowColor.isValid()) { + 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); @@ -410,7 +412,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) patternOffset = patWidth / 2; } else { if (remainder) - patternOffset = (patWidth - remainder)/2; + patternOffset = (patWidth - remainder) / 2; } } @@ -614,10 +616,20 @@ void GraphicsContext::fillRect(const FloatRect& rect) QPainter* p = m_data->p(); if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) { - drawBorderlessRectShadow(this, p, rect); + if (m_common->state.shadowColor.isValid()) + drawBorderlessRectShadow(this, p, rect); if (m_common->state.fillPattern) { AffineTransform affine; - p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); + FloatRect rectM(rect); + QBrush brush(m_common->state.fillPattern->createPlatformPattern(affine)); + QPixmap* image = m_common->state.fillPattern->tileImage()->nativeImageForCurrentFrame(); + + if (!m_common->state.fillPattern->repeatX() && image) + rectM.setWidth(image->width()); + if (!m_common->state.fillPattern->repeatY() && image) + rectM.setHeight(image->height()); + p->fillRect(rectM, brush); + } else if (m_common->state.fillGradient) { QBrush brush(*m_common->state.fillGradient->platformGradient()); brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); @@ -636,7 +648,8 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c, ColorSpace m_data->solidColor.setColor(c); QPainter* p = m_data->p(); - drawBorderlessRectShadow(this, p, rect); + if (m_common->state.shadowColor.isValid()) + drawBorderlessRectShadow(this, p, rect); p->fillRect(rect, m_data->solidColor); } @@ -1006,11 +1019,11 @@ void GraphicsContext::rotate(float radians) if (paintingDisabled()) return; - m_data->p()->rotate(180/M_PI*radians); + m_data->p()->rotate(180 / M_PI*radians); if (!m_data->currentPath.isEmpty()) { QTransform matrix; - m_data->currentPath = m_data->currentPath * matrix.rotate(-180/M_PI*radians); + m_data->currentPath = m_data->currentPath * matrix.rotate(-180 / M_PI*radians); m_common->state.pathTransform.rotate(radians); } } diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp index 0fd0f1a..834cd4f 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp @@ -29,6 +29,7 @@ #include "UnitBezier.h" #include <QtCore/qabstractanimation.h> #include <QtCore/qdebug.h> +#include <QtCore/qmetaobject.h> #include <QtCore/qset.h> #include <QtCore/qtimer.h> #include <QtGui/qbitmap.h> @@ -101,31 +102,37 @@ public: // modified by the compositor, so we can know what to look for in the next flush enum ChangeMask { NoChanges = 0, + + ParentChange = (1L << 0), ChildrenChange = (1L << 1), MaskLayerChange = (1L << 2), PositionChange = (1L << 3), + AnchorPointChange = (1L << 4), SizeChange = (1L << 5), TransformChange = (1L << 6), ContentChange = (1L << 7), + GeometryOrientationChange = (1L << 8), ContentsOrientationChange = (1L << 9), OpacityChange = (1L << 10), ContentsRectChange = (1L << 11), + Preserves3DChange = (1L << 12), MasksToBoundsChange = (1L << 13), DrawsContentChange = (1L << 14), ContentsOpaqueChange = (1L << 15), + BackfaceVisibilityChange = (1L << 16), ChildrenTransformChange = (1L << 17), DisplayChange = (1L << 18), BackgroundColorChange = (1L << 19), - ParentChange = (1L << 20), - DistributesOpacityChange = (1L << 21) + + DistributesOpacityChange = (1L << 20) }; // the compositor lets us special-case images and colors, so we try to do so - enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType}; + enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType, MediaContentType}; GraphicsLayerQtImpl(GraphicsLayerQt* newLayer); virtual ~GraphicsLayerQtImpl(); @@ -149,10 +156,6 @@ public: // or ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP) void flushChanges(bool recursive = true, bool forceTransformUpdate = false); - // optimization: when we have an animation running on an element with no contents, that has child-elements with contents, - // ALL of them have to have ItemCoordinateCache and not DeviceCoordinateCache - void adjustCachingRecursively(bool animationIsRunning); - // optimization: returns true if this or an ancestor has a transform animation running. // this enables us to use ItemCoordinatesCache while the animation is running, otherwise we have to recache for every frame bool isTransformAnimationRunning() const; @@ -161,6 +164,9 @@ public slots: // we need to notify the client (aka the layer compositor) when the animation actually starts void notifyAnimationStarted(); + // we notify WebCore of a layer changed asynchronously; otherwise we end up calling flushChanges too often. + void notifySyncRequired(); + signals: // optimization: we don't want to use QTimer::singleShot void notifyAnimationStartedAsync(); @@ -179,6 +185,7 @@ public: bool updateAll; QColor contentsBackgroundColor; QColor backgroundColor; + QWeakPointer<QGraphicsObject> mediaLayer; StaticContentType contentType; float opacity; ContentData() @@ -196,7 +203,9 @@ public: int m_changeMask; QSizeF m_size; +#ifndef QT_NO_ANIMATION QList<QWeakPointer<QAbstractAnimation> > m_animations; +#endif QTimer m_suspendTimer; struct State { @@ -227,7 +236,9 @@ public: } } m_state; +#ifndef QT_NO_ANIMATION friend class AnimationQtBase; +#endif }; GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer) @@ -245,7 +256,7 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer) setEnabled(true); // we'll set the cache when we know what's going on - setCacheMode(NoCache); + setCacheMode(ItemCoordinateCache); connect(this, SIGNAL(notifyAnimationStartedAsync()), this, SLOT(notifyAnimationStarted()), Qt::QueuedConnection); } @@ -263,26 +274,13 @@ GraphicsLayerQtImpl::~GraphicsLayerQtImpl() item->setParentItem(0); } } - + +#ifndef QT_NO_ANIMATION // we do, however, own the animations... for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_animations.begin(); it != m_animations.end(); ++it) if (QAbstractAnimation* anim = it->data()) delete anim; -} - -void GraphicsLayerQtImpl::adjustCachingRecursively(bool animationIsRunning) -{ - // optimization: we make sure all our children have ItemCoordinateCache - - // otherwise we end up re-rendering them during the animation - const QList<QGraphicsItem*> children = childItems(); - - for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it) { - if (QGraphicsItem* item = *it) - if (GraphicsLayerQtImpl* layer = qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject())) { - if (layer->m_layer->drawsContent() && layer->m_currentContent.contentType == HTMLContentType) - layer->setCacheMode(animationIsRunning ? QGraphicsItem::ItemCoordinateCache : QGraphicsItem::DeviceCoordinateCache); - } - } +#endif } void GraphicsLayerQtImpl::updateTransform() @@ -307,29 +305,26 @@ QTransform GraphicsLayerQtImpl::computeTransform(const TransformationMatrix& bas // this has to do with how WebCore implements -webkit-perspective and -webkit-perspective-origin, which are the CSS // attribute that call setChildrenTransform QPointF offset = -pos() - boundingRect().bottomRight() / 2; - const GraphicsLayerQtImpl* ancestor = this; - while ((ancestor = qobject_cast<GraphicsLayerQtImpl*>(ancestor->parentObject()))) { + + for (const GraphicsLayerQtImpl* ancestor = this; (ancestor = qobject_cast<GraphicsLayerQtImpl*>(ancestor->parentObject())); ) { if (!ancestor->m_state.childrenTransform.isIdentity()) { - offset += ancestor->boundingRect().bottomRight() / 2; + const QPointF offset = mapFromItem(ancestor, QPointF(ancestor->m_size.width() / 2, ancestor->m_size.height() / 2)); computedTransform .translate(offset.x(), offset.y()) .multLeft(ancestor->m_state.childrenTransform) .translate(-offset.x(), -offset.y()); break; } - offset -= ancestor->pos(); } - computedTransform.multLeft(baseTransform); - // webkit has relative-to-size originPoint, graphics-view has a pixel originPoint, here we convert // we have to manage this ourselves because QGraphicsView's transformOrigin is incompatible const qreal originX = m_state.anchorPoint.x() * m_size.width(); const qreal originY = m_state.anchorPoint.y() * m_size.height(); - computedTransform = TransformationMatrix() - .translate(originX, originY) - .multiply(computedTransform) - .translate(-originX, -originY); + computedTransform + .translate3d(originX, originY, m_state.anchorPoint.z()) + .multLeft(baseTransform) + .translate3d(-originX, -originY, -m_state.anchorPoint.z()); // now we project to 2D return QTransform(computedTransform); @@ -353,6 +348,7 @@ QPainterPath GraphicsLayerQtImpl::opaqueArea() const else { if (m_state.contentsOpaque || (m_currentContent.contentType == ColorContentType && m_currentContent.contentsBackgroundColor.alpha() == 0xff) + || (m_currentContent.contentType == MediaContentType) || (m_currentContent.contentType == PixmapContentType && !m_currentContent.pixmap.hasAlpha())) { painterPath.addRect(m_state.contentsRect); @@ -369,14 +365,14 @@ QRectF GraphicsLayerQtImpl::boundingRect() const void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { if (m_currentContent.backgroundColor.isValid()) - painter->fillRect(option->exposedRect, QColor(m_currentContent.backgroundColor)); + painter->fillRect(option->rect, QColor(m_currentContent.backgroundColor)); switch (m_currentContent.contentType) { case HTMLContentType: if (m_state.drawsContent) { // this is the expensive bit. we try to minimize calls to this area by proper caching GraphicsContext gc(painter); - m_layer->paintGraphicsLayerContents(gc, option->exposedRect.toAlignedRect()); + m_layer->paintGraphicsLayerContents(gc, option->rect); } break; case PixmapContentType: @@ -385,19 +381,25 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte case ColorContentType: painter->fillRect(m_state.contentsRect, m_currentContent.contentsBackgroundColor); break; + case MediaContentType: + // we don't need to paint anything: we have a QGraphicsItem from the media element + break; } } -void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask) +void GraphicsLayerQtImpl::notifySyncRequired() { - Q_ASSERT(this); - - m_changeMask |= changeMask; - if (m_layer->client()) m_layer->client()->notifySyncRequired(m_layer); } +void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask) +{ + m_changeMask |= changeMask; + static QMetaMethod syncMethod = staticMetaObject.method(staticMetaObject.indexOfMethod("notifySyncRequired()")); + syncMethod.invoke(this, Qt::QueuedConnection); +} + void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform) { // this is the bulk of the work. understanding what the compositor is trying to achieve, @@ -433,7 +435,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform w->setParentItem(this); for (QSet<QGraphicsItem*>::const_iterator it = childrenToRemove.begin(); it != childrenToRemove.end(); ++it) - if (QGraphicsItem* w = *it) + if (GraphicsLayerQtImpl* w = qobject_cast<GraphicsLayerQtImpl*>((*it)->toGraphicsObject())) w->setParentItem(0); // children are ordered by z-value, let graphics-view know. @@ -450,7 +452,6 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform if (m_layer->maskLayer()) { if (GraphicsLayerQtImpl* mask = qobject_cast<GraphicsLayerQtImpl*>(m_layer->maskLayer()->platformLayer()->toGraphicsObject())) { mask->m_maskEffect = new MaskEffectQt(this, mask); - mask->setCacheMode(NoCache); setGraphicsEffect(mask->m_maskEffect.data()); } } @@ -465,11 +466,11 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform m_size = QSizeF(m_layer->size().width(), m_layer->size().height()); } } - // FIXME: this is a hack, due to a probable QGraphicsScene bug when rapidly modifying the perspective // but without this line we get graphic artifacts if ((m_changeMask & ChildrenTransformChange) && m_state.childrenTransform != m_layer->childrenTransform()) - scene()->update(); + if (scene()) + scene()->update(); if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange)) { // due to the differences between the way WebCore handles transforms and the way Qt handles transforms, @@ -483,11 +484,19 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform update(); setFlag(ItemHasNoContents, false); + // no point in caching a directly composited pixmap into another pixmap + setCacheMode(NoCache); + + break; + case MediaContentType: + setFlag(ItemHasNoContents, true); + setCacheMode(NoCache); + m_pendingContent.mediaLayer.data()->setParentItem(this); break; case ColorContentType: // no point in caching a solid-color rectangle - setCacheMode(m_layer->maskLayer() ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache); + setCacheMode(NoCache); if (m_pendingContent.contentType != m_currentContent.contentType || m_pendingContent.contentsBackgroundColor != m_currentContent.contentsBackgroundColor) update(); m_state.drawsContent = false; @@ -500,19 +509,11 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform case HTMLContentType: if (m_pendingContent.contentType != m_currentContent.contentType) update(); - if (!m_state.drawsContent && m_layer->drawsContent()) + if (!m_state.drawsContent && m_layer->drawsContent()) { update(); - if (m_layer->drawsContent() && !m_maskEffect) { - const QGraphicsItem::CacheMode mewCacheMode = isTransformAnimationRunning() ? ItemCoordinateCache : DeviceCoordinateCache; - - // optimization: QGraphicsItem doesn't always perform this test - if (mewCacheMode != cacheMode()) - setCacheMode(mewCacheMode); - - // HTML content: we want to use exposedRect so we don't use WebCore rendering if we don't have to - setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true); - } - else + if (m_layer->drawsContent() && !m_maskEffect) + setCacheMode(ItemCoordinateCache); + } else if (!m_layer->drawsContent()) setCacheMode(NoCache); setFlag(ItemHasNoContents, !m_layer->drawsContent()); @@ -520,7 +521,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform } } - if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity()) + if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity() && !m_opacityAnimationRunning) setOpacity(m_layer->opacity()); if (m_changeMask & ContentsRectChange) { @@ -569,6 +570,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform m_state.childrenTransform = m_layer->childrenTransform(); m_currentContent.pixmap = m_pendingContent.pixmap; m_currentContent.contentType = m_pendingContent.contentType; + m_currentContent.mediaLayer = m_pendingContent.mediaLayer; m_currentContent.backgroundColor = m_pendingContent.backgroundColor; m_currentContent.regionToUpdate |= m_pendingContent.regionToUpdate; m_currentContent.contentsBackgroundColor = m_pendingContent.contentsBackgroundColor; @@ -707,116 +709,140 @@ void GraphicsLayerQt::removeFromParent() } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setMaskLayer(GraphicsLayer* layer) +void GraphicsLayerQt::setMaskLayer(GraphicsLayer* value) { - GraphicsLayer::setMaskLayer(layer); + if (value == maskLayer()) + return; + GraphicsLayer::setMaskLayer(value); m_impl->notifyChange(GraphicsLayerQtImpl::MaskLayerChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setPosition(const FloatPoint& p) +void GraphicsLayerQt::setPosition(const FloatPoint& value) { - if (position() != p) - m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange); - GraphicsLayer::setPosition(p); + if (value == position()) + return; + GraphicsLayer::setPosition(value); + m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& p) +void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& value) { - if (anchorPoint() != p) - m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange); - GraphicsLayer::setAnchorPoint(p); + if (value == anchorPoint()) + return; + GraphicsLayer::setAnchorPoint(value); + m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setSize(const FloatSize& size) +void GraphicsLayerQt::setSize(const FloatSize& value) { - if (this->size() != size) - m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange); - GraphicsLayer::setSize(size); + if (value == size()) + return; + GraphicsLayer::setSize(value); + m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setTransform(const TransformationMatrix& t) +void GraphicsLayerQt::setTransform(const TransformationMatrix& value) { - if (!m_impl->m_transformAnimationRunning && transform() != t) - m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange); - GraphicsLayer::setTransform(t); + if (value == transform()) + return; + GraphicsLayer::setTransform(value); + m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& t) +void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& value) { - GraphicsLayer::setChildrenTransform(t); + if (value == childrenTransform()) + return; + GraphicsLayer::setChildrenTransform(value); m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenTransformChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setPreserves3D(bool b) +void GraphicsLayerQt::setPreserves3D(bool value) { - if (b != preserves3D()); - m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange); - GraphicsLayer::setPreserves3D(b); + if (value == preserves3D()) + return; + GraphicsLayer::setPreserves3D(value); + m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setMasksToBounds(bool b) +void GraphicsLayerQt::setMasksToBounds(bool value) { - GraphicsLayer::setMasksToBounds(b); + if (value == masksToBounds()) + return; + GraphicsLayer::setMasksToBounds(value); m_impl->notifyChange(GraphicsLayerQtImpl::MasksToBoundsChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setDrawsContent(bool b) +void GraphicsLayerQt::setDrawsContent(bool value) { + if (value == drawsContent()) + return; m_impl->notifyChange(GraphicsLayerQtImpl::DrawsContentChange); - GraphicsLayer::setDrawsContent(b); + GraphicsLayer::setDrawsContent(value); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setBackgroundColor(const Color& c) +void GraphicsLayerQt::setBackgroundColor(const Color& value) { + if (value == m_impl->m_pendingContent.backgroundColor) + return; + m_impl->m_pendingContent.backgroundColor = value; + GraphicsLayer::setBackgroundColor(value); m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange); - m_impl->m_pendingContent.backgroundColor = c; - GraphicsLayer::setBackgroundColor(c); } // reimp from GraphicsLayer.h void GraphicsLayerQt::clearBackgroundColor() { + if (!m_impl->m_pendingContent.backgroundColor.isValid()) + return; m_impl->m_pendingContent.backgroundColor = QColor(); - m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange); GraphicsLayer::clearBackgroundColor(); + m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setContentsOpaque(bool b) +void GraphicsLayerQt::setContentsOpaque(bool value) { + if (value == contentsOpaque()) + return; m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOpaqueChange); - GraphicsLayer::setContentsOpaque(b); + GraphicsLayer::setContentsOpaque(value); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setBackfaceVisibility(bool b) +void GraphicsLayerQt::setBackfaceVisibility(bool value) { + if (value == backfaceVisibility()) + return; + GraphicsLayer::setBackfaceVisibility(value); m_impl->notifyChange(GraphicsLayerQtImpl::BackfaceVisibilityChange); - GraphicsLayer::setBackfaceVisibility(b); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setOpacity(float o) +void GraphicsLayerQt::setOpacity(float value) { - if (!m_impl->m_opacityAnimationRunning && opacity() != o) - m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange); - GraphicsLayer::setOpacity(o); + if (value == opacity()) + return; + GraphicsLayer::setOpacity(value); + m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange); } // reimp from GraphicsLayer.h -void GraphicsLayerQt::setContentsRect(const IntRect& r) +void GraphicsLayerQt::setContentsRect(const IntRect& value) { + if (value == contentsRect()) + return; + GraphicsLayer::setContentsRect(value); m_impl->notifyChange(GraphicsLayerQtImpl::ContentsRectChange); - GraphicsLayer::setContentsRect(r); } // reimp from GraphicsLayer.h @@ -845,6 +871,19 @@ void GraphicsLayerQt::setContentsBackgroundColor(const Color& color) GraphicsLayer::setContentsBackgroundColor(color); } +void GraphicsLayerQt::setContentsToMedia(PlatformLayer* media) +{ + if (media) { + m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::MediaContentType; + m_impl->m_pendingContent.mediaLayer = media->toGraphicsObject(); + } else + m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::HTMLContentType; + + m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange); + GraphicsLayer::setContentsToMedia(media); +} + + // reimp from GraphicsLayer.h void GraphicsLayerQt::setGeometryOrientation(CompositingCoordinatesOrientation orientation) { @@ -913,18 +952,18 @@ static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, q // we want the timing function to be as close as possible to what the web-developer intended, so we're using the same function used by WebCore when compositing is disabled // Using easing-curves would probably work for some of the cases, but wouldn't really buy us anything as we'd have to convert the bezier function back to an easing curve -static inline qreal applyTimingFunction(const TimingFunction& timingFunction, qreal progress, int duration) -{ - if (timingFunction.type() == LinearTimingFunction) - return progress; - if (timingFunction.type() == CubicBezierTimingFunction) { - return solveCubicBezierFunction(timingFunction.x1(), - timingFunction.y1(), - timingFunction.x2(), - timingFunction.y2(), - double(progress), double(duration) / 1000); - } +static inline qreal applyTimingFunction(const TimingFunction& timingFunction, qreal progress, double duration) +{ + if (timingFunction.type() == LinearTimingFunction) return progress; + if (timingFunction.type() == CubicBezierTimingFunction) { + return solveCubicBezierFunction(timingFunction.x1(), + timingFunction.y1(), + timingFunction.x2(), + timingFunction.y2(), + double(progress), double(duration) / 1000); + } + return progress; } // helper functions to safely get a value out of WebCore's AnimationValue* @@ -943,6 +982,7 @@ static void webkitAnimationToQtAnimationValue(const AnimationValue* animationVal realValue = animationValue ? static_cast<const FloatAnimationValue*>(animationValue)->value() : 0; } +#ifndef QT_NO_ANIMATION // we put a bit of the functionality in a base class to allow casting and to save some code size class AnimationQtBase : public QAbstractAnimation { public: @@ -953,7 +993,9 @@ public: , m_duration(anim->duration() * 1000) , m_isAlternate(anim->direction() == Animation::AnimationDirectionAlternate) , m_webkitPropertyID(values.property()) + , m_webkitAnimation(anim) , m_keyframesName(name) + , m_fillsForwards(false) { } @@ -973,7 +1015,11 @@ public: int m_duration; bool m_isAlternate; AnimatedPropertyID m_webkitPropertyID; + + // we might need this in case the same animation is added again (i.e. resumed by WebCore) + const Animation* m_webkitAnimation; QString m_keyframesName; + bool m_fillsForwards; }; // we'd rather have a templatized QAbstractAnimation than QPropertyAnimation / QVariantAnimation; @@ -992,6 +1038,8 @@ public: KeyframeValueQt<T> keyframeValue; if (animationValue->timingFunction()) keyframeValue.timingFunction = *animationValue->timingFunction(); + else + keyframeValue.timingFunction = anim->timingFunction(); webkitAnimationToQtAnimationValue(animationValue, keyframeValue.value); m_keyframeValues[animationValue->keyTime()] = keyframeValue; } @@ -1028,7 +1076,7 @@ protected: typename QMap<qreal, KeyframeValueQt<T> >::iterator it2 = it+1; if (it2 == m_keyframeValues.end()) - it2 = m_keyframeValues.begin(); + it2 = it; const KeyframeValueQt<T>& fromKeyframe = it.value(); const KeyframeValueQt<T>& toKeyframe = it2.value(); @@ -1040,7 +1088,7 @@ protected: // we can now process the progress and apply the frame progress = (!progress || progress == 1 || it.key() == it2.key()) ? progress - : applyTimingFunction(timingFunc, (progress - it.key()) / (it2.key() - it.key()), duration() / 1000); + : applyTimingFunction(timingFunc, (progress - it.key()) / (it2.key() - it.key()), duration()); applyFrame(fromValue, toValue, progress); } @@ -1056,10 +1104,10 @@ public: ~TransformAnimationQt() { - // this came up during the compositing/animation LayoutTests - // when the animation dies, the transform has to go back to default - if (m_layer) - m_layer.data()->updateTransform(); + if (m_fillsForwards) + setCurrentTime(1); + else if (m_layer && m_layer.data()->m_layer) + m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform()); } // the idea is that we let WebCore manage the transform-operations @@ -1077,15 +1125,29 @@ public: sourceOperations.apply(m_boxSize, sourceMatrix); transformMatrix = m_sourceMatrix; transformMatrix.blend(sourceMatrix, 1 - progress); - } else if (targetOperations.size() != sourceOperations.size()) { - transformMatrix = m_sourceMatrix; - targetOperations.apply(m_boxSize, transformMatrix); - transformMatrix.blend(m_sourceMatrix, progress); } else { - for (size_t i = 0; i < targetOperations.size(); ++i) - targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize); + bool validTransformLists = true; + const int sourceOperationCount = sourceOperations.size(); + if (sourceOperationCount) { + if (targetOperations.size() != sourceOperationCount) + validTransformLists = false; + else + for (size_t j = 0; j < sourceOperationCount && validTransformLists; ++j) + if (!sourceOperations.operations()[j]->isSameType(*targetOperations.operations()[j])) + validTransformLists = false; + } + + if (validTransformLists) { + for (size_t i = 0; i < targetOperations.size(); ++i) + targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize); + } else { + targetOperations.apply(m_boxSize, transformMatrix); + transformMatrix.blend(m_sourceMatrix, progress); + } } m_layer.data()->setBaseTransform(transformMatrix); + if (m_fillsForwards) + m_layer.data()->m_layer->setTransform(m_layer.data()->m_baseTransform); } virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) @@ -1100,10 +1162,8 @@ public: if (newState == QAbstractAnimation::Running) { m_sourceMatrix = m_layer.data()->m_layer->transform(); m_layer.data()->m_transformAnimationRunning = true; - m_layer.data()->adjustCachingRecursively(true); - } else { + } else if (newState == QAbstractAnimation::Stopped) { m_layer.data()->m_transformAnimationRunning = false; - m_layer.data()->adjustCachingRecursively(false); } } @@ -1117,9 +1177,25 @@ public: { } + ~OpacityAnimationQt() + { + if (m_fillsForwards) + setCurrentTime(1); + else if (m_layer && m_layer.data()->m_layer) + m_layer.data()->setOpacity(m_layer.data()->m_layer->opacity()); + } virtual void applyFrame(const qreal& fromValue, const qreal& toValue, qreal progress) { - m_layer.data()->setOpacity(qMin<qreal>(qMax<qreal>(fromValue + (toValue-fromValue)*progress, 0), 1)); + qreal opacity = qBound(qreal(0), fromValue + (toValue-fromValue)*progress, qreal(1)); + + // FIXME: this is a hack, due to a probable QGraphicsScene bug. + // Without this the opacity change doesn't always have immediate effect. + if (!m_layer.data()->opacity() && opacity) + m_layer.data()->scene()->update(); + + m_layer.data()->setOpacity(opacity); + if (m_fillsForwards) + m_layer.data()->m_layer->setOpacity(opacity); } virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) @@ -1136,33 +1212,51 @@ bool GraphicsLayerQt::addAnimation(const KeyframeValueList& values, const IntSiz if (!anim->duration() || !anim->iterationCount()) return false; - QAbstractAnimation* newAnim; + AnimationQtBase* newAnim = 0; - switch (values.property()) { - case AnimatedPropertyOpacity: - newAnim = new OpacityAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName); - break; - case AnimatedPropertyWebkitTransform: - newAnim = new TransformAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName); - break; - default: - return false; + // fixed: we might already have the Qt animation object associated with this WebCore::Animation object + for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) { + if (*it) { + AnimationQtBase* curAnimation = static_cast<AnimationQtBase*>(it->data()); + if (curAnimation && curAnimation->m_webkitAnimation == anim) + newAnim = curAnimation; + } } - // we make sure WebCore::Animation and QAnimation are on the same terms - newAnim->setLoopCount(anim->iterationCount()); - m_impl->m_animations.append(QWeakPointer<QAbstractAnimation>(newAnim)); - QObject::connect(&m_impl->m_suspendTimer, SIGNAL(timeout()), newAnim, SLOT(resume())); - timeOffset += anim->delay(); + if (!newAnim) { + switch (values.property()) { + case AnimatedPropertyOpacity: + newAnim = new OpacityAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName); + break; + case AnimatedPropertyWebkitTransform: + newAnim = new TransformAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName); + break; + default: + return false; + } + + // we make sure WebCore::Animation and QAnimation are on the same terms + newAnim->setLoopCount(anim->iterationCount()); + newAnim->m_fillsForwards = anim->fillsForwards(); + m_impl->m_animations.append(QWeakPointer<QAbstractAnimation>(newAnim)); + QObject::connect(&m_impl->m_suspendTimer, SIGNAL(timeout()), newAnim, SLOT(resume())); + } // flush now or flicker... m_impl->flushChanges(false); - if (timeOffset) - QTimer::singleShot(timeOffset * 1000, newAnim, SLOT(start())); + // when fill-mode is backwards/both, we set the value to 0 before the delay takes place + if (anim->fillsBackwards()) + newAnim->setCurrentTime(0); + + if (anim->delay()) + QTimer::singleShot(anim->delay() * 1000, newAnim, SLOT(start())); else newAnim->start(); + // we synchronize the animation's clock to WebCore's timeOffset + newAnim->setCurrentTime(timeOffset * 1000); + // we don't need to manage the animation object's lifecycle: // WebCore would call removeAnimations when it's time to delete. @@ -1204,8 +1298,11 @@ void GraphicsLayerQt::pauseAnimation(const String& name, double timeOffset) continue; AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data()); - if (anim && anim->m_keyframesName == QString(name)) - QTimer::singleShot(timeOffset * 1000, anim, SLOT(pause())); + if (anim && anim->m_keyframesName == QString(name)) { + // we synchronize the animation's clock to WebCore's timeOffset + anim->setCurrentTime(timeOffset * 1000); + anim->pause(); + } } } @@ -1235,6 +1332,7 @@ void GraphicsLayerQt::resumeAnimations() } } +#endif // QT_NO_ANIMATION } #include <GraphicsLayerQt.moc> diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h index 3a53bd9..9e5832f 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.h +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.h @@ -63,13 +63,16 @@ public: virtual void setBackfaceVisibility(bool b); virtual void setOpacity(float opacity); virtual void setContentsRect(const IntRect& r); +#ifndef QT_NO_ANIMATION virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double timeOffset); virtual void removeAnimationsForProperty(AnimatedPropertyID); virtual void removeAnimationsForKeyframes(const String& keyframesName); virtual void pauseAnimation(const String& keyframesName, double timeOffset); virtual void suspendAnimations(double time); virtual void resumeAnimations(); +#endif // QT_NO_ANIMATION virtual void setContentsToImage(Image*); + virtual void setContentsToMedia(PlatformLayer*); virtual void setContentsBackgroundColor(const Color&); virtual void setGeometryOrientation(CompositingCoordinatesOrientation orientation); virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation); diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index d831566..4b85a18 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -28,11 +28,11 @@ #include "config.h" #include "ImageBuffer.h" -#include "CString.h" #include "GraphicsContext.h" #include "ImageData.h" #include "MIMETypeRegistry.h" #include "StillImageQt.h" +#include <wtf/text/CString.h> #include <QBuffer> #include <QColor> diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 18e7f08..b48b278 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -57,7 +57,7 @@ ImageDecoderQt::~ImageDecoderQt() void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) { - if (m_failed) + if (failed()) return; // No progressive loading possible @@ -75,7 +75,7 @@ void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size()); m_buffer.set(new QBuffer); m_buffer->setData(imageData); - m_buffer->open(QBuffer::ReadOnly); + m_buffer->open(QIODevice::ReadOnly | QIODevice::Unbuffered); m_reader.set(new QImageReader(m_buffer.get(), m_format)); // This will force the JPEG decoder to use JDCT_IFAST @@ -106,9 +106,8 @@ size_t ImageDecoderQt::frameCount() forceLoadEverything(); else m_frameBufferCache.resize(imageCount); - } else { + } else m_frameBufferCache.resize(1); - } } return m_frameBufferCache.size(); @@ -116,8 +115,21 @@ size_t ImageDecoderQt::frameCount() int ImageDecoderQt::repetitionCount() const { - if (m_reader && m_reader->supportsAnimation()) - m_repetitionCount = qMax(0, m_reader->loopCount()); + if (m_reader && m_reader->supportsAnimation()) { + m_repetitionCount = m_reader->loopCount(); + + // Qt and WebCore have a incompatible understanding of + // the loop count and we can not completely map everything. + // Qt | WebCore | description + // -1 | 0 | infinite animation + // 0 | cAnimationLoopOnce | show every frame once + // n | n | no idea if that is supported + // n/a | cAnimationNone | show only the first frame + if (m_repetitionCount == -1) + m_repetitionCount = 0; + else if (m_repetitionCount == 0) + m_repetitionCount = cAnimationLoopOnce; + } return m_repetitionCount; } @@ -133,7 +145,7 @@ RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) // yet how many images we are going to have and need to // find that out now. size_t count = m_frameBufferCache.size(); - if (!m_failed && !count) { + if (!failed() && !count) { internalDecodeSize(); count = frameCount(); } @@ -157,8 +169,10 @@ void ImageDecoderQt::internalDecodeSize() // If we have a QSize() something failed QSize size = m_reader->size(); - if (size.isEmpty()) - return failRead(); + if (size.isEmpty()) { + setFailed(); + return clearPointers(); + } setSize(size.width(), size.height()); } @@ -169,26 +183,33 @@ void ImageDecoderQt::internalReadImage(size_t frameIndex) if (m_reader->supportsAnimation()) m_reader->jumpToImage(frameIndex); - else if (frameIndex != 0) - return failRead(); + else if (frameIndex) { + setFailed(); + return clearPointers(); + } - internalHandleCurrentImage(frameIndex); + if (!internalHandleCurrentImage(frameIndex)) + setFailed(); // Attempt to return some memory - for (int i = 0; i < m_frameBufferCache.size(); ++i) + for (int i = 0; i < m_frameBufferCache.size(); ++i) { if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete) return; + } - m_reader.clear(); - m_buffer.clear(); + clearPointers(); } -void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) +bool ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) { // Now get the QImage from Qt and place it in the RGBA32Buffer QImage img; - if (!m_reader->read(&img)) - return failRead(); + if (!m_reader->read(&img)) { + frameCount(); + repetitionCount(); + clearPointers(); + return false; + } // now into the RGBA32Buffer - even if the image is not QSize imageSize = img.size(); @@ -197,6 +218,7 @@ void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) buffer->setStatus(RGBA32Buffer::FrameComplete); buffer->setDuration(m_reader->nextImageDelay()); buffer->setDecodedImage(img); + return true; } // The QImageIOHandler is not able to tell us how many frames @@ -204,8 +226,8 @@ void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) // increasing the m_frameBufferCache by one and try to parse // the image. We stop when QImage::read fails and then need // to resize the m_frameBufferCache to the final size and update -// the m_failed. In case we failed to decode the first image -// we want to keep m_failed set to true. +// the failed bit. If we failed to decode the first image +// then we truly failed to decode, otherwise we're OK. // TODO: Do not increment the m_frameBufferCache.size() by one but more than one void ImageDecoderQt::forceLoadEverything() @@ -214,20 +236,19 @@ void ImageDecoderQt::forceLoadEverything() do { m_frameBufferCache.resize(++imageCount); - internalHandleCurrentImage(imageCount - 1); - } while (!m_failed); + } while (internalHandleCurrentImage(imageCount - 1)); // If we failed decoding the first image we actually - // have no images and need to keep m_failed set to - // true otherwise we want to reset it and forget about + // have no images and need to set the failed bit. + // Otherwise, we want to forget about // the last attempt to decode a image. m_frameBufferCache.resize(imageCount - 1); - m_failed = imageCount == 1; + if (imageCount == 1) + setFailed(); } -void ImageDecoderQt::failRead() +void ImageDecoderQt::clearPointers() { - setFailed(); m_reader.clear(); m_buffer.clear(); } diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index be9a9b0..ceef884 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -61,9 +61,9 @@ private: private: void internalDecodeSize(); void internalReadImage(size_t); - void internalHandleCurrentImage(size_t); + bool internalHandleCurrentImage(size_t); void forceLoadEverything(); - void failRead(); + void clearPointers(); private: QByteArray m_format; diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index 3274db5..21e670c 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -23,23 +23,25 @@ #include <limits> -#include "CString.h" #include "FrameView.h" #include "GraphicsContext.h" +#include "MIMETypeRegistry.h" #include "NotImplemented.h" #include "TimeRanges.h" #include "Widget.h" #include <wtf/HashSet.h> +#include <wtf/text/CString.h> #include <QDebug> +#include <QEvent> +#include <QMetaEnum> #include <QPainter> #include <QWidget> -#include <QMetaEnum> #include <QUrl> -#include <QEvent> -#include <phonon/path.h> #include <phonon/audiooutput.h> +#include <phonon/backendcapabilities.h> +#include <phonon/path.h> #include <phonon/mediaobject.h> #include <phonon/videowidget.h> @@ -143,15 +145,62 @@ MediaPlayerPrivate::~MediaPlayerPrivate() m_mediaObject = 0; } -void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&) +HashSet<String>& MediaPlayerPrivate::supportedTypesCache() { - notImplemented(); + static HashSet<String> supportedTypes; + if (!supportedTypes.isEmpty()) + return supportedTypes; + + // FIXME: we should rebuild the MIME type cache every time the backend is changed, + // however, this would have no effect on MIMETypeRegistry anyway, because it + // pulls this data only once. + + QStringList types = Phonon::BackendCapabilities::availableMimeTypes(); + foreach (const QString& type, types) { + QString first = type.split(QLatin1Char('/')).at(0); + + // We're only interested in types which are not supported by WebCore itself. + if (first != QLatin1String("video") + && first != QLatin1String("audio") + && first != QLatin1String("application")) + continue; + if (MIMETypeRegistry::isSupportedNonImageMIMEType(type)) + continue; + + supportedTypes.add(String(type)); + } + + // These formats are supported by GStreamer, but not correctly advertised. + if (supportedTypes.contains(String("video/x-h264")) + || supportedTypes.contains(String("audio/x-m4a"))) { + supportedTypes.add(String("video/mp4")); + supportedTypes.add(String("audio/aac")); + } + + if (supportedTypes.contains(String("video/x-theora"))) + supportedTypes.add(String("video/ogg")); + + if (supportedTypes.contains(String("audio/x-vorbis"))) + supportedTypes.add(String("audio/ogg")); + + if (supportedTypes.contains(String("audio/x-wav"))) + supportedTypes.add(String("audio/wav")); + + return supportedTypes; } -MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String&, const String&) +void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) { - // FIXME: do the real thing - notImplemented(); + types = supportedTypesCache(); +} + +MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) +{ + if (type.isEmpty()) + return MediaPlayer::IsNotSupported; + + if (supportedTypesCache().contains(type)) + return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported; return MediaPlayer::IsNotSupported; } diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h index e7630a1..ff6a01c 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h @@ -132,6 +132,7 @@ namespace WebCore { static void getSupportedTypes(HashSet<String>&); static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); + static HashSet<String>& supportedTypesCache(); static bool isAvailable() { return true; } void updateStates(); diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp new file mode 100644 index 0000000..bdac2a4 --- /dev/null +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -0,0 +1,571 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "MediaPlayerPrivateQt.h" + +#include "FrameLoaderClientQt.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLMediaElement.h" +#include "HTMLVideoElement.h" +#include "TimeRanges.h" +#include "Widget.h" +#include "qwebframe.h" +#include "qwebpage.h" + +#include <QGraphicsScene> +#include <QGraphicsVideoItem> +#include <QMediaPlayerControl> +#include <QMediaService> +#include <QNetworkAccessManager> +#include <QNetworkCookieJar> +#include <QNetworkRequest> +#include <QPainter> +#include <QPoint> +#include <QRect> +#include <QTime> +#include <QTimer> +#include <QUrl> +#include <limits> +#include <wtf/HashSet.h> +#include <wtf/text/CString.h> + +using namespace WTF; + +namespace WebCore { + +MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) +{ + return new MediaPlayerPrivate(player); +} + +void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) +{ + registrar(create, getSupportedTypes, supportsType); +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet<String> &supported) +{ + QStringList types = QMediaPlayer::supportedMimeTypes(); + + for (int i = 0; i < types.size(); i++) { + QString mime = types.at(i); + if (mime.startsWith("audio/") || mime.startsWith("video/")) + supported.add(mime); + } +} + +MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& mime, const String& codec) +{ + if (!mime.startsWith("audio/") && !mime.startsWith("video/")) + return MediaPlayer::IsNotSupported; + + if (QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMultimedia::ProbablySupported) + return MediaPlayer::IsSupported; + + return MediaPlayer::MayBeSupported; +} + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) + : m_player(player) + , m_mediaPlayer(new QMediaPlayer) + , m_mediaPlayerControl(0) + , m_videoItem(new QGraphicsVideoItem) + , m_videoScene(new QGraphicsScene) + , m_networkState(MediaPlayer::Empty) + , m_readyState(MediaPlayer::HaveNothing) + , m_isVisible(false) + , m_isSeeking(false) + , m_composited(false) + , m_queuedSeek(-1) +{ + m_videoItem->setMediaObject(m_mediaPlayer); + m_videoScene->addItem(m_videoItem); + + // Signal Handlers + connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SLOT(stateChanged(QMediaPlayer::State))); + connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), + this, SLOT(handleError(QMediaPlayer::Error))); + connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)), + this, SLOT(durationChanged(qint64))); + connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)), + this, SLOT(positionChanged(qint64))); + connect(m_mediaPlayer, SIGNAL(volumeChanged(int)), + this, SLOT(volumeChanged(int))); + connect(m_mediaPlayer, SIGNAL(mutedChanged(bool)), + this, SLOT(mutedChanged(bool))); + connect(m_videoScene, SIGNAL(changed(QList<QRectF>)), + this, SLOT(repaint())); + connect(m_videoItem, SIGNAL(nativeSizeChanged(QSizeF)), + this, SLOT(nativeSizeChanged(QSizeF))); + + // Grab the player control + QMediaService* service = m_mediaPlayer->service(); + if (service) { + m_mediaPlayerControl = qobject_cast<QMediaPlayerControl *>( + service->control(QMediaPlayerControl_iid)); + } +} + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ + delete m_mediaPlayer; + delete m_videoScene; +} + +bool MediaPlayerPrivate::hasVideo() const +{ + return m_mediaPlayer->isVideoAvailable(); +} + +bool MediaPlayerPrivate::hasAudio() const +{ + return true; +} + +void MediaPlayerPrivate::load(const String& url) +{ + // We are now loading + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + + // And we don't have any data yet + if (m_readyState != MediaPlayer::HaveNothing) { + m_readyState = MediaPlayer::HaveNothing; + m_player->readyStateChanged(); + } + + const QUrl rUrl = QUrl(QString(url)); + const QString scheme = rUrl.scheme().toLower(); + + // Grab the client media element + HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_player->mediaPlayerClient()); + + // Construct the media content with a network request if the resource is http[s] + if (scheme == "http" || scheme == "https") { + QNetworkRequest request = QNetworkRequest(rUrl); + + // Grab the current document + Document* document = element->document(); + if (!document) + document = element->ownerDocument(); + + // Grab the frame and network manager + Frame* frame = document ? document->frame() : 0; + FrameLoaderClientQt* frameLoader = frame ? static_cast<FrameLoaderClientQt*>(frame->loader()->client()) : 0; + QNetworkAccessManager* manager = frameLoader ? frameLoader->webFrame()->page()->networkAccessManager() : 0; + + if (document && manager) { + // Set the cookies + QNetworkCookieJar* jar = manager->cookieJar(); + QList<QNetworkCookie> cookies = jar->cookiesForUrl(rUrl); + + // Don't set the header if there are no cookies. + // This prevents a warning from being emitted. + if (!cookies.isEmpty()) + request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies)); + + // Set the refferer, but not when requesting insecure content from a secure page + QUrl documentUrl = QUrl(QString(document->documentURI())); + if (documentUrl.scheme().toLower() == "http" || scheme == "https") + request.setRawHeader("Referer", documentUrl.toEncoded()); + + // Set the user agent + request.setRawHeader("User-Agent", frameLoader->userAgent(rUrl).utf8().data()); + } + + m_mediaPlayer->setMedia(QMediaContent(request)); + } else { + // Otherwise, just use the URL + m_mediaPlayer->setMedia(QMediaContent(rUrl)); + } + + // Set the current volume and mute status + // We get these from the element, rather than the player, in case we have + // transitioned from a media engine which doesn't support muting, to a media + // engine which does. + m_mediaPlayer->setMuted(element->muted()); + m_mediaPlayer->setVolume(static_cast<int>(element->volume() * 100.0)); +} + +void MediaPlayerPrivate::cancelLoad() +{ + m_mediaPlayer->setMedia(QMediaContent()); + updateStates(); +} + +void MediaPlayerPrivate::play() +{ + if (m_mediaPlayer->state() != QMediaPlayer::PlayingState) + m_mediaPlayer->play(); +} + +void MediaPlayerPrivate::pause() +{ + if (m_mediaPlayer->state() == QMediaPlayer::PlayingState) + m_mediaPlayer->pause(); +} + +bool MediaPlayerPrivate::paused() const +{ + return (m_mediaPlayer->state() != QMediaPlayer::PlayingState); +} + +void MediaPlayerPrivate::seek(float position) +{ + if (!m_mediaPlayer->isSeekable()) + return; + + if (m_mediaPlayerControl && !m_mediaPlayerControl->availablePlaybackRanges().contains(position * 1000)) + return; + + if (m_isSeeking) + return; + + if (position > duration()) + position = duration(); + + // Seeking is most reliable when we're paused. + // Webkit will try to pause before seeking, but due to the asynchronous nature + // of the backend, the player may not actually be paused yet. + // In this case, we should queue the seek and wait until pausing has completed + // before attempting to seek. + if (m_mediaPlayer->state() == QMediaPlayer::PlayingState) { + m_mediaPlayer->pause(); + m_isSeeking = true; + m_queuedSeek = static_cast<qint64>(position * 1000); + + // Set a timeout, so that in the event that we don't get a state changed + // signal, we still attempt the seek. + QTimer::singleShot(1000, this, SLOT(queuedSeekTimeout())); + } else { + m_isSeeking = true; + m_mediaPlayer->setPosition(static_cast<qint64>(position * 1000)); + + // Set a timeout, in case we don't get a position changed signal + QTimer::singleShot(10000, this, SLOT(seekTimeout())); + } +} + +bool MediaPlayerPrivate::seeking() const +{ + return m_isSeeking; +} + +float MediaPlayerPrivate::duration() const +{ + if (m_readyState < MediaPlayer::HaveMetadata) + return 0.0f; + + float duration = m_mediaPlayer->duration() / 1000.0f; + + // We are streaming + if (duration <= 0.0f) + duration = std::numeric_limits<float>::infinity(); + + return duration; +} + +float MediaPlayerPrivate::currentTime() const +{ + float currentTime = m_mediaPlayer->position() / 1000.0f; + return currentTime; +} + +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const +{ + RefPtr<TimeRanges> buffered = TimeRanges::create(); + + if (!m_mediaPlayerControl) + return buffered; + + QMediaTimeRange playbackRanges = m_mediaPlayerControl->availablePlaybackRanges(); + + foreach (const QMediaTimeInterval interval, playbackRanges.intervals()) { + float rangeMin = static_cast<float>(interval.start()) / 1000.0f; + float rangeMax = static_cast<float>(interval.end()) / 1000.0f; + buffered->add(rangeMin, rangeMax); + } + + return buffered.release(); +} + +float MediaPlayerPrivate::maxTimeSeekable() const +{ + if (!m_mediaPlayerControl) + return 0; + + return static_cast<float>(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f; +} + +unsigned MediaPlayerPrivate::bytesLoaded() const +{ + unsigned percentage = m_mediaPlayer->bufferStatus(); + + if (percentage == 100) { + if (m_networkState != MediaPlayer::Idle) { + m_networkState = MediaPlayer::Idle; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::HaveEnoughData) { + m_readyState = MediaPlayer::HaveEnoughData; + m_player->readyStateChanged(); + } + } + + QLatin1String bytesLoadedKey("bytes-loaded"); + if (m_mediaPlayer->availableExtendedMetaData().contains(bytesLoadedKey)) + return m_mediaPlayer->extendedMetaData(bytesLoadedKey).toInt(); + + return percentage; +} + +unsigned MediaPlayerPrivate::totalBytes() const +{ + if (m_mediaPlayer->availableMetaData().contains(QtMultimedia::Size)) + return m_mediaPlayer->metaData(QtMultimedia::Size).toInt(); + + return 100; +} + +void MediaPlayerPrivate::setRate(float rate) +{ + m_mediaPlayer->setPlaybackRate(rate); +} + +void MediaPlayerPrivate::setVolume(float volume) +{ + m_mediaPlayer->setVolume(static_cast<int>(volume * 100.0)); +} + +bool MediaPlayerPrivate::supportsMuting() const +{ + return true; +} + +void MediaPlayerPrivate::setMuted(bool muted) +{ + m_mediaPlayer->setMuted(muted); +} + +MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const +{ + return m_networkState; +} + +MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const +{ + return m_readyState; +} + +void MediaPlayerPrivate::setVisible(bool visible) +{ + m_isVisible = visible; +} + +void MediaPlayerPrivate::mediaStatusChanged(QMediaPlayer::MediaStatus) +{ + updateStates(); +} + +void MediaPlayerPrivate::handleError(QMediaPlayer::Error) +{ + updateStates(); +} + +void MediaPlayerPrivate::stateChanged(QMediaPlayer::State state) +{ + if (state != QMediaPlayer::PlayingState && m_isSeeking && m_queuedSeek >= 0) { + m_mediaPlayer->setPosition(m_queuedSeek); + m_queuedSeek = -1; + } +} + +void MediaPlayerPrivate::nativeSizeChanged(const QSizeF&) +{ + m_player->sizeChanged(); +} + +void MediaPlayerPrivate::queuedSeekTimeout() +{ + // If we haven't heard anything, assume the player is now paused + // and we can attempt the seek + if (m_isSeeking && m_queuedSeek >= 0) { + m_mediaPlayer->setPosition(m_queuedSeek); + m_queuedSeek = -1; + + // Set a timeout, in case we don't get a position changed signal + QTimer::singleShot(10000, this, SLOT(seekTimeout())); + } +} + +void MediaPlayerPrivate::seekTimeout() +{ + // If we haven't heard anything, assume the seek succeeded + if (m_isSeeking) { + m_player->timeChanged(); + m_isSeeking = false; + } +} + +void MediaPlayerPrivate::positionChanged(qint64) +{ + // Only propogate this event if we are seeking + if (m_isSeeking && m_queuedSeek == -1) { + m_player->timeChanged(); + m_isSeeking = false; + } +} + +void MediaPlayerPrivate::durationChanged(qint64) +{ + m_player->durationChanged(); +} + +void MediaPlayerPrivate::volumeChanged(int volume) +{ + m_player->volumeChanged(static_cast<float>(volume) / 100.0); +} + +void MediaPlayerPrivate::mutedChanged(bool muted) +{ + m_player->muteChanged(muted); +} + +void MediaPlayerPrivate::updateStates() +{ + // Store the old states so that we can detect a change and raise change events + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + + QMediaPlayer::MediaStatus currentStatus = m_mediaPlayer->mediaStatus(); + QMediaPlayer::Error currentError = m_mediaPlayer->error(); + + if (currentError != QMediaPlayer::NoError) { + m_readyState = MediaPlayer::HaveNothing; + if (currentError == QMediaPlayer::FormatError) + m_networkState = MediaPlayer::FormatError; + else + m_networkState = MediaPlayer::NetworkError; + } else if (currentStatus == QMediaPlayer::UnknownMediaStatus + || currentStatus == QMediaPlayer::NoMedia) { + m_networkState = MediaPlayer::Idle; + m_readyState = MediaPlayer::HaveNothing; + } else if (currentStatus == QMediaPlayer::LoadingMedia) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveNothing; + } else if (currentStatus == QMediaPlayer::LoadedMedia) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveMetadata; + } else if (currentStatus == QMediaPlayer::BufferingMedia) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveFutureData; + } else if (currentStatus == QMediaPlayer::StalledMedia) { + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::HaveCurrentData; + } else if (currentStatus == QMediaPlayer::BufferedMedia + || currentStatus == QMediaPlayer::EndOfMedia) { + m_networkState = MediaPlayer::Idle; + m_readyState = MediaPlayer::HaveEnoughData; + } else if (currentStatus == QMediaPlayer::InvalidMedia) { + m_networkState = MediaPlayer::NetworkError; + m_readyState = MediaPlayer::HaveNothing; + } + + // Log the state changes and raise the state change events + // NB: The readyStateChanged event must come before the networkStateChanged event. + // Breaking this invariant will cause the resource selection algorithm for multiple + // sources to fail. + if (m_readyState != oldReadyState) + m_player->readyStateChanged(); + + if (m_networkState != oldNetworkState) + m_player->networkStateChanged(); +} + +void MediaPlayerPrivate::setSize(const IntSize& size) +{ + if (size == m_currentSize) + return; + + m_currentSize = size; + m_videoItem->setSize(QSizeF(QSize(size))); +} + +IntSize MediaPlayerPrivate::naturalSize() const +{ + if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) + return IntSize(); + + return IntSize(m_videoItem->nativeSize().toSize()); +} + +void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_composited) + return; +#endif + if (context->paintingDisabled()) + return; + + if (!m_isVisible) + return; + + // Grab the painter and widget + QPainter* painter = context->platformContext(); + + // Render the video + m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect()); +} + +void MediaPlayerPrivate::repaint() +{ + m_player->repaint(); +} + +#if USE(ACCELERATED_COMPOSITING) +void MediaPlayerPrivate::acceleratedRenderingStateChanged() +{ + bool composited = m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player); + if (composited == m_composited) + return; + + m_composited = composited; + if (composited) + m_videoScene->removeItem(m_videoItem); + else + m_videoScene->addItem(m_videoItem); +} + +PlatformLayer* MediaPlayerPrivate::platformLayer() const +{ + return m_composited ? m_videoItem : 0; +} +#endif + +} // namespace WebCore + +#include "moc_MediaPlayerPrivateQt.cpp" diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h new file mode 100644 index 0000000..d72404c --- /dev/null +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h @@ -0,0 +1,133 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef MediaPlayerPrivateQt_h +#define MediaPlayerPrivateQt_h + +#include "MediaPlayerPrivate.h" + +#include <QMediaPlayer> +#include <QObject> + +QT_BEGIN_NAMESPACE +class QMediaPlayerControl; +class QGraphicsVideoItem; +class QGraphicsScene; +QT_END_NAMESPACE + +namespace WebCore { + +class MediaPlayerPrivate : public QObject, public MediaPlayerPrivateInterface { + + Q_OBJECT + +public: + static MediaPlayerPrivateInterface* create(MediaPlayer* player); + ~MediaPlayerPrivate(); + + static void registerMediaEngine(MediaEngineRegistrar); + static void getSupportedTypes(HashSet<String>&); + static MediaPlayer::SupportsType supportsType(const String&, const String&); + static bool isAvailable() { return true; } + + bool hasVideo() const; + bool hasAudio() 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); + + void setRate(float); + void setVolume(float); + + bool supportsMuting() const; + void setMuted(bool); + + MediaPlayer::NetworkState networkState() const; + MediaPlayer::ReadyState readyState() const; + + PassRefPtr<TimeRanges> buffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + unsigned totalBytes() const; + + void setVisible(bool); + + IntSize naturalSize() const; + void setSize(const IntSize&); + + void paint(GraphicsContext*, const IntRect&); + + bool supportsFullscreen() const { return false; } + +#if USE(ACCELERATED_COMPOSITING) + // whether accelerated rendering is supported by the media engine for the current media. + virtual bool supportsAcceleratedRendering() const { return true; } + // called when the rendering system flips the into or out of accelerated rendering mode. + virtual void acceleratedRenderingStateChanged(); + // returns an object that can be directly composited via GraphicsLayerQt (essentially a QGraphicsItem*) + virtual PlatformLayer* platformLayer() const; +#endif + +private slots: + void mediaStatusChanged(QMediaPlayer::MediaStatus); + void handleError(QMediaPlayer::Error); + void stateChanged(QMediaPlayer::State); + void nativeSizeChanged(const QSizeF&); + void queuedSeekTimeout(); + void seekTimeout(); + void positionChanged(qint64); + void durationChanged(qint64); + void volumeChanged(int); + void mutedChanged(bool); + void repaint(); + +private: + void updateStates(); + +private: + MediaPlayerPrivate(MediaPlayer*); + + MediaPlayer* m_player; + QMediaPlayer* m_mediaPlayer; + QMediaPlayerControl* m_mediaPlayerControl; + QGraphicsVideoItem* m_videoItem; + QGraphicsScene* m_videoScene; + + mutable MediaPlayer::NetworkState m_networkState; + mutable MediaPlayer::ReadyState m_readyState; + + IntSize m_currentSize; + bool m_isVisible; + bool m_isSeeking; + bool m_composited; + qint64 m_queuedSeek; +}; +} + +#endif // MediaPlayerPrivateQt_h diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp index 507f029..ee4af7f 100644 --- a/WebCore/platform/graphics/qt/PathQt.cpp +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -269,10 +269,12 @@ void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool antic span += ea - sa; } - m_path.moveTo(QPointF(xc + radius * cos(sar), + // connect to the previous point by a straight line + m_path.lineTo(QPointF(xc + radius * cos(sar), yc - radius * sin(sar))); m_path.arcTo(xs, ys, width, height, sa, span); + } void Path::addRect(const FloatRect& r) diff --git a/WebCore/platform/graphics/qt/StillImageQt.cpp b/WebCore/platform/graphics/qt/StillImageQt.cpp index 1db04a7..4653c58 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.cpp +++ b/WebCore/platform/graphics/qt/StillImageQt.cpp @@ -57,8 +57,43 @@ void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst, ctxt->save(); ctxt->setCompositeOperation(op); + + // To support width or height is negative + float sx = src.x(); + float sy = src.y(); + float sw = src.width(); + float sh = src.height(); + + if (sw < 0) { + sx = sx + sw; + sw = -sw; + } + + if (sh < 0) { + sy = sy + sh; + sh = -sh; + } + + float dx = dst.x(); + float dy = dst.y(); + float dw = dst.width(); + float dh = dst.height(); + + if (dw < 0) { + dx = dx + dw; + dw = -dw; + } + + if (dh < 0) { + dy = dy + dh; + dh = -dh; + } + + FloatRect srcM(sx, sy, sw, sh); + FloatRect dstM(dx, dy, dw, dh); QPainter* painter(ctxt->platformContext()); - painter->drawPixmap(dst, m_pixmap, src); + + painter->drawPixmap(dstM, m_pixmap, srcM); ctxt->restore(); } diff --git a/WebCore/platform/graphics/qt/TileQt.cpp b/WebCore/platform/graphics/qt/TileQt.cpp new file mode 100644 index 0000000..9628448 --- /dev/null +++ b/WebCore/platform/graphics/qt/TileQt.cpp @@ -0,0 +1,178 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Tile.h" + +#if ENABLE(TILED_BACKING_STORE) + +#include "GraphicsContext.h" +#include "TiledBackingStore.h" +#include "TiledBackingStoreClient.h" +#include <QApplication> +#include <QObject> +#include <QPainter> +#include <QRegion> + +namespace WebCore { + +static const unsigned checkerSize = 16; +static const unsigned checkerColor1 = 0xff555555; +static const unsigned checkerColor2 = 0xffaaaaaa; + +static QPixmap& checkeredPixmap() +{ + static QPixmap* pixmap; + if (!pixmap) { + pixmap = new QPixmap(checkerSize, checkerSize); + QPainter painter(pixmap); + QColor color1(checkerColor1); + QColor color2(checkerColor2); + for (unsigned y = 0; y < checkerSize; y += checkerSize / 2) { + bool alternate = y % checkerSize; + for (unsigned x = 0; x < checkerSize; x += checkerSize / 2) { + painter.fillRect(x, y, checkerSize / 2, checkerSize / 2, alternate ? color1 : color2); + alternate = !alternate; + } + } + } + return *pixmap; +} + +Tile::Tile(TiledBackingStore* backingStore, const Coordinate& tileCoordinate) + : m_backingStore(backingStore) + , m_coordinate(tileCoordinate) + , m_rect(m_backingStore->tileRectForCoordinate(tileCoordinate)) + , m_buffer(0) + , m_backBuffer(0) + , m_dirtyRegion(new QRegion(m_rect)) +{ +} + +Tile::~Tile() +{ + delete m_buffer; + delete m_backBuffer; + delete m_dirtyRegion; +} + +bool Tile::isDirty() const +{ + return !m_dirtyRegion->isEmpty(); +} + +bool Tile::isReadyToPaint() const +{ + return m_buffer; +} + +void Tile::invalidate(const IntRect& dirtyRect) +{ + IntRect tileDirtyRect = intersection(dirtyRect, m_rect); + if (tileDirtyRect.isEmpty()) + return; + + *m_dirtyRegion += tileDirtyRect; +} + +void Tile::updateBackBuffer() +{ + if (m_buffer && !isDirty()) + return; + + if (!m_backBuffer) { + if (!m_buffer) + m_backBuffer = new QPixmap(m_backingStore->m_tileSize.width(), m_backingStore->m_tileSize.height()); + else { + // Currently all buffers are updated synchronously at the same time so there is no real need + // to have separate back and front buffers. Just use the existing buffer. + m_backBuffer = m_buffer; + m_buffer = 0; + } + } + + QVector<QRect> dirtyRects = m_dirtyRegion->rects(); + *m_dirtyRegion = QRegion(); + + QPainter painter(m_backBuffer); + GraphicsContext context(&painter); + context.translate(-m_rect.x(), -m_rect.y()); + + int size = dirtyRects.size(); + for (int n = 0; n < size; ++n) { + context.save(); + IntRect rect = dirtyRects[n]; + context.clip(FloatRect(rect)); + context.scale(FloatSize(m_backingStore->m_contentsScale, m_backingStore->m_contentsScale)); + m_backingStore->m_client->tiledBackingStorePaint(&context, m_backingStore->mapToContents(rect)); + context.restore(); + } +} + +void Tile::swapBackBufferToFront() +{ + if (!m_backBuffer) + return; + delete m_buffer; + m_buffer = m_backBuffer; + m_backBuffer = 0; +} + +void Tile::paint(GraphicsContext* context, const IntRect& rect) +{ + if (!m_buffer) + return; + + IntRect target = intersection(rect, m_rect); + IntRect source((target.x() - m_rect.x()), + (target.y() - m_rect.y()), + target.width(), + target.height()); + + context->platformContext()->drawPixmap(target, *m_buffer, source); +} + +void Tile::paintCheckerPattern(GraphicsContext* context, const FloatRect& target) +{ + QPainter* painter = context->platformContext(); + QTransform worldTransform = painter->worldTransform(); + qreal scaleX = worldTransform.m11(); + qreal scaleY = worldTransform.m22(); + + QRect targetViewRect = QRectF(target.x() * scaleX, + target.y() * scaleY, + target.width() * scaleX, + target.height() * scaleY).toAlignedRect(); + + QTransform adjustedTransform(1., worldTransform.m12(), worldTransform.m13(), + worldTransform.m21(), 1., worldTransform.m23(), + worldTransform.m31(), worldTransform.m32(), worldTransform.m33()); + painter->setWorldTransform(adjustedTransform); + + painter->drawTiledPixmap(targetViewRect, + checkeredPixmap(), + QPoint(targetViewRect.left() % checkerSize, + targetViewRect.top() % checkerSize)); + + painter->setWorldTransform(worldTransform); +} + +} + +#endif diff --git a/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp index cd86e6d..cc4ca2e 100644 --- a/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp @@ -33,6 +33,8 @@ #include "Image.h" #include "NativeImageSkia.h" +#include <algorithm> + namespace WebCore { bool GraphicsContext3D::getImageData(Image* image, @@ -59,13 +61,17 @@ bool GraphicsContext3D::getImageData(Image* image, ASSERT(rowBytes == width * 4); uint8_t* pixels = reinterpret_cast<uint8_t*>(skiaImage->getPixels()); outputVector.resize(rowBytes * height); - memcpy(outputVector.data(), pixels, rowBytes * height); + int size = rowBytes * height; + memcpy(outputVector.data(), pixels, size); *hasAlphaChannel = true; if (!premultiplyAlpha) // FIXME: must fetch the image data before the premultiplication step *neededAlphaOp = kAlphaDoUnmultiply; - // FIXME: remove this dependency on desktop OpenGL - *format = 0x80E1; // GL_BGRA + // Convert from BGRA to RGBA. FIXME: add GL_BGRA extension support + // to all underlying OpenGL implementations. + for (int i = 0; i < size; i += 4) + std::swap(outputVector[i], outputVector[i + 2]); + *format = RGBA; return true; } diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index ba9f824..b1bfbdd 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -457,8 +457,7 @@ void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap) { RefPtr<BitmapImageSingleFrameSkia> image(adoptRef(new BitmapImageSingleFrameSkia())); - if (!bitmap.copyTo(&image->m_nativeImage, bitmap.config())) - return 0; + bitmap.copyTo(&image->m_nativeImage, bitmap.config()); return image.release(); } diff --git a/WebCore/platform/graphics/transforms/AffineTransform.cpp b/WebCore/platform/graphics/transforms/AffineTransform.cpp index d6688d2..be18e07 100644 --- a/WebCore/platform/graphics/transforms/AffineTransform.cpp +++ b/WebCore/platform/graphics/transforms/AffineTransform.cpp @@ -314,14 +314,28 @@ FloatRect AffineTransform::mapRect(const FloatRect& rect) const return mappedRect; } - FloatQuad q(rect); + FloatQuad result; + result.setP1(mapPoint(rect.location())); + result.setP2(mapPoint(FloatPoint(rect.right(), rect.y()))); + result.setP3(mapPoint(FloatPoint(rect.right(), rect.bottom()))); + result.setP4(mapPoint(FloatPoint(rect.x(), rect.bottom()))); + return result.boundingBox(); +} + +FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const +{ + if (isIdentityOrTranslation()) { + FloatQuad mappedQuad(q); + mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5])); + return mappedQuad; + } FloatQuad result; result.setP1(mapPoint(q.p1())); result.setP2(mapPoint(q.p2())); result.setP3(mapPoint(q.p3())); result.setP4(mapPoint(q.p4())); - return result.boundingBox(); + return result; } void AffineTransform::blend(const AffineTransform& from, double progress) diff --git a/WebCore/platform/graphics/transforms/AffineTransform.h b/WebCore/platform/graphics/transforms/AffineTransform.h index 00631c2..289ec54 100644 --- a/WebCore/platform/graphics/transforms/AffineTransform.h +++ b/WebCore/platform/graphics/transforms/AffineTransform.h @@ -36,6 +36,8 @@ #include <CoreGraphics/CGAffineTransform.h> #elif PLATFORM(CAIRO) #include <cairo.h> +#elif PLATFORM(OPENVG) +#include "VGUtils.h" #elif PLATFORM(QT) #include <QTransform> #elif PLATFORM(SKIA) @@ -74,6 +76,7 @@ public: IntRect mapRect(const IntRect&) const; FloatRect mapRect(const FloatRect&) const; + FloatQuad mapQuad(const FloatQuad&) const; bool isIdentity() const; @@ -120,6 +123,11 @@ public: { return m_transform[0] == 1 && m_transform[1] == 0 && m_transform[2] == 0 && m_transform[3] == 1; } + + bool isIdentityOrTranslationOrFlipped() const + { + return m_transform[0] == 1 && m_transform[1] == 0 && m_transform[2] == 0 && (m_transform[3] == 1 || m_transform[3] == -1); + } bool operator== (const AffineTransform& m2) const { @@ -152,6 +160,8 @@ public: operator CGAffineTransform() const; #elif PLATFORM(CAIRO) operator cairo_matrix_t() const; +#elif PLATFORM(OPENVG) + operator VGMatrix() const; #elif PLATFORM(QT) operator QTransform() const; #elif PLATFORM(SKIA) diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index 8ed8712..e4eb159 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -321,12 +321,9 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo ASSERT_NOT_REACHED(); } - if (font->platformData().useGDI()) { - static bool canCreateCGFontWithLOGFONT = wkCanCreateCGFontWithLOGFONT(); - if (!shouldUseFontSmoothing || !canCreateCGFontWithLOGFONT && (graphicsContext->textDrawingMode() & cTextStroke)) { - drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); - return; - } + if (font->platformData().useGDI() && !shouldUseFontSmoothing) { + drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); + return; } uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing); diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp index 8869a90..d050243 100644 --- a/WebCore/platform/graphics/win/FontCacheWin.cpp +++ b/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -301,22 +301,68 @@ SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font) return 0; } +static SimpleFontData* fontDataFromDescriptionAndLogFont(FontCache* fontCache, const FontDescription& fontDescription, const LOGFONT& font, AtomicString& outFontFamilyName) +{ + AtomicString familyName = String(font.lfFaceName, wcsnlen(font.lfFaceName, LF_FACESIZE)); + SimpleFontData* fontData = fontCache->getCachedFontData(fontDescription, familyName); + if (fontData) + outFontFamilyName = familyName; + return fontData; +} + SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) { + DEFINE_STATIC_LOCAL(AtomicString, fallbackFontName, ()); + if (!fallbackFontName.isEmpty()) + return getCachedFontData(fontDescription, fallbackFontName); + // 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"); - if (SimpleFontData* simpleFont = getCachedFontData(fontDescription, timesStr)) - return simpleFont; - 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)); + // Search all typical Windows-installed full Unicode fonts. + // Sorted by most to least glyphs according to http://en.wikipedia.org/wiki/Unicode_typefaces + // Start with Times New Roman also since it is the default if the user doesn't change prefs. + static AtomicString fallbackFonts[] = { + AtomicString("Times New Roman"), + AtomicString("Microsoft Sans Serif"), + AtomicString("Tahoma"), + AtomicString("Lucida Sans Unicode"), + AtomicString("Arial") + }; + SimpleFontData* simpleFont; + for (int i = 0; i < ARRAYSIZE(fallbackFonts); ++i) { + if (simpleFont = getCachedFontData(fontDescription, fallbackFonts[i])) { + fallbackFontName = fallbackFonts[i]; + return simpleFont; + } } - return getCachedFontData(fontDescription, defaultGUIFontFamily); + + // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available. + if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) { + LOGFONT defaultGUILogFont; + GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont); + if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, defaultGUILogFont, fallbackFontName)) + return simpleFont; + } + + // Fall back to Non-client metrics fonts. + NONCLIENTMETRICS nonClientMetrics = {0}; + nonClientMetrics.cbSize = sizeof(nonClientMetrics); + if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) { + if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfMessageFont, fallbackFontName)) + return simpleFont; + if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfMenuFont, fallbackFontName)) + return simpleFont; + if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfStatusFont, fallbackFontName)) + return simpleFont; + if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfCaptionFont, fallbackFontName)) + return simpleFont; + if (simpleFont = fontDataFromDescriptionAndLogFont(this, fontDescription, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) + return simpleFont; + } + + ASSERT_NOT_REACHED(); + return 0; } static LONG toGDIFontWeight(FontWeight fontWeight) @@ -517,14 +563,9 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD // This masks rounding errors related to the HFONT metrics being different from the CGFont metrics. // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't // look as nice. That may be solvable though. -#if PLATFORM(CG) - bool canCreateCGFontWithLOGFONT = wkCanCreateCGFontWithLOGFONT(); -#else - bool canCreateCGFontWithLOGFONT = true; -#endif LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()), family); HFONT hfont = createGDIFont(family, weight, fontDescription.italic(), - fontDescription.computedPixelSize() * (useGDI ? 1 : 32), useGDI && canCreateCGFontWithLOGFONT); + fontDescription.computedPixelSize() * (useGDI ? 1 : 32), useGDI); if (!hfont) return 0; diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp index b2d1b32..e9f83ab 100644 --- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp @@ -48,7 +48,6 @@ SOFT_LINK(T2embed, TTDeleteEmbeddedFont, LONG, __stdcall, (HANDLE hFontReference FontCustomPlatformData::~FontCustomPlatformData() { - CGFontRelease(m_cgFont); if (m_fontReference) { if (m_name.isNull()) { ASSERT(T2embedLibrary()); @@ -61,7 +60,6 @@ FontCustomPlatformData::~FontCustomPlatformData() FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode renderingMode) { - ASSERT(wkCanCreateCGFontWithLOGFONT() || m_cgFont); ASSERT(m_fontReference); ASSERT(T2embedLibrary()); @@ -88,35 +86,8 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b HFONT hfont = CreateFontIndirect(&logFont); - if (wkCanCreateCGFontWithLOGFONT()) { - RetainPtr<CGFontRef> cgFont(AdoptCF, CGFontCreateWithPlatformFont(&logFont)); - return FontPlatformData(hfont, cgFont.get(), size, bold, italic, renderingMode == AlternateRenderingMode); - } - - wkSetFontPlatformInfo(m_cgFont, &logFont, free); - return FontPlatformData(hfont, m_cgFont, size, bold, italic, renderingMode == AlternateRenderingMode); -} - -const void* getData(void* info) -{ - SharedBuffer* buffer = static_cast<SharedBuffer*>(info); - buffer->ref(); - return (void*)buffer->data(); -} - -void releaseData(void* info, const void* data) -{ - static_cast<SharedBuffer*>(info)->deref(); -} - -size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count) -{ - SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); - size_t availBytes = count; - if (offset + count > sharedBuffer->size()) - availBytes -= (offset + count) - sharedBuffer->size(); - memcpy(buffer, sharedBuffer->data() + offset, availBytes); - return availBytes; + RetainPtr<CGFontRef> cgFont(AdoptCF, CGFontCreateWithPlatformFont(&logFont)); + return FontPlatformData(hfont, cgFont.get(), size, bold, italic, renderingMode == AlternateRenderingMode); } // Streams the concatenation of a header and font data. @@ -196,16 +167,6 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) ASSERT_ARG(buffer, buffer); ASSERT(T2embedLibrary()); - RetainPtr<CGFontRef> cgFont; - if (!wkCanCreateCGFontWithLOGFONT()) { - // Get CG to create the font. - CGDataProviderDirectAccessCallbacks callbacks = { &getData, &releaseData, &getBytesWithOffset, NULL }; - RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirectAccess(buffer, buffer->size(), &callbacks)); - cgFont.adoptCF(CGFontCreateWithDataProvider(dataProvider.get())); - if (!cgFont) - return 0; - } - // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name @@ -236,7 +197,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) return 0; } - return new FontCustomPlatformData(cgFont.releaseRef(), fontReference, fontName); + return new FontCustomPlatformData(fontReference, fontName); } } diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.h b/WebCore/platform/graphics/win/FontCustomPlatformData.h index 34a9851..f75f12a 100644 --- a/WebCore/platform/graphics/win/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/win/FontCustomPlatformData.h @@ -33,9 +33,8 @@ class FontPlatformData; class SharedBuffer; struct FontCustomPlatformData : Noncopyable { - FontCustomPlatformData(CGFontRef cgFont, HANDLE fontReference, const String& name) - : m_cgFont(cgFont) - , m_fontReference(fontReference) + FontCustomPlatformData(HANDLE fontReference, const String& name) + : m_fontReference(fontReference) , m_name(name) { } @@ -44,7 +43,6 @@ struct FontCustomPlatformData : Noncopyable { FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode); - CGFontRef m_cgFont; HANDLE m_fontReference; String m_name; }; diff --git a/WebCore/platform/graphics/win/FontDatabase.cpp b/WebCore/platform/graphics/win/FontDatabase.cpp deleted file mode 100644 index 22ad4a6..0000000 --- a/WebCore/platform/graphics/win/FontDatabase.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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 - * 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 "FontDatabase.h" - -#include "CString.h" -#include "FileSystem.h" -#include "PlatformString.h" -#include <WebKitSystemInterface/WebKitSystemInterface.h> -#include <shlobj.h> -#include <wtf/RetainPtr.h> - -namespace WebCore { - -static String systemFontsDirectory() -{ - static bool initialized; - static String directory; - - if (!initialized) { - initialized = true; - - Vector<UChar> buffer(MAX_PATH); - if (FAILED(SHGetFolderPath(0, CSIDL_FONTS | CSIDL_FLAG_CREATE, 0, 0, buffer.data()))) - return directory; - buffer.resize(wcslen(buffer.data())); - - directory = String::adopt(buffer); - } - - return directory; -} - -static String fontsPlistPath() -{ - static String path = pathByAppendingComponent(localUserSpecificStorageDirectory(), "FontsList.plist"); - return path; -} - -static bool systemHasFontsNewerThanFontsPlist() -{ - WIN32_FILE_ATTRIBUTE_DATA plistAttributes = {0}; - if (!GetFileAttributesEx(fontsPlistPath().charactersWithNullTermination(), GetFileExInfoStandard, &plistAttributes)) - return true; - - WIN32_FILE_ATTRIBUTE_DATA fontsDirectoryAttributes = {0}; - if (!GetFileAttributesEx(systemFontsDirectory().charactersWithNullTermination(), GetFileExInfoStandard, &fontsDirectoryAttributes)) - return true; - - return CompareFileTime(&plistAttributes.ftLastWriteTime, &fontsDirectoryAttributes.ftLastWriteTime) < 0; -} - -static RetainPtr<CFPropertyListRef> readFontPlist() -{ - CString plistPath = fontsPlistPath().utf8(); - - RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateFromFileSystemRepresentation(0, reinterpret_cast<const UInt8*>(plistPath.data()), plistPath.length(), false)); - if (!url) - return 0; - - RetainPtr<CFReadStreamRef> stream(AdoptCF, CFReadStreamCreateWithFile(0, url.get())); - if (!stream) - return 0; - - if (!CFReadStreamOpen(stream.get())) - return 0; - - CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0 | kCFPropertyListXMLFormat_v1_0; - RetainPtr<CFPropertyListRef> plist(AdoptCF, CFPropertyListCreateFromStream(0, stream.get(), 0, kCFPropertyListMutableContainersAndLeaves, &format, 0)); - - CFReadStreamClose(stream.get()); - - return plist; -} - -static bool populateFontDatabaseFromPlist(CFPropertyListRef plist) -{ - if (!plist) - return false; - - wkAddFontsFromPlist(plist); - return true; -} - -static bool populateFontDatabaseFromFileSystem() -{ - RetainPtr<CFStringRef> directory(AdoptCF, systemFontsDirectory().createCFString()); - if (!directory) - return false; - - wkAddFontsInDirectory(directory.get()); - return true; -} - -static CFStringRef fontFilenamesFromRegistryKey() -{ - static CFStringRef key = CFSTR("WebKitFontFilenamesFromRegistry"); - return key; -} - -static void writeFontDatabaseToPlist(CFPropertyListRef cgFontDBPropertyList, CFPropertyListRef filenamesFromRegistry) -{ - 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; - if (initialized) - return; - initialized = true; - - if (wkCanCreateCGFontWithLOGFONT()) - return; - - 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()) { - wkAddFontsFromRegistry(); - RetainPtr<CFPropertyListRef> cgFontDBPropertyList(AdoptCF, wkCreateFontsPlist()); - writeFontDatabaseToPlist(cgFontDBPropertyList.get(), currentFilenamesFromRegistry.get()); - } -} - -} // namespace WebCore diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp index d605cf9..ed9073f 100644 --- a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp +++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp @@ -1,5 +1,5 @@ /* - * This file is part of the internal font implementation. It should not be included by anyone other than + * This file is part of the internal font implementation. It should not be included by anyone other than * FontMac.cpp, FontWin.cpp and Font.cpp. * * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. @@ -109,29 +109,9 @@ static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc) void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName) { - if (wkCanCreateCGFontWithLOGFONT()) { - LOGFONT logfont; - GetObject(font, sizeof(logfont), &logfont); - m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&logfont)); - return; - } - - // Try the face name first. Windows may end up localizing this name, and CG doesn't know about - // the localization. If the create fails, we'll try the PostScript name. - RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName))); - m_cgFont.adoptCF(CGFontCreateWithFontName(fullName.get())); - if (!m_cgFont) { - CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc); - if (postScriptName) { - m_cgFont.adoptCF(CGFontCreateWithFontName(postScriptName)); - ASSERT(m_cgFont); - } - } - if (m_useGDI) { - LOGFONT* logfont = static_cast<LOGFONT*>(malloc(sizeof(LOGFONT))); - GetObject(font, sizeof(*logfont), logfont); - wkSetFontPlatformInfo(m_cgFont.get(), logfont, free); - } + LOGFONT logfont; + GetObject(font, sizeof(logfont), &logfont); + m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&logfont)); } FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI) diff --git a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp index 9fce68a..9b916bd 100644 --- a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp @@ -4,7 +4,7 @@ * * Copyright (C) 2006, 2007, 2008 Apple Inc. * Copyright (C) 2007 Alp Toker - * Copyright (C) 2008 Brent Fulgham + * Copyright (C) 2008, 2010 Brent Fulgham * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -34,7 +34,7 @@ #include <cairo-win32.h> -using std::min; +using namespace std; namespace WebCore { @@ -47,8 +47,7 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* cairo_matrix_init_scale(&sizeMatrix, size, size); static cairo_font_options_t* fontOptions = 0; - if (!fontOptions) - { + if (!fontOptions) { fontOptions = cairo_font_options_create(); cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL); } @@ -130,4 +129,15 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) return *this; } +bool FontPlatformData::operator==(const FontPlatformData& other) const +{ + return m_font == other.m_font + && m_fontFace == other.m_fontFace + && m_scaledFont == other.m_scaledFont + && m_size == other.m_size + && m_syntheticBold == other.m_syntheticBold + && m_syntheticOblique == other.m_syntheticOblique + && m_useGDI == other.m_useGDI; +} + } diff --git a/WebCore/platform/graphics/win/FontWin.cpp b/WebCore/platform/graphics/win/FontWin.cpp index 27d8dee..717171f 100644 --- a/WebCore/platform/graphics/win/FontWin.cpp +++ b/WebCore/platform/graphics/win/FontWin.cpp @@ -34,6 +34,8 @@ #include "UniscribeController.h" #include <wtf/MathExtras.h> +using namespace std; + namespace WebCore { bool Font::canReturnFallbackFontsForComplexText() @@ -89,10 +91,16 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F drawGlyphBuffer(context, glyphBuffer, run, startPoint); } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { UniscribeController controller(this, run, fallbackFonts); controller.advance(run.length()); + if (glyphOverflow) { + glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - ascent()); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - descent()); + glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); + glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.runWidthSoFar())); + } return controller.runWidthSoFar(); } diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp index 49b5af3..0065191 100644 --- a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp @@ -29,21 +29,132 @@ #include "GraphicsLayerCACF.h" -#include "CString.h" #include "FloatConversion.h" #include "FloatRect.h" +#include "Font.h" +#include "FontSelector.h" #include "Image.h" #include "PlatformString.h" #include "SystemTime.h" #include "WKCACFLayer.h" -#include <QuartzCoreInterface/QuartzCoreInterface.h> #include <wtf/CurrentTime.h> #include <wtf/StringExtras.h> +#include <wtf/text/CString.h> using namespace std; namespace WebCore { +class WebLayer : public WKCACFLayer { +public: + static PassRefPtr<WKCACFLayer> create(LayerType layerType, GraphicsLayerCACF* owner) + { + return adoptRef(new WebLayer(layerType, owner)); + } + + virtual void setNeedsDisplay(const CGRect* dirtyRect) + { + if (m_owner) { + if (m_owner->showRepaintCounter()) { + CGRect layerBounds = bounds(); + CGRect repaintCounterRect = layerBounds; + // We assume a maximum of 4 digits and a font size of 22. + repaintCounterRect.size.width = 48; + repaintCounterRect.size.height = 25; + if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) + repaintCounterRect.origin.y = layerBounds.size.height - (layerBounds.origin.y + repaintCounterRect.size.height); + WKCACFLayer::setNeedsDisplay(&repaintCounterRect); + } + if (dirtyRect && m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { + CGRect flippedDirtyRect = *dirtyRect; + flippedDirtyRect.origin.y = bounds().size.height - (flippedDirtyRect.origin.y + flippedDirtyRect.size.height); + WKCACFLayer::setNeedsDisplay(&flippedDirtyRect); + return; + } + } + WKCACFLayer::setNeedsDisplay(dirtyRect); + } + + virtual void drawInContext(PlatformGraphicsContext* context) + { + if (!m_owner) + return; + + CGContextSaveGState(context); + + CGRect layerBounds = bounds(); + if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -layerBounds.size.height); + } + + if (m_owner->client()) { + GraphicsContext graphicsContext(context); + + // It's important to get the clip from the context, because it may be significantly + // smaller than the layer bounds (e.g. tiled layers) + CGRect clipBounds = CGContextGetClipBoundingBox(context); + IntRect clip(enclosingIntRect(clipBounds)); + m_owner->paintGraphicsLayerContents(graphicsContext, clip); + } +#ifndef NDEBUG + else { + ASSERT_NOT_REACHED(); + + // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color, + // so CA never makes backing store for it (which is what -setNeedsDisplay will do above). + CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f); + CGContextFillRect(context, layerBounds); + } +#endif + + if (m_owner->showRepaintCounter()) { + String text = String::format("%d", m_owner->incrementRepaintCount());; + + CGContextSaveGState(context); + CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f); + + CGRect aBounds = layerBounds; + + aBounds.size.width = 10 + 12 * text.length(); + aBounds.size.height = 25; + CGContextFillRect(context, aBounds); + + FontDescription desc; + + NONCLIENTMETRICS metrics; + metrics.cbSize = sizeof(metrics); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0); + FontFamily family; + family.setFamily(metrics.lfSmCaptionFont.lfFaceName); + desc.setFamily(family); + + desc.setComputedSize(22); + + Font font = Font(desc, 0, 0); + font.update(0); + + GraphicsContext cg(context); + cg.setFillColor(Color::black, DeviceColorSpace); + cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 3, aBounds.origin.y + 20)); + + CGContextRestoreGState(context); + } + + CGContextRestoreGState(context); + } + +protected: + WebLayer(LayerType layerType, GraphicsLayerCACF* owner) + : WKCACFLayer(layerType) + , m_owner(owner) + { + } + +private: + GraphicsLayer* m_owner; +}; + static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t) { toT3D.m11 = narrowPrecisionToFloat(t.m11()); @@ -124,7 +235,7 @@ GraphicsLayerCACF::GraphicsLayerCACF(GraphicsLayerClient* client) , m_contentsLayerPurpose(NoContentsLayer) , m_contentsLayerHasBackgroundColor(false) { - m_layer = WKCACFLayer::create(WKCACFLayer::Layer, this); + m_layer = WebLayer::create(WKCACFLayer::Layer, this); updateDebugIndicators(); } @@ -142,12 +253,12 @@ GraphicsLayerCACF::~GraphicsLayerCACF() m_transformLayer->removeFromSuperlayer(); } -void GraphicsLayerCACF::setName(const String& inName) +void GraphicsLayerCACF::setName(const String& name) { - String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + inName; - GraphicsLayer::setName(name); + String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name; + GraphicsLayer::setName(longName); - m_layer->setName(inName); + m_layer->setName(longName); } NativeLayer GraphicsLayerCACF::nativeLayer() const @@ -331,8 +442,10 @@ void GraphicsLayerCACF::setNeedsDisplay() void GraphicsLayerCACF::setNeedsDisplayInRect(const FloatRect& rect) { - if (drawsContent()) - m_layer->setNeedsDisplay(rect); + if (drawsContent()) { + CGRect cgRect = rect; + m_layer->setNeedsDisplay(&cgRect); + } } void GraphicsLayerCACF::setContentsRect(const IntRect& rect) @@ -537,7 +650,7 @@ void GraphicsLayerCACF::updateLayerPreserves3D() { if (m_preserves3D && !m_transformLayer) { // Create the transform layer. - m_transformLayer = WKCACFLayer::create(WKCACFLayer::TransformLayer, this); + m_transformLayer = WebLayer::create(WKCACFLayer::TransformLayer, this); #ifndef NDEBUG m_transformLayer->setName(String().format("Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this)); @@ -553,7 +666,7 @@ void GraphicsLayerCACF::updateLayerPreserves3D() m_layer->setPosition(point); m_layer->setAnchorPoint(CGPointMake(0.5f, 0.5f)); - m_layer->setTransform(wkqcCATransform3DIdentity()); + m_layer->setTransform(CATransform3DIdentity); // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer. m_layer->setOpacity(1); @@ -610,7 +723,7 @@ void GraphicsLayerCACF::updateContentsImage() { if (m_pendingContentsImage) { if (!m_contentsLayer.get()) { - RefPtr<WKCACFLayer> imageLayer = WKCACFLayer::create(WKCACFLayer::Layer, this); + RefPtr<WKCACFLayer> imageLayer = WebLayer::create(WKCACFLayer::Layer, this); #ifndef NDEBUG imageLayer->setName("Image Layer"); #endif diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.h b/WebCore/platform/graphics/win/GraphicsLayerCACF.h index 0a52764..8c3f848 100644 --- a/WebCore/platform/graphics/win/GraphicsLayerCACF.h +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.h @@ -91,8 +91,6 @@ public: virtual void setGeometryOrientation(CompositingCoordinatesOrientation); - void notifySyncRequired() { if (m_client) m_client->notifySyncRequired(this); } - private: void updateOpacityOnLayer(); diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp index 2c6d41d..a0fbba7 100644 --- a/WebCore/platform/graphics/win/ImageCGWin.cpp +++ b/WebCore/platform/graphics/win/ImageCGWin.cpp @@ -25,13 +25,14 @@ #include "config.h" #include "Image.h" + #include "BitmapImage.h" #include "BitmapInfo.h" #include "GraphicsContext.h" +#include "PlatformString.h" #include <ApplicationServices/ApplicationServices.h> - #include <windows.h> -#include "PlatformString.h" +#include <wtf/RetainPtr.h> namespace WebCore { diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index 1df73a7..c848eb3 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -28,13 +28,20 @@ #if ENABLE(VIDEO) #include "MediaPlayerPrivateQuickTimeWin.h" +#include "Cookie.h" +#include "CookieJar.h" +#include "Frame.h" +#include "FrameView.h" #include "GraphicsContext.h" #include "KURL.h" #include "QTMovieWin.h" #include "ScrollView.h" +#include "SoftLinking.h" +#include "StringBuilder.h" #include "StringHash.h" #include "TimeRanges.h" #include "Timer.h" +#include <Wininet.h> #include <wtf/CurrentTime.h> #include <wtf/HashSet.h> #include <wtf/MathExtras.h> @@ -59,6 +66,9 @@ using namespace std; namespace WebCore { +SOFT_LINK_LIBRARY(Wininet) +SOFT_LINK(Wininet, InternetSetCookieExW, DWORD, WINAPI, (LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData, DWORD dwFlags, DWORD_PTR dwReserved), (lpszUrl, lpszCookieName, lpszCookieData, dwFlags, dwReserved)) + MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) { return new MediaPlayerPrivate(player); @@ -111,7 +121,7 @@ PlatformMedia MediaPlayerPrivate::platformMedia() const #if USE(ACCELERATED_COMPOSITING) PlatformLayer* MediaPlayerPrivate::platformLayer() const { - return m_qtVideoLayer->platformLayer(); + return m_qtVideoLayer ? m_qtVideoLayer->platformLayer() : 0; } #endif @@ -159,6 +169,97 @@ void TaskTimer::fired() QTMovieWin::taskTimerFired(); } +String MediaPlayerPrivate::rfc2616DateStringFromTime(CFAbsoluteTime time) +{ + static const char* const dayStrings[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; + static const char* const monthStrings[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + static const CFStringRef dateFormatString = CFSTR("%s, %02d %s %04d %02d:%02d:%02d GMT"); + static CFTimeZoneRef gmtTimeZone; + if (!gmtTimeZone) + gmtTimeZone = CFTimeZoneCopyDefault(); + + CFGregorianDate dateValue = CFAbsoluteTimeGetGregorianDate(time, gmtTimeZone); + if (!CFGregorianDateIsValid(dateValue, kCFGregorianAllUnits)) + return String(); + + time = CFGregorianDateGetAbsoluteTime(dateValue, gmtTimeZone); + SInt32 day = CFAbsoluteTimeGetDayOfWeek(time, 0); + + RetainPtr<CFStringRef> dateCFString(AdoptCF, CFStringCreateWithFormat(0, 0, dateFormatString, dayStrings[day - 1], dateValue.day, + monthStrings[dateValue.month - 1], dateValue.year, dateValue.hour, dateValue.minute, (int)dateValue.second)); + return dateCFString.get(); +} + +static void addCookieParam(StringBuilder& cookieBuilder, const String& name, const String& value) +{ + if (name.isEmpty()) + return; + + // If this isn't the first parameter added, terminate the previous one. + if (cookieBuilder.length()) + cookieBuilder.append("; "); + + // Add parameter name, and value if there is one. + cookieBuilder.append(name); + if (!value.isEmpty()) { + cookieBuilder.append("="); + cookieBuilder.append(value); + } +} + + +void MediaPlayerPrivate::setUpCookiesForQuickTime(const String& url) +{ + // WebCore loaded the page with the movie URL with CFNetwork but QuickTime will + // use WinINet to download the movie, so we need to copy any cookies needed to + // download the movie into WinInet before asking QuickTime to open it. + Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : 0; + if (!frame || !frame->page() || !frame->page()->cookieEnabled()) + return; + + KURL movieURL = KURL(KURL(), url); + Vector<Cookie> documentCookies; + if (!getRawCookies(frame->document(), movieURL, documentCookies)) + return; + + for (size_t ndx = 0; ndx < documentCookies.size(); ndx++) { + const Cookie& cookie = documentCookies[ndx]; + + if (cookie.name.isEmpty()) + continue; + + // Build up the cookie string with as much information as we can get so WinINet + // knows what to do with it. + StringBuilder cookieBuilder; + addCookieParam(cookieBuilder, cookie.name, cookie.value); + addCookieParam(cookieBuilder, "path", cookie.path); + if (cookie.expires) + addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires)); + if (cookie.httpOnly) + addCookieParam(cookieBuilder, "httpOnly", String()); + cookieBuilder.append(";"); + + String cookieURL; + if (!cookie.domain.isEmpty()) { + StringBuilder urlBuilder; + + urlBuilder.append(movieURL.protocol()); + urlBuilder.append("://"); + if (cookie.domain[0] == '.') + urlBuilder.append(cookie.domain.substring(1)); + else + urlBuilder.append(cookie.domain); + if (cookie.path.length() > 1) + urlBuilder.append(cookie.path); + + cookieURL = urlBuilder.toString(); + } else + cookieURL = movieURL; + + InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0); + } +} + void MediaPlayerPrivate::load(const String& url) { if (!QTMovieWin::initializeQuickTime()) { @@ -181,6 +282,8 @@ void MediaPlayerPrivate::load(const String& url) } cancelSeek(); + setUpCookiesForQuickTime(url); + m_qtMovie.set(new QTMovieWin(this)); m_qtMovie->load(url.characters(), url.length(), m_player->preservesPitch()); m_qtMovie->setVolume(m_player->volume()); @@ -861,14 +964,6 @@ void MediaPlayerPrivate::acceleratedRenderingStateChanged() setUpVideoRendering(); } -void MediaPlayerPrivate::notifySyncRequired(const GraphicsLayer*) -{ - GraphicsLayerCACF* videoGraphicsLayer = static_cast<GraphicsLayerCACF*>(m_qtVideoLayer.get()); - if (videoGraphicsLayer) - videoGraphicsLayer->notifySyncRequired(); - } - - #endif diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index 029a520..9de5894 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -67,7 +67,7 @@ private: // GraphicsLayerClient methods virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip); virtual void notifyAnimationStarted(const GraphicsLayer*, double time) { } - virtual void notifySyncRequired(const GraphicsLayer*); + virtual void notifySyncRequired(const GraphicsLayer*) { } virtual bool showDebugBorders() const { return false; } virtual bool showRepaintCounter() const { return false; } #endif @@ -158,6 +158,9 @@ private: void createLayerForMovie(); void destroyLayerForMovie(); + void setUpCookiesForQuickTime(const String& url); + String rfc2616DateStringFromTime(CFAbsoluteTime); + MediaPlayer* m_player; OwnPtr<QTMovieWin> m_qtMovie; #if USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/RefCountedHFONT.h b/WebCore/platform/graphics/win/RefCountedHFONT.h new file mode 100755 index 0000000..b1b691b --- /dev/null +++ b/WebCore/platform/graphics/win/RefCountedHFONT.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2010 Apple 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 RefCountedHFONT_h +#define RefCountedHFONT_h + +#include "StringImpl.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +class RefCountedHFONT : public RefCounted<RefCountedHFONT> { +public: + static PassRefPtr<RefCountedHFONT> create(HFONT hfont) { return adoptRef(new RefCountedHFONT(hfont)); } + static PassRefPtr<RefCountedHFONT> createDeleted() { return adoptRef(new RefCountedHFONT(reinterpret_cast<HFONT>(-1))); } + + ~RefCountedHFONT() + { + if (m_hfont != reinterpret_cast<HFONT>(-1)) + DeleteObject(m_hfont); + } + + HFONT hfont() const { return m_hfont; } + unsigned hash() const + { + return StringImpl::computeHash(reinterpret_cast<const UChar*>(&m_hfont), sizeof(HFONT) / sizeof(UChar)); + } + +private: + RefCountedHFONT(HFONT hfont) + : m_hfont(hfont) + { + } + + HFONT m_hfont; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp index 6b3a96e..ee3a980 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp @@ -126,10 +126,10 @@ void SimpleFontData::platformCharWidthInit() } } -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode metricsMode) const { if (m_platformData.useGDI()) - return widthForGDIGlyph(glyph); + return metricsForGDIGlyph(glyph); CGFontRef font = m_platformData.cgFont(); float pointSize = m_platformData.size(); @@ -139,8 +139,18 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const // FIXME: Need to add real support for printer fonts. bool isPrinterFont = false; wkGetGlyphAdvances(font, m, m_isSystemFont, isPrinterFont, glyph, advance); - - return advance.width + m_syntheticBoldOffset; + GlyphMetrics metrics; + metrics.horizontalAdvance = advance.width + m_syntheticBoldOffset; + + if (metricsMode == GlyphBoundingBox) { + CGRect boundingBox; + CGFontGetGlyphBBoxes(font, &glyph, 1, &boundingBox); + CGFloat scale = pointSize / unitsPerEm(); + metrics.boundingBox = CGRectApplyAffineTransform(boundingBox, CGAffineTransformMakeScale(scale, -scale)); + if (m_syntheticBoldOffset) + metrics.boundingBox.setWidth(metrics.boundingBox.width() + m_syntheticBoldOffset); + } + return metrics; } } diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index 5a3244c..f85f9ba 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -179,16 +179,25 @@ void SimpleFontData::determinePitch() ReleaseDC(0, dc); } -float SimpleFontData::widthForGDIGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::metricsForGDIGlyph(Glyph glyph) const { HDC hdc = GetDC(0); SetGraphicsMode(hdc, GM_ADVANCED); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); - int width; - GetCharWidthI(hdc, glyph, 1, 0, &width); + + GLYPHMETRICS gdiMetrics; + static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; + GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity); + SelectObject(hdc, oldFont); ReleaseDC(0, hdc); - return width + m_syntheticBoldOffset; + + GlyphMetrics glyphMetrics; + glyphMetrics.horizontalAdvance = gdiMetrics.gmCellIncX + m_syntheticBoldOffset; + glyphMetrics.boundingBox = FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y, + gdiMetrics.gmBlackBoxX + m_syntheticBoldOffset, gdiMetrics.gmBlackBoxY); + + return glyphMetrics; } SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp index f382857..cfa15a2 100644 --- a/WebCore/platform/graphics/win/UniscribeController.cpp +++ b/WebCore/platform/graphics/win/UniscribeController.cpp @@ -32,6 +32,8 @@ #include "SimpleFontData.h" #include <wtf/MathExtras.h> +using namespace std; + namespace WebCore { // FIXME: Rearchitect this to be more like WidthIterator in Font.cpp. Have an advance() method @@ -39,16 +41,20 @@ namespace WebCore { // take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when // measuring. UniscribeController::UniscribeController(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) -: m_font(*font) -, m_run(run) -, m_fallbackFonts(fallbackFonts) -, m_end(run.length()) -, m_currentCharacter(0) -, m_runWidthSoFar(0) -, m_computingOffsetPosition(false) -, m_includePartialGlyphs(false) -, m_offsetX(0) -, m_offsetPosition(0) + : m_font(*font) + , m_run(run) + , m_fallbackFonts(fallbackFonts) + , m_minGlyphBoundingBoxX(numeric_limits<float>::max()) + , m_maxGlyphBoundingBoxX(numeric_limits<float>::min()) + , m_minGlyphBoundingBoxY(numeric_limits<float>::max()) + , m_maxGlyphBoundingBoxY(numeric_limits<float>::min()) + , m_end(run.length()) + , m_currentCharacter(0) + , m_runWidthSoFar(0) + , m_computingOffsetPosition(false) + , m_includePartialGlyphs(false) + , m_offsetX(0) + , m_offsetPosition(0) { m_padding = m_run.padding(); if (!m_padding) @@ -374,6 +380,14 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S glyphBuffer->add(glyph, fontData, advance, &size); } + GlyphMetrics glyphMetrics = fontData->metricsForGlyph(glyph); + glyphMetrics.boundingBox.move(m_glyphOrigin.x(), m_glyphOrigin.y()); + m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphMetrics.boundingBox.x()); + m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphMetrics.boundingBox.right()); + m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphMetrics.boundingBox.y()); + m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphMetrics.boundingBox.bottom()); + m_glyphOrigin.move(advance + offsetX, -offsetY); + // Mutate the glyph array to contain our altered advances. if (m_computingOffsetPosition) advances[k] = advance; diff --git a/WebCore/platform/graphics/win/UniscribeController.h b/WebCore/platform/graphics/win/UniscribeController.h index 23b8108..09203b5 100644 --- a/WebCore/platform/graphics/win/UniscribeController.h +++ b/WebCore/platform/graphics/win/UniscribeController.h @@ -49,6 +49,11 @@ public: // Returns the width of everything we've consumed so far. float runWidthSoFar() const { return m_runWidthSoFar; } + float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; } + float maxGlyphBoundingBoxX() const { return m_maxGlyphBoundingBoxX; } + float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; } + float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; } + private: void resetControlAndState(); @@ -61,6 +66,11 @@ private: const Font& m_font; const TextRun& m_run; HashSet<const SimpleFontData*>* m_fallbackFonts; + FloatPoint m_glyphOrigin; + float m_minGlyphBoundingBoxX; + float m_maxGlyphBoundingBoxX; + float m_minGlyphBoundingBoxY; + float m_maxGlyphBoundingBoxY; SCRIPT_CONTROL m_control; SCRIPT_STATE m_state; diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp index e5b184d..4a0461d 100644 --- a/WebCore/platform/graphics/win/WKCACFLayer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp @@ -29,68 +29,33 @@ #include "WKCACFLayer.h" -#include "CString.h" #include "WKCACFContextFlusher.h" #include "WKCACFLayerRenderer.h" +#include <wtf/text/CString.h> #include <stdio.h> #include <QuartzCore/CACFContext.h> #include <QuartzCore/CARender.h> -#include <QuartzCoreInterface/QuartzCoreInterface.h> #ifndef NDEBUG #include <wtf/CurrentTime.h> #endif -#ifdef DEBUG_ALL -#pragma comment(lib, "QuartzCore_debug") -#pragma comment(lib, "QuartzCoreInterface_debug") -#else -#pragma comment(lib, "QuartzCore") -#pragma comment(lib, "QuartzCoreInterface") -#endif - namespace WebCore { using namespace std; -static void displayInContext(CACFLayerRef layer, CGContextRef context) +static void displayCallback(CACFLayerRef layer, CGContextRef context) { ASSERT_ARG(layer, WKCACFLayer::layer(layer)); - WKCACFLayer::layer(layer)->display(context); + WKCACFLayer::layer(layer)->drawInContext(context); } -#define STATIC_CACF_STRING(name) \ - static CFStringRef name() \ - { \ - static CFStringRef name = wkqcCFStringRef(wkqc##name); \ - return name; \ - } - -STATIC_CACF_STRING(kCACFLayer) -STATIC_CACF_STRING(kCACFTransformLayer) -STATIC_CACF_STRING(kCACFGravityCenter) -STATIC_CACF_STRING(kCACFGravityTop) -STATIC_CACF_STRING(kCACFGravityBottom) -STATIC_CACF_STRING(kCACFGravityLeft) -STATIC_CACF_STRING(kCACFGravityRight) -STATIC_CACF_STRING(kCACFGravityTopLeft) -STATIC_CACF_STRING(kCACFGravityTopRight) -STATIC_CACF_STRING(kCACFGravityBottomLeft) -STATIC_CACF_STRING(kCACFGravityBottomRight) -STATIC_CACF_STRING(kCACFGravityResize) -STATIC_CACF_STRING(kCACFGravityResizeAspect) -STATIC_CACF_STRING(kCACFGravityResizeAspectFill) -STATIC_CACF_STRING(kCACFFilterLinear) -STATIC_CACF_STRING(kCACFFilterNearest) -STATIC_CACF_STRING(kCACFFilterTrilinear) -STATIC_CACF_STRING(kCACFFilterLanczos) - static CFStringRef toCACFLayerType(WKCACFLayer::LayerType type) { switch (type) { - case WKCACFLayer::Layer: return kCACFLayer(); - case WKCACFLayer::TransformLayer: return kCACFTransformLayer(); + case WKCACFLayer::Layer: return kCACFLayer; + case WKCACFLayer::TransformLayer: return kCACFTransformLayer; default: return 0; } } @@ -98,55 +63,55 @@ static CFStringRef toCACFLayerType(WKCACFLayer::LayerType type) static CFStringRef toCACFContentsGravityType(WKCACFLayer::ContentsGravityType type) { switch (type) { - case WKCACFLayer::Center: return kCACFGravityCenter(); - case WKCACFLayer::Top: return kCACFGravityTop(); - case WKCACFLayer::Bottom: return kCACFGravityBottom(); - case WKCACFLayer::Left: return kCACFGravityLeft(); - case WKCACFLayer::Right: return kCACFGravityRight(); - case WKCACFLayer::TopLeft: return kCACFGravityTopLeft(); - case WKCACFLayer::TopRight: return kCACFGravityTopRight(); - case WKCACFLayer::BottomLeft: return kCACFGravityBottomLeft(); - case WKCACFLayer::BottomRight: return kCACFGravityBottomRight(); - case WKCACFLayer::Resize: return kCACFGravityResize(); - case WKCACFLayer::ResizeAspect: return kCACFGravityResizeAspect(); - case WKCACFLayer::ResizeAspectFill: return kCACFGravityResizeAspectFill(); + case WKCACFLayer::Center: return kCACFGravityCenter; + case WKCACFLayer::Top: return kCACFGravityTop; + case WKCACFLayer::Bottom: return kCACFGravityBottom; + case WKCACFLayer::Left: return kCACFGravityLeft; + case WKCACFLayer::Right: return kCACFGravityRight; + case WKCACFLayer::TopLeft: return kCACFGravityTopLeft; + case WKCACFLayer::TopRight: return kCACFGravityTopRight; + case WKCACFLayer::BottomLeft: return kCACFGravityBottomLeft; + case WKCACFLayer::BottomRight: return kCACFGravityBottomRight; + case WKCACFLayer::Resize: return kCACFGravityResize; + case WKCACFLayer::ResizeAspect: return kCACFGravityResizeAspect; + case WKCACFLayer::ResizeAspectFill: return kCACFGravityResizeAspectFill; default: return 0; } } static WKCACFLayer::ContentsGravityType fromCACFContentsGravityType(CFStringRef string) { - if (CFEqual(string, kCACFGravityTop())) + if (CFEqual(string, kCACFGravityTop)) return WKCACFLayer::Top; - if (CFEqual(string, kCACFGravityBottom())) + if (CFEqual(string, kCACFGravityBottom)) return WKCACFLayer::Bottom; - if (CFEqual(string, kCACFGravityLeft())) + if (CFEqual(string, kCACFGravityLeft)) return WKCACFLayer::Left; - if (CFEqual(string, kCACFGravityRight())) + if (CFEqual(string, kCACFGravityRight)) return WKCACFLayer::Right; - if (CFEqual(string, kCACFGravityTopLeft())) + if (CFEqual(string, kCACFGravityTopLeft)) return WKCACFLayer::TopLeft; - if (CFEqual(string, kCACFGravityTopRight())) + if (CFEqual(string, kCACFGravityTopRight)) return WKCACFLayer::TopRight; - if (CFEqual(string, kCACFGravityBottomLeft())) + if (CFEqual(string, kCACFGravityBottomLeft)) return WKCACFLayer::BottomLeft; - if (CFEqual(string, kCACFGravityBottomRight())) + if (CFEqual(string, kCACFGravityBottomRight)) return WKCACFLayer::BottomRight; - if (CFEqual(string, kCACFGravityResize())) + if (CFEqual(string, kCACFGravityResize)) return WKCACFLayer::Resize; - if (CFEqual(string, kCACFGravityResizeAspect())) + if (CFEqual(string, kCACFGravityResizeAspect)) return WKCACFLayer::ResizeAspect; - if (CFEqual(string, kCACFGravityResizeAspectFill())) + if (CFEqual(string, kCACFGravityResizeAspectFill)) return WKCACFLayer::ResizeAspectFill; return WKCACFLayer::Center; @@ -155,45 +120,44 @@ static WKCACFLayer::ContentsGravityType fromCACFContentsGravityType(CFStringRef static CFStringRef toCACFFilterType(WKCACFLayer::FilterType type) { switch (type) { - case WKCACFLayer::Linear: return kCACFFilterLinear(); - case WKCACFLayer::Nearest: return kCACFFilterNearest(); - case WKCACFLayer::Trilinear: return kCACFFilterTrilinear(); - case WKCACFLayer::Lanczos: return kCACFFilterLanczos(); + case WKCACFLayer::Linear: return kCACFFilterLinear; + case WKCACFLayer::Nearest: return kCACFFilterNearest; + case WKCACFLayer::Trilinear: return kCACFFilterTrilinear; + case WKCACFLayer::Lanczos: return kCACFFilterLanczos; default: return 0; } } static WKCACFLayer::FilterType fromCACFFilterType(CFStringRef string) { - if (CFEqual(string, kCACFFilterNearest())) + if (CFEqual(string, kCACFFilterNearest)) return WKCACFLayer::Nearest; - if (CFEqual(string, kCACFFilterTrilinear())) + if (CFEqual(string, kCACFFilterTrilinear)) return WKCACFLayer::Trilinear; - if (CFEqual(string, kCACFFilterLanczos())) + if (CFEqual(string, kCACFFilterLanczos)) return WKCACFLayer::Lanczos; return WKCACFLayer::Linear; } -PassRefPtr<WKCACFLayer> WKCACFLayer::create(LayerType type, GraphicsLayerCACF* owner) +PassRefPtr<WKCACFLayer> WKCACFLayer::create(LayerType type) { if (!WKCACFLayerRenderer::acceleratedCompositingAvailable()) return 0; - return adoptRef(new WKCACFLayer(type, owner)); + return adoptRef(new WKCACFLayer(type)); } // FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually // get destroyed in debug builds. A static counter could accomplish this pretty easily. -WKCACFLayer::WKCACFLayer(LayerType type, GraphicsLayerCACF* owner) +WKCACFLayer::WKCACFLayer(LayerType type) : m_layer(AdoptCF, CACFLayerCreate(toCACFLayerType(type))) , m_needsDisplayOnBoundsChange(false) - , m_owner(owner) { CACFLayerSetUserData(layer(), this); - CACFLayerSetDisplayCallback(layer(), displayInContext); + CACFLayerSetDisplayCallback(layer(), displayCallback); } WKCACFLayer::~WKCACFLayer() @@ -205,64 +169,6 @@ WKCACFLayer::~WKCACFLayer() CACFLayerSetDisplayCallback(layer(), 0); } -void WKCACFLayer::display(PlatformGraphicsContext* context) -{ - if (!m_owner) - return; - - CGContextSaveGState(context); - - CGRect layerBounds = bounds(); - if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { - CGContextScaleCTM(context, 1, -1); - CGContextTranslateCTM(context, 0, -layerBounds.size.height); - } - - if (m_owner->client()) { - GraphicsContext graphicsContext(context); - - // It's important to get the clip from the context, because it may be significantly - // smaller than the layer bounds (e.g. tiled layers) - CGRect clipBounds = CGContextGetClipBoundingBox(context); - IntRect clip(enclosingIntRect(clipBounds)); - m_owner->paintGraphicsLayerContents(graphicsContext, clip); - } -#ifndef NDEBUG - else { - ASSERT_NOT_REACHED(); - - // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color, - // so CA never makes backing store for it (which is what -setNeedsDisplay will do above). - CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f); - CGContextFillRect(context, layerBounds); - } -#endif - - if (m_owner->showRepaintCounter()) { - char text[16]; // that's a lot of repaints - _snprintf(text, sizeof(text), "%d", m_owner->incrementRepaintCount()); - - CGContextSaveGState(context); - CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f); - - CGRect aBounds = layerBounds; - - aBounds.size.width = 10 + 12 * strlen(text); - aBounds.size.height = 25; - CGContextFillRect(context, aBounds); - - CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f); - - CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f)); - CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman); - CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text)); - - CGContextRestoreGState(context); - } - - CGContextRestoreGState(context); -} - void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context) { CACFContextSetLayer(context, layer()); @@ -271,7 +177,9 @@ void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context) void WKCACFLayer::setNeedsCommit() { - CACFContextRef context = CACFLayerGetContext(rootLayer()->layer()); + WKCACFLayer* root = rootLayer(); + + CACFContextRef context = CACFLayerGetContext(root->layer()); // The context might now be set yet. This happens if a property gets set // before placing the layer in the tree. In this case we don't need to @@ -280,16 +188,14 @@ void WKCACFLayer::setNeedsCommit() if (context) WKCACFContextFlusher::shared().addContext(context); - // Call notifySyncRequired(), which in this implementation plumbs through to - // call setRootLayerNeedsDisplay() on the WebView, which causes the CACFRenderer - // to render a frame. - if (m_owner) - m_owner->notifySyncRequired(); + // Call setNeedsRender on the root layer, which will cause a render to + // happen in WKCACFLayerRenderer + root->setNeedsRender(); } bool WKCACFLayer::isTransformLayer() const { - return CACFLayerGetClass(layer()) == kCACFTransformLayer(); + return CACFLayerGetClass(layer()) == kCACFTransformLayer; } void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer) @@ -300,6 +206,7 @@ void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer) void WKCACFLayer::insertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index) { index = min(index, numSublayers()); + sublayer->removeFromSuperlayer(); CACFLayerInsertSublayer(layer(), sublayer->layer(), index); setNeedsCommit(); } @@ -344,21 +251,17 @@ void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer if (reference == newLayer) return; - if (!newLayer) { - removeSublayer(reference); - return; - } - - newLayer->removeFromSuperlayer(); - int referenceIndex = indexOfSublayer(reference); ASSERT(referenceIndex != -1); if (referenceIndex == -1) return; - // FIXME: Can we make this more efficient? The current CACF API doesn't seem to give us a way to do so. reference->removeFromSuperlayer(); - insertSublayer(newLayer, referenceIndex); + + if (newLayer) { + newLayer->removeFromSuperlayer(); + insertSublayer(newLayer, referenceIndex); + } } void WKCACFLayer::removeFromSuperlayer() @@ -367,21 +270,10 @@ void WKCACFLayer::removeFromSuperlayer() if (!superlayer) return; - superlayer->removeSublayer(this); CACFLayerRemoveFromSuperlayer(layer()); superlayer->setNeedsCommit(); } -void WKCACFLayer::removeSublayer(const WKCACFLayer* sublayer) -{ - int foundIndex = indexOfSublayer(sublayer); - if (foundIndex == -1) - return; - - CACFLayerRemoveFromSuperlayer(sublayer->layer()); - setNeedsCommit(); -} - const WKCACFLayer* WKCACFLayer::sublayerAtIndex(int index) const { CFArrayRef sublayers = CACFLayerGetSublayers(layer()); @@ -490,29 +382,18 @@ void WKCACFLayer::removeAllSublayers() void WKCACFLayer::setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) { - if (sublayers.isEmpty()) - CACFLayerSetSublayers(layer(), 0); - else { - // Create a vector of CACFLayers. - Vector<const void*> layers; - for (size_t i = 0; i < sublayers.size(); i++) - layers.append(sublayers[i]->layer()); - - RetainPtr<CFArrayRef> layersArray(AdoptCF, CFArrayCreate(0, layers.data(), layers.size(), 0)); - CACFLayerSetSublayers(layer(), layersArray.get()); - } - - setNeedsCommit(); -} + // Remove all the current sublayers and add the passed layers + CACFLayerSetSublayers(layer(), 0); -void WKCACFLayer::moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer) -{ - if (!fromLayer || !toLayer) - return; + // Perform removeFromSuperLayer in a separate pass. CACF requires superlayer to + // be null or CACFLayerInsertSublayer silently fails. + for (size_t i = 0; i < sublayers.size(); i++) + CACFLayerRemoveFromSuperlayer(sublayers[i]->layer()); + + for (size_t i = 0; i < sublayers.size(); i++) + CACFLayerInsertSublayer(layer(), sublayers[i]->layer(), i); - CACFLayerSetSublayers(toLayer->layer(), CACFLayerGetSublayers(fromLayer->layer())); - fromLayer->setNeedsCommit(); - toLayer->setNeedsCommit(); + setNeedsCommit(); } WKCACFLayer* WKCACFLayer::superlayer() const @@ -523,18 +404,15 @@ WKCACFLayer* WKCACFLayer::superlayer() const return WKCACFLayer::layer(super); } -void WKCACFLayer::setNeedsDisplay(const CGRect& dirtyRect) +void WKCACFLayer::setNeedsDisplay(const CGRect* dirtyRect) { - if (m_owner) - CACFLayerSetNeedsDisplay(layer(), &dirtyRect); + CACFLayerSetNeedsDisplay(layer(), dirtyRect); setNeedsCommit(); } void WKCACFLayer::setNeedsDisplay() { - if (m_owner) - CACFLayerSetNeedsDisplay(layer(), 0); - setNeedsCommit(); + setNeedsDisplay(0); } #ifndef NDEBUG @@ -570,11 +448,11 @@ void WKCACFLayer::printLayer(int indent) const CGPoint layerAnchorPoint = anchorPoint(); CGRect layerBounds = bounds(); printIndent(indent); - fprintf(stderr, "(%s [%g %g %g] [%g %g %g %g] [%g %g %g]\n", + fprintf(stderr, "(%s [%g %g %g] [%g %g %g %g] [%g %g %g] superlayer=%p\n", isTransformLayer() ? "transform-layer" : "layer", layerPosition.x, layerPosition.y, zPosition(), layerBounds.origin.x, layerBounds.origin.y, layerBounds.size.width, layerBounds.size.height, - layerAnchorPoint.x, layerAnchorPoint.y, anchorPointZ()); + layerAnchorPoint.x, layerAnchorPoint.y, anchorPointZ(), superlayer()); // Print name if needed String layerName = name(); diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h index e5568c9..f1b2613 100644 --- a/WebCore/platform/graphics/win/WKCACFLayer.h +++ b/WebCore/platform/graphics/win/WKCACFLayer.h @@ -39,7 +39,6 @@ #include <wtf/Vector.h> #include "GraphicsContext.h" -#include "GraphicsLayerCACF.h" #include "PlatformString.h" #include "TransformationMatrix.h" @@ -55,10 +54,15 @@ public: enum ContentsGravityType { Center, Top, Bottom, Left, Right, TopLeft, TopRight, BottomLeft, BottomRight, Resize, ResizeAspect, ResizeAspectFill }; - static PassRefPtr<WKCACFLayer> create(LayerType, GraphicsLayerCACF* owner = 0); + static PassRefPtr<WKCACFLayer> create(LayerType); static WKCACFLayer* layer(CACFLayerRef layer) { return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer)); } - ~WKCACFLayer(); + virtual ~WKCACFLayer(); + + virtual void setNeedsRender() { } + virtual void drawInContext(PlatformGraphicsContext*) { } + virtual void setNeedsDisplay(const CGRect* dirtyRect); + void setNeedsDisplay(); // Makes this layer the root when the passed context is rendered void becomeRootLayerForContext(CACFContextRef); @@ -106,8 +110,6 @@ public: return RetainPtr<CFTypeRef>(AdoptCF, CGColorCreateGenericRGB(color.red(), color.green(), color.blue(), color.alpha())); } - void display(PlatformGraphicsContext*); - bool isTransformLayer() const; void addSublayer(PassRefPtr<WKCACFLayer> sublayer); @@ -116,7 +118,6 @@ public: void insertSublayerBelowLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); void replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer>); void removeFromSuperlayer(); - static void moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer); WKCACFLayer* ancestorOrSelfWithSuperlayer(WKCACFLayer*) const; @@ -180,9 +181,6 @@ public: void setName(const String& name) { CACFLayerSetName(layer(), RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get()); } String name() const { return CACFLayerGetName(layer()); } - void setNeedsDisplay(const CGRect& dirtyRect); - void setNeedsDisplay(); - void setNeedsDisplayOnBoundsChange(bool needsDisplay) { m_needsDisplayOnBoundsChange = needsDisplay; } void setOpacity(float opacity) { CACFLayerSetOpacity(layer(), opacity); setNeedsCommit(); } @@ -228,10 +226,12 @@ public: void printTree() const; #endif -private: - WKCACFLayer(LayerType, GraphicsLayerCACF* owner); +protected: + WKCACFLayer(LayerType); void setNeedsCommit(); + +private: CACFLayerRef layer() const { return m_layer.get(); } size_t numSublayers() const { @@ -255,7 +255,6 @@ private: RetainPtr<CACFLayerRef> m_layer; bool m_needsDisplayOnBoundsChange; - GraphicsLayerCACF* m_owner; }; } diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp index 78ebb9d..1b14846 100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp @@ -27,16 +27,22 @@ #if USE(ACCELERATED_COMPOSITING) +#ifndef NDEBUG +#define D3D_DEBUG_INFO +#endif + #include "WKCACFLayerRenderer.h" #include "WKCACFContextFlusher.h" #include "WKCACFLayer.h" +#include "WebCoreInstanceHandle.h" #include <CoreGraphics/CGSRegion.h> #include <QuartzCore/CACFContext.h> #include <QuartzCore/CARenderOGL.h> -#include <QuartzCoreInterface/QuartzCoreInterface.h> #include <wtf/HashMap.h> #include <wtf/OwnArrayPtr.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> #include <wtf/StdLibExtras.h> #include <d3d9.h> #include <d3dx9.h> @@ -75,6 +81,33 @@ inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect) namespace WebCore { +// Subclass of WKCACFLayer to allow the root layer to have a back pointer to the layer renderer +// to fire off a draw +class WKCACFRootLayer : public WKCACFLayer { +public: + WKCACFRootLayer(WKCACFLayerRenderer* renderer) + : WKCACFLayer(WKCACFLayer::Layer) + { + m_renderer = renderer; + } + + static PassRefPtr<WKCACFRootLayer> create(WKCACFLayerRenderer* renderer) + { + if (!WKCACFLayerRenderer::acceleratedCompositingAvailable()) + return 0; + return adoptRef(new WKCACFRootLayer(renderer)); + } + + virtual void setNeedsRender() { m_renderer->renderSoon(); } + + // Overload this to avoid calling setNeedsDisplay on the layer, which would override the contents + // we have placed on the root layer. + virtual void setNeedsDisplay(const CGRect* dirtyRect) { setNeedsCommit(); } + +private: + WKCACFLayerRenderer* m_renderer; +}; + typedef HashMap<CACFContextRef, WKCACFLayerRenderer*> ContextToWindowMap; static ContextToWindowMap& windowsForContexts() @@ -95,6 +128,28 @@ static D3DPRESENT_PARAMETERS initialPresentationParameters() return parameters; } +// FIXME: <rdar://6507851> Share this code with CoreAnimation. +static bool hardwareCapabilitiesIndicateCoreAnimationSupport(const D3DCAPS9& caps) +{ + // CoreAnimation needs two or more texture units. + if (caps.MaxTextureBlendStages < 2) + return false; + + // CoreAnimation needs non-power-of-two textures. + if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && !(caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) + return false; + + // CoreAnimation needs vertex shader 2.0 or greater. + if (D3DSHADER_VERSION_MAJOR(caps.VertexShaderVersion) < 2) + return false; + + // CoreAnimation needs pixel shader 2.0 or greater. + if (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion) < 2) + return false; + + return true; +} + bool WKCACFLayerRenderer::acceleratedCompositingAvailable() { static bool available; @@ -104,17 +159,50 @@ bool WKCACFLayerRenderer::acceleratedCompositingAvailable() return available; tested = true; + + // Initialize available to true since this function will be called from a + // propagation within createRenderer(). We want to be able to return true + // when that happens so that the test can continue. + available = true; + HMODULE library = LoadLibrary(TEXT("d3d9.dll")); - if (!library) - return false; + if (!library) { + available = false; + return available; + } FreeLibrary(library); +#ifdef DEBUG_ALL + library = LoadLibrary(TEXT("QuartzCore_debug.dll")); +#else library = LoadLibrary(TEXT("QuartzCore.dll")); - if (!library) - return false; +#endif + if (!library) { + available = false; + return available; + } FreeLibrary(library); - available = true; + + // Make a dummy HWND. + WNDCLASSEX wcex = { 0 }; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.lpfnWndProc = DefWindowProc; + wcex.hInstance = WebCore::instanceHandle(); + wcex.lpszClassName = L"CoreAnimationTesterWindowClass"; + ::RegisterClassEx(&wcex); + HWND testWindow = ::CreateWindow(L"CoreAnimationTesterWindowClass", L"CoreAnimationTesterWindow", WS_POPUP, -500, -500, 0, 0, 0, 0, 0, 0); + + if (!testWindow) { + available = false; + return available; + } + + OwnPtr<WKCACFLayerRenderer> testLayerRenderer = WKCACFLayerRenderer::create(); + testLayerRenderer->setHostWindow(testWindow); + available = testLayerRenderer->createRenderer(); + ::DestroyWindow(testWindow); + return available; } @@ -140,7 +228,9 @@ WKCACFLayerRenderer::WKCACFLayerRenderer() , m_renderer(0) , m_hostWindow(0) , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired) - , m_scrollFrame(0, 0, 1, 1) // Default to 1 to avoid 0 size frames + , m_scrollPosition(0, 0) + , m_scrollSize(1, 1) + , m_backingStoreDirty(false) { #ifndef NDEBUG char* printTreeFlag = getenv("CA_PRINT_TREE"); @@ -153,15 +243,29 @@ WKCACFLayerRenderer::~WKCACFLayerRenderer() destroyRenderer(); } -void WKCACFLayerRenderer::setScrollFrame(const IntRect& scrollFrame) +WKCACFLayer* WKCACFLayerRenderer::rootLayer() const { - m_scrollFrame = scrollFrame; - CGRect frameBounds = bounds(); - m_scrollLayer->setBounds(CGRectMake(0, 0, m_scrollFrame.width(), m_scrollFrame.height())); - m_scrollLayer->setPosition(CGPointMake(0, frameBounds.size.height)); + return m_rootLayer.get(); +} - if (m_rootChildLayer) - m_rootChildLayer->setPosition(CGPointMake(-m_scrollFrame.x(), m_scrollFrame.height() + m_scrollFrame.y())); +void WKCACFLayerRenderer::setScrollFrame(const IntPoint& position, const IntSize& size) +{ + m_scrollSize = size; + m_scrollPosition = position; + + updateScrollFrame(); +} + +void WKCACFLayerRenderer::updateScrollFrame() +{ + CGRect frameBounds = bounds(); + m_clipLayer->setBounds(CGRectMake(0, 0, m_scrollSize.width(), m_scrollSize.height())); + m_clipLayer->setPosition(CGPointMake(0, frameBounds.size.height)); + if (m_rootChildLayer) { + CGRect rootBounds = m_rootChildLayer->bounds(); + m_scrollLayer->setBounds(rootBounds); + } + m_scrollLayer->setPosition(CGPointMake(-m_scrollPosition.x(), m_scrollPosition.y() + m_scrollSize.height())); } void WKCACFLayerRenderer::setRootContents(CGImageRef image) @@ -171,7 +275,7 @@ void WKCACFLayerRenderer::setRootContents(CGImageRef image) renderSoon(); } -void WKCACFLayerRenderer::setRootChildLayer(WebCore::PlatformLayer* layer) +void WKCACFLayerRenderer::setRootChildLayer(WKCACFLayer* layer) { if (!m_scrollLayer) return; @@ -180,30 +284,28 @@ void WKCACFLayerRenderer::setRootChildLayer(WebCore::PlatformLayer* layer) m_rootChildLayer = layer; if (layer) { m_scrollLayer->addSublayer(layer); - - // Set the frame - layer->setAnchorPoint(CGPointMake(0, 1)); - setScrollFrame(m_scrollFrame); + // Adjust the scroll frame accordingly + updateScrollFrame(); } } void WKCACFLayerRenderer::setNeedsDisplay() { ASSERT(m_rootLayer); - m_rootLayer->setNeedsDisplay(); + m_rootLayer->setNeedsDisplay(0); renderSoon(); } -void WKCACFLayerRenderer::createRenderer() +bool WKCACFLayerRenderer::createRenderer() { if (m_triedToCreateD3DRenderer) - return; + return m_d3dDevice; m_triedToCreateD3DRenderer = true; D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); if (!d3d() || !::IsWindow(m_hostWindow)) - return; + return false; // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero @@ -216,8 +318,23 @@ void WKCACFLayerRenderer::createRenderer() parameters.BackBufferHeight = 1; } - if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, ¶meters, &m_d3dDevice))) - return; + COMPtr<IDirect3DDevice9> device; + if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, ¶meters, &device))) + return false; + + // Now that we've created the IDirect3DDevice9 based on the capabilities we + // got from the IDirect3D9 global object, we requery the device for its + // actual capabilities. The capabilities returned by the device can + // sometimes be more complete, for example when using software vertex + // processing. + D3DCAPS9 deviceCaps; + if (FAILED(device->GetDeviceCaps(&deviceCaps))) + return false; + + if (!hardwareCapabilitiesIndicateCoreAnimationSupport(deviceCaps)) + return false; + + m_d3dDevice = device; D3DXMATRIXA16 projection; D3DXMatrixOrthoOffCenterRH(&projection, rect.left, rect.right, rect.top, rect.bottom, -1.0f, 1.0f); @@ -228,17 +345,32 @@ void WKCACFLayerRenderer::createRenderer() windowsForContexts().set(m_context.get(), this); m_renderContext = static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get())); - m_renderer = CARenderOGLNew(wkqcCARenderOGLCallbacks(wkqckCARenderDX9Callbacks), m_d3dDevice.get(), 0); - - // Create the root hierarchy - m_rootLayer = WKCACFLayer::create(WKCACFLayer::Layer); + m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0); + + // Create the root hierarchy. + // Under the root layer, we have a clipping layer to clip the content, + // that contains a scroll layer that we use for scrolling the content. + // The root layer is the size of the client area of the window. + // The clipping layer is the size of the WebView client area (window less the scrollbars). + // The scroll layer is the size of the root child layer. + // Resizing the window will change the bounds of the rootLayer and the clip layer and will not + // cause any repositioning. + // Scrolling will affect only the position of the scroll layer without affecting the bounds. + + m_rootLayer = WKCACFRootLayer::create(this); m_rootLayer->setName("WKCACFLayerRenderer rootLayer"); + + m_clipLayer = WKCACFLayer::create(WKCACFLayer::Layer); + m_clipLayer->setName("WKCACFLayerRenderer clipLayer"); + m_scrollLayer = WKCACFLayer::create(WKCACFLayer::Layer); m_scrollLayer->setName("WKCACFLayerRenderer scrollLayer"); - m_rootLayer->addSublayer(m_scrollLayer); - m_scrollLayer->setMasksToBounds(true); + m_rootLayer->addSublayer(m_clipLayer); + m_clipLayer->addSublayer(m_scrollLayer); + m_clipLayer->setMasksToBounds(true); m_scrollLayer->setAnchorPoint(CGPointMake(0, 1)); + m_clipLayer->setAnchorPoint(CGPointMake(0, 1)); #ifndef NDEBUG CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204)); @@ -251,6 +383,8 @@ void WKCACFLayerRenderer::createRenderer() if (m_context) m_rootLayer->becomeRootLayerForContext(m_context.get()); + + return true; } void WKCACFLayerRenderer::destroyRenderer() @@ -269,6 +403,7 @@ void WKCACFLayerRenderer::destroyRenderer() s_d3d = 0; m_rootLayer = 0; + m_clipLayer = 0; m_scrollLayer = 0; m_rootChildLayer = 0; @@ -285,7 +420,7 @@ void WKCACFLayerRenderer::resize() if (m_rootLayer) { m_rootLayer->setFrame(bounds()); WKCACFContextFlusher::shared().flushAllContexts(); - setScrollFrame(m_scrollFrame); + updateScrollFrame(); } } @@ -331,6 +466,15 @@ void WKCACFLayerRenderer::paint() if (!m_d3dDevice) return; + if (m_backingStoreDirty) { + // If the backing store is still dirty when we are about to draw the + // composited content, we need to force the window to paint into the + // backing store. The paint will only paint the dirty region that + // if being tracked in WebView. + UpdateWindow(m_hostWindow); + return; + } + Vector<CGRect> dirtyRects; getDirtyRects(m_hostWindow, dirtyRects); render(dirtyRects); diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h index 4e76f55..ea710b6 100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h @@ -47,6 +47,8 @@ typedef struct _CARenderOGLContext CARenderOGLContext; namespace WebCore { +class WKCACFRootLayer; + // FIXME: Currently there is a WKCACFLayerRenderer for each WebView and each // has its own CARenderOGLContext and Direct3DDevice9, which is inefficient. // (https://bugs.webkit.org/show_bug.cgi?id=31855) @@ -58,19 +60,20 @@ public: static bool acceleratedCompositingAvailable(); static void didFlushContext(CACFContextRef); - void setScrollFrame(const IntRect&); + void setScrollFrame(const IntPoint&, const IntSize&); void setRootContents(CGImageRef); - void setRootChildLayer(WebCore::PlatformLayer* layer); + void setRootChildLayer(WKCACFLayer* layer); void setNeedsDisplay(); - void setHostWindow(HWND window) { m_hostWindow = window; createRenderer(); } - - void createRenderer(); + void setHostWindow(HWND window) { m_hostWindow = window; } + void setBackingStoreDirty(bool dirty) { m_backingStoreDirty = dirty; } + bool createRenderer(); void destroyRenderer(); void resize(); void renderSoon(); + void updateScrollFrame(); protected: - WKCACFLayer* rootLayer() const { return m_rootLayer.get(); } + WKCACFLayer* rootLayer() const; private: WKCACFLayerRenderer(); @@ -87,17 +90,19 @@ private: bool m_triedToCreateD3DRenderer; COMPtr<IDirect3DDevice9> m_d3dDevice; - RefPtr<WKCACFLayer> m_rootLayer; + RefPtr<WKCACFRootLayer> m_rootLayer; RefPtr<WKCACFLayer> m_viewLayer; RefPtr<WKCACFLayer> m_scrollLayer; RefPtr<WKCACFLayer> m_rootChildLayer; + RefPtr<WKCACFLayer> m_clipLayer; RetainPtr<CACFContextRef> m_context; CARenderContext* m_renderContext; CARenderOGLContext* m_renderer; HWND m_hostWindow; Timer<WKCACFLayerRenderer> m_renderTimer; - IntRect m_scrollFrame; - + IntPoint m_scrollPosition; + IntSize m_scrollSize; + bool m_backingStoreDirty; #ifndef NDEBUG bool m_printTree; #endif diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp index 699ff25..d5f8a5a 100644 --- a/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp @@ -25,6 +25,7 @@ #include "Base64.h" #include "CachedFont.h" #include "FontPlatformData.h" +#include "SharedBuffer.h" #include <wtf/RandomNumber.h> namespace WebCore { diff --git a/WebCore/platform/graphics/wince/FontPlatformData.cpp b/WebCore/platform/graphics/wince/FontPlatformData.cpp index f0db2ff..74cadc2 100644 --- a/WebCore/platform/graphics/wince/FontPlatformData.cpp +++ b/WebCore/platform/graphics/wince/FontPlatformData.cpp @@ -26,8 +26,10 @@ #include "FontData.h" #include "PlatformString.h" #include "SimpleFontData.h" +#include "StringHash.h" #include "UnicodeRange.h" #include "wtf/OwnPtr.h" +#include <wtf/StdLibExtras.h> #include <windows.h> #include <mlang.h> diff --git a/WebCore/platform/graphics/wince/FontWince.cpp b/WebCore/platform/graphics/wince/FontWince.cpp index 6c03712..f8b1886 100644 --- a/WebCore/platform/graphics/wince/FontWince.cpp +++ b/WebCore/platform/graphics/wince/FontWince.cpp @@ -235,7 +235,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F } } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { TextRunComponents components; int w = generateComponents(&components, *this, run); diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp index 42e94a4..a7bb695 100644 --- a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp +++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp @@ -23,6 +23,7 @@ #include "AffineTransform.h" #include "CharacterNames.h" +#include "Font.h" #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContextPrivate.h" diff --git a/WebCore/platform/graphics/wince/ImageBufferWince.cpp b/WebCore/platform/graphics/wince/ImageBufferWince.cpp index 9624e26..ac3a630 100644 --- a/WebCore/platform/graphics/wince/ImageBufferWince.cpp +++ b/WebCore/platform/graphics/wince/ImageBufferWince.cpp @@ -27,6 +27,7 @@ #include "JPEGEncoder.h" #include "PNGEncoder.h" #include "SharedBitmap.h" +#include <wtf/UnusedParam.h> namespace WebCore { diff --git a/WebCore/platform/graphics/wince/PlatformPathWince.h b/WebCore/platform/graphics/wince/PlatformPathWince.h index e614cec..614e8c5 100644 --- a/WebCore/platform/graphics/wince/PlatformPathWince.h +++ b/WebCore/platform/graphics/wince/PlatformPathWince.h @@ -20,6 +20,11 @@ #ifndef PlatformPathWince_h #define PlatformPathWince_h +#include "FloatPoint.h" +#include "FloatRect.h" +#include "Path.h" +#include <wtf/Vector.h> + namespace WebCore { class GraphicsContext; diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h index be00edc..ecb957e 100644 --- a/WebCore/platform/graphics/wx/FontPlatformData.h +++ b/WebCore/platform/graphics/wx/FontPlatformData.h @@ -31,9 +31,9 @@ #include "FontDescription.h" #include "AtomicString.h" -#include "CString.h" #include "StringImpl.h" #include <wtf/RefPtr.h> +#include <wtf/text/CString.h> #include <wx/defs.h> #include <wx/font.h> @@ -65,21 +65,25 @@ public: FontPlatformData(WTF::HashTableDeletedValueType) : m_fontState(DELETED), - m_font(0) + m_font(0), + m_size(0) { } ~FontPlatformData(); FontPlatformData(const FontDescription&, const AtomicString&); + FontPlatformData(float size, bool bold, bool italic) : m_fontState(UNINITIALIZED) , m_font(0) + , m_size(size) { } FontPlatformData() : m_fontState(UNINITIALIZED) , m_font(0) + , m_size(0) { } @@ -99,6 +103,8 @@ public: } unsigned computeHash() const; + + float size() const { return m_size; } bool operator==(const FontPlatformData& other) const { @@ -127,6 +133,7 @@ public: private: WTF::RefPtr<FontHolder> m_font; FontState m_fontState; + float m_size; }; } diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index c9646d7..a75d244 100644 --- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -100,6 +100,7 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri ); #endif m_fontState = VALID; + m_size = desc.computedPixelSize(); } diff --git a/WebCore/platform/graphics/wx/FontWx.cpp b/WebCore/platform/graphics/wx/FontWx.cpp index 98b5a0a..dce3841 100644 --- a/WebCore/platform/graphics/wx/FontWx.cpp +++ b/WebCore/platform/graphics/wx/FontWx.cpp @@ -121,7 +121,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const { #if OS(WINDOWS) UniscribeController controller(this, run, fallbackFonts); diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 8e1a391..2298d6a 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -91,6 +91,7 @@ public: #if USE(WXGC) wxGCDC* context; + wxGraphicsPath currentPath; #else wxWindowDC* context; #endif @@ -124,6 +125,9 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) } #if USE(WXGC) m_data->context = (wxGCDC*)context; + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + if (gc) + m_data->currentPath = gc->CreatePath(); #else m_data->context = (wxWindowDC*)context; #endif @@ -323,6 +327,11 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect&) notImplemented(); } +void GraphicsContext::clipPath(WindRule) +{ + notImplemented(); +} + void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) { if (paintingDisabled()) @@ -361,7 +370,15 @@ void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) AffineTransform GraphicsContext::getCTM() const { - notImplemented(); +#if USE(WXGC) + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + if (gc) { + wxGraphicsMatrix matrix = gc->GetTransform(); + double a, b, c, d, e, f; + matrix.Get(&a, &b, &c, &d, &e, &f); + return AffineTransform(a, b, c, d, e, f); + } +#endif return AffineTransform(); } @@ -435,12 +452,19 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op) void GraphicsContext::beginPath() { - notImplemented(); +#if USE(WXGC) + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + if (gc) + m_data->currentPath = gc->CreatePath(); +#endif } void GraphicsContext::addPath(const Path& path) { - notImplemented(); +#if USE(WXGC) + if (path.platformPath()) + m_data->currentPath.AddPath(*path.platformPath()); +#endif } void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) @@ -476,7 +500,11 @@ void GraphicsContext::concatCTM(const AffineTransform& transform) if (paintingDisabled()) return; - notImplemented(); +#if USE(WXGC) + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + if (gc) + gc->ConcatTransform(transform); +#endif return; } @@ -498,10 +526,20 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const void GraphicsContext::fillPath() { +#if USE(WXGC) + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + if (gc) + gc->FillPath(m_data->currentPath); +#endif } void GraphicsContext::strokePath() { +#if USE(WXGC) + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + if (gc) + gc->StrokePath(m_data->currentPath); +#endif } void GraphicsContext::drawPath() @@ -551,6 +589,11 @@ void GraphicsContext::setLineCap(LineCap) notImplemented(); } +void GraphicsContext::setLineDash(const DashArray&, float dashOffset) +{ + notImplemented(); +} + void GraphicsContext::setLineJoin(LineJoin) { notImplemented(); diff --git a/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/WebCore/platform/graphics/wx/ImageBufferWx.cpp index 49f3f3b..6cc611e 100644 --- a/WebCore/platform/graphics/wx/ImageBufferWx.cpp +++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp @@ -87,4 +87,9 @@ Image* ImageBuffer::image() const return 0; } +void ImageBuffer::platformTransformColorSpace(const Vector<int>&) +{ + notImplemented(); +} + } // namespace WebCore diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp index c246ec1..b51bde8 100644 --- a/WebCore/platform/graphics/wx/ImageWx.cpp +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -33,6 +33,7 @@ #include "GraphicsContext.h" #include "ImageObserver.h" #include "NotImplemented.h" +#include "SharedBuffer.h" #include <math.h> #include <stdio.h> diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp index 6c115ac..2305be0 100644 --- a/WebCore/platform/graphics/wx/PathWx.cpp +++ b/WebCore/platform/graphics/wx/PathWx.cpp @@ -30,6 +30,7 @@ #include "FloatPoint.h" #include "FloatRect.h" #include "NotImplemented.h" +#include "PlatformString.h" #include "StrokeStyleApplier.h" #include <stdio.h> @@ -110,10 +111,22 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) return FloatRect(); } -Path& Path::operator=(const Path&) +bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const +{ + notImplemented(); + return false; +} + +String Path::debugString() const +{ + notImplemented(); + return String(); +} + +Path& Path::operator=(const Path& path) { - notImplemented(); - return*this; + *m_path = *path.platformPath(); + return *this; } void Path::clear() @@ -219,8 +232,8 @@ bool Path::isEmpty() const { #if USE(WXGC) if (m_path) { - wxDouble width, height; - m_path->GetBox(NULL, NULL, &width, &height); + wxDouble x, y, width, height; + m_path->GetBox(&x, &y, &width, &height); return (width == 0 && height == 0); } #endif diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp index d9fd2b3..3c8a1da 100644 --- a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp +++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp @@ -112,17 +112,19 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = false; } -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +GlyphMetrics SimpleFontData::platformMetricsForGlyph(Glyph glyph, GlyphMetricsMode) const { + GlyphMetrics metrics; #if __WXMSW__ // under Windows / wxMSW we currently always use GDI fonts. - return widthForGDIGlyph(glyph); + metrics.horizontalAdvance = widthForGDIGlyph(glyph); #else // TODO: fix this! Make GetTextExtents a method of wxFont in 2.9 int width = 10; GetTextExtent(*m_platformData.font(), (wxChar)glyph, &width, NULL); - return width; + metrics.horizontalAdvance = width; #endif + return metrics; } #if OS(WINDOWS) |