diff options
author | Iain Merrick <husky@google.com> | 2010-09-13 16:35:48 +0100 |
---|---|---|
committer | Iain Merrick <husky@google.com> | 2010-09-16 12:10:42 +0100 |
commit | 5abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306 (patch) | |
tree | ddce1aa5e3b6967a69691892e500897558ff8ab6 /WebCore/platform/graphics | |
parent | 12bec63ec71e46baba27f0bd9bd9d8067683690a (diff) | |
download | external_webkit-5abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306.zip external_webkit-5abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306.tar.gz external_webkit-5abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306.tar.bz2 |
Merge WebKit at r67178 : Initial merge by git.
Change-Id: I57e01163b6866cb029cdadf405a0394a3918bc18
Diffstat (limited to 'WebCore/platform/graphics')
87 files changed, 4205 insertions, 504 deletions
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp index 0e93d4f..a0cf5a4 100644 --- a/WebCore/platform/graphics/Font.cpp +++ b/WebCore/platform/graphics/Font.cpp @@ -277,6 +277,8 @@ Font::CodePath Font::codePath(const TextRun& run) const return Complex; #endif + CodePath result = Simple; + // Start from 0 since drawing and highlighting also measure the characters before run->from for (int i = 0; i < run.length(); i++) { const UChar c = run[i]; @@ -312,8 +314,10 @@ Font::CodePath Font::codePath(const TextRun& run) const if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics continue; - if (c <= 0x2000) - return SimpleWithGlyphOverflow; + if (c <= 0x2000) { + result = SimpleWithGlyphOverflow; + continue; + } if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols continue; @@ -329,7 +333,7 @@ Font::CodePath Font::codePath(const TextRun& run) const if (typesettingFeatures()) return Complex; - return Simple; + return result; } } diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index 94f3424..3dfdb20 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -467,7 +467,7 @@ void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorS { if (paintingDisabled() || !image) return; - + float tsw = src.width(); float tsh = src.height(); float tw = dest.width(); @@ -489,7 +489,7 @@ void GraphicsContext::drawImageBuffer(ImageBuffer* image, ColorSpace styleColorS } image->draw(this, styleColorSpace, dest, src, op, useLowQualityScale); - + if (useLowQualityScale) restore(); } @@ -571,6 +571,21 @@ void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&) } #endif +#if !PLATFORM(SKIA) +void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&) +{ +} + +void GraphicsContext::syncSoftwareCanvas() +{ +} + +void GraphicsContext::markDirtyRect(const IntRect&) +{ +} +#endif + + void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle& penStyle) { // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic @@ -600,14 +615,4 @@ void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2 } } -#if !PLATFORM(SKIA) -void GraphicsContext::setGraphicsContext3D(GraphicsContext3D*, const IntSize&) -{ -} - -void GraphicsContext::syncSoftwareCanvas() -{ -} -#endif - } diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index c5440f3..7863b95 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -21,7 +21,7 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef GraphicsContext_h @@ -131,16 +131,17 @@ namespace WebCore { const int cMisspellingLinePatternGapWidth = 1; class AffineTransform; + class DrawingBuffer; class Font; class Generator; class Gradient; - class GraphicsContext3D; class GraphicsContextPlatformPrivate; class GraphicsContextPrivate; class ImageBuffer; class KURL; class Path; class Pattern; + class SharedGraphicsContext3D; class TextRun; // These bits can be ORed together for a total of 8 possible text drawing modes. @@ -456,8 +457,9 @@ namespace WebCore { pattern getHaikuStrokeStyle(); #endif - void setGraphicsContext3D(GraphicsContext3D*, const IntSize&); + void setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&); void syncSoftwareCanvas(); + void markDirtyRect(const IntRect&); // Hints that a portion of the backing store is dirty. private: void savePlatformState(); diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 0f74cd5..68a580e 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -85,18 +85,18 @@ class FloatPoint3D; class GraphicsContext; class Image; class TextStream; -struct TimingFunction; +class TimingFunction; // Base class for animation values (also used for transitions). Here to // represent values for properties being animated via the GraphicsLayer, // without pulling in style-related data from outside of the platform directory. class AnimationValue : public Noncopyable { public: - AnimationValue(float keyTime, const TimingFunction* timingFunction = 0) + AnimationValue(float keyTime, PassRefPtr<TimingFunction> timingFunction = 0) : m_keyTime(keyTime) { if (timingFunction) - m_timingFunction = adoptPtr(new TimingFunction(*timingFunction)); + m_timingFunction = timingFunction; } virtual ~AnimationValue() { } @@ -106,13 +106,13 @@ public: private: float m_keyTime; - OwnPtr<TimingFunction> m_timingFunction; + RefPtr<TimingFunction> m_timingFunction; }; // Used to store one float value of an animation. class FloatAnimationValue : public AnimationValue { public: - FloatAnimationValue(float keyTime, float value, const TimingFunction* timingFunction = 0) + FloatAnimationValue(float keyTime, float value, PassRefPtr<TimingFunction> timingFunction = 0) : AnimationValue(keyTime, timingFunction) , m_value(value) { @@ -127,7 +127,7 @@ private: // Used to store one transform value in a keyframe list. class TransformAnimationValue : public AnimationValue { public: - TransformAnimationValue(float keyTime, const TransformOperations* value = 0, const TimingFunction* timingFunction = 0) + TransformAnimationValue(float keyTime, const TransformOperations* value = 0, PassRefPtr<TimingFunction> timingFunction = 0) : AnimationValue(keyTime, timingFunction) { if (value) diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index a5db85f..2588d8d 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -699,6 +699,12 @@ void MediaPlayer::rateChanged() m_mediaPlayerClient->mediaPlayerRateChanged(this); } +void MediaPlayer::playbackStateChanged() +{ + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerPlaybackStateChanged(this); +} + } #endif diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 643f17f..bf445e3 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -70,6 +70,7 @@ struct PlatformMedia { QTMovieVisualContextType, GStreamerGWorldType, ChromiumMediaPlayerType, + QtMediaPlayerType, } type; union { @@ -78,6 +79,7 @@ struct PlatformMedia { QTMovieVisualContext* qtMovieVisualContext; GStreamerGWorld* gstreamerGWorld; MediaPlayerPrivateInterface* chromiumMediaPlayer; + MediaPlayerPrivateInterface* qtMediaPlayer; } media; }; @@ -119,6 +121,9 @@ public: // the playback rate has changed virtual void mediaPlayerRateChanged(MediaPlayer*) { } + // the play/pause status changed + virtual void mediaPlayerPlaybackStateChanged(MediaPlayer*) { } + // The MediaPlayer has found potentially problematic media content. // This is used internally to trigger swapping from a <video> // element to an <embed> in standalone documents @@ -244,6 +249,7 @@ public: void timeChanged(); void sizeChanged(); void rateChanged(); + void playbackStateChanged(); void durationChanged(); void repaint(); diff --git a/WebCore/platform/graphics/Path.cpp b/WebCore/platform/graphics/Path.cpp index 333afcb..4e2de53 100644 --- a/WebCore/platform/graphics/Path.cpp +++ b/WebCore/platform/graphics/Path.cpp @@ -39,7 +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) +#if !PLATFORM(OPENVG) && !PLATFORM(QT) static void pathLengthApplierFunction(void* info, const PathElement* element) { PathTraversalState& traversalState = *static_cast<PathTraversalState*>(info); diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index 61ea328..9896713 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -133,6 +133,11 @@ namespace WebCore { void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& endPoint); void addArcTo(const FloatPoint&, const FloatPoint&, float radius); void closeSubpath(); +#if PLATFORM(QT) + void closeCanvasSubpath(); +#else + void closeCanvasSubpath() { closeSubpath(); } +#endif void addArc(const FloatPoint&, float radius, float startAngle, float endAngle, bool anticlockwise); void addRect(const FloatRect&); diff --git a/WebCore/platform/graphics/cairo/FontCacheCairo.cpp b/WebCore/platform/graphics/cairo/FontCacheCairo.cpp index cb54549..5d3263e 100644 --- a/WebCore/platform/graphics/cairo/FontCacheCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCacheCairo.cpp @@ -23,7 +23,7 @@ #include "CString.h" #include "Font.h" -#include "GOwnPtrCairo.h" +#include "OwnPtrCairo.h" #include "SimpleFontData.h" #include <wtf/Assertions.h> @@ -115,15 +115,15 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD CString familyNameString = family.string().utf8(); const char* fcfamily = familyNameString.data(); - GOwnPtr<FcPattern> pattern(FcPatternCreate()); + OwnPtr<FcPattern> pattern(FcPatternCreate()); if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) return 0; - GOwnPtr<FcObjectSet> objectSet(FcObjectSetCreate()); + OwnPtr<FcObjectSet> objectSet(FcObjectSetCreate()); if (!FcObjectSetAdd(objectSet.get(), FC_FAMILY)) return 0; - GOwnPtr<FcFontSet> fontSet(FcFontList(0, pattern.get(), objectSet.get())); + OwnPtr<FcFontSet> fontSet(FcFontList(0, pattern.get(), objectSet.get())); if (!fontSet) return 0; diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 19cc518..283e75a 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -562,7 +562,7 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* poin cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_antialias_t savedAntialiasRule = cairo_get_antialias(cr); - cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT); + cairo_set_antialias(cr, antialiased ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); addConvexPolygonToContext(cr, numPoints, points); cairo_clip(cr); diff --git a/WebCore/platform/graphics/cairo/GOwnPtrCairo.cpp b/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp index 12df3cf..9be8670 100644 --- a/WebCore/platform/graphics/cairo/GOwnPtrCairo.cpp +++ b/WebCore/platform/graphics/cairo/OwnPtrCairo.cpp @@ -18,7 +18,7 @@ */ #include "config.h" -#include "GOwnPtrCairo.h" +#include "OwnPtrCairo.h" #if defined(USE_FREETYPE) #include <cairo-ft.h> @@ -28,19 +28,19 @@ namespace WTF { #if defined(USE_FREETYPE) -template <> void freeOwnedGPtr<FcPattern>(FcPattern* ptr) +template <> void deleteOwnedPtr<FcPattern>(FcPattern* ptr) { if (ptr) FcPatternDestroy(ptr); } -template <> void freeOwnedGPtr<FcObjectSet>(FcObjectSet* ptr) +template <> void deleteOwnedPtr<FcObjectSet>(FcObjectSet* ptr) { if (ptr) FcObjectSetDestroy(ptr); } -template <> void freeOwnedGPtr<FcFontSet>(FcFontSet* ptr) +template <> void deleteOwnedPtr<FcFontSet>(FcFontSet* ptr) { if (ptr) FcFontSetDestroy(ptr); diff --git a/WebCore/platform/graphics/cairo/GOwnPtrCairo.h b/WebCore/platform/graphics/cairo/OwnPtrCairo.h index b099707..29f4562 100644 --- a/WebCore/platform/graphics/cairo/GOwnPtrCairo.h +++ b/WebCore/platform/graphics/cairo/OwnPtrCairo.h @@ -17,10 +17,10 @@ * Boston, MA 02110-1301 USA */ -#ifndef GOwnPtrCairo_h -#define GOwnPtrCairo_h +#ifndef OwnPtrCairo_h +#define OwnPtrCairo_h -#include "GOwnPtr.h" +#include "OwnPtr.h" #if defined(USE_FREETYPE) typedef struct _FcPattern FcPattern; @@ -31,9 +31,9 @@ typedef struct _FcFontSet FcFontSet; namespace WTF { #if defined(USE_FREETYPE) -template <> void freeOwnedGPtr<FcPattern>(FcPattern*); -template <> void freeOwnedGPtr<FcObjectSet>(FcObjectSet*); -template <> void freeOwnedGPtr<FcFontSet>(FcFontSet*); +template <> void deleteOwnedPtr<FcPattern>(FcPattern*); +template <> void deleteOwnedPtr<FcObjectSet>(FcObjectSet*); +template <> void deleteOwnedPtr<FcFontSet>(FcFontSet*); #endif } // namespace WTF diff --git a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index c4008cc..fadc385 100644 --- a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -119,6 +119,7 @@ bool GraphicsContext3D::getImageData(Image* image, default: return false; } + break; case kCGImageAlphaNone: switch (componentsPerPixel) { case 1: diff --git a/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp b/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp new file mode 100644 index 0000000..9826c3e --- /dev/null +++ b/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp @@ -0,0 +1,112 @@ +/* + * 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 "Canvas2DLayerChromium.h" + +#include "DrawingBuffer.h" + +#include <GLES2/gl2.h> + +namespace WebCore { + +PassRefPtr<Canvas2DLayerChromium> Canvas2DLayerChromium::create(DrawingBuffer* drawingBuffer, GraphicsLayerChromium* owner) +{ + return adoptRef(new Canvas2DLayerChromium(drawingBuffer, owner)); +} + +Canvas2DLayerChromium::Canvas2DLayerChromium(DrawingBuffer* drawingBuffer, GraphicsLayerChromium* owner) + : CanvasLayerChromium(owner) + , m_drawingBuffer(drawingBuffer) +{ +} + +Canvas2DLayerChromium::~Canvas2DLayerChromium() +{ + if (m_textureId) + glDeleteTextures(1, &m_textureId); +} + +void Canvas2DLayerChromium::updateContents() +{ + if (!m_drawingBuffer) + return; + if (m_textureChanged) { // We have to generate a new backing texture. + if (m_textureId) + glDeleteTextures(1, &m_textureId); + glGenTextures(1, &m_textureId); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_textureId); + IntSize size = m_drawingBuffer->size(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + // Set the min-mag filters to linear and wrap modes to GL_CLAMP_TO_EDGE + // to get around NPOT texture limitations of GLES. + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + m_textureChanged = false; + // FIXME: The glFinish() here is required because we have to make sure that the texture created in this + // context (the compositor context) is actually created by the service side before the child context + // attempts to use it (in publishToPlatformLayer). glFinish() is currently the only call with strong + // enough semantics to promise this, but is actually much stronger. Ideally we'd do something like + // inserting a fence here and waiting for it before trying to publish. + glFinish(); + } + // Update the contents of the texture used by the compositor. + if (m_contentsDirty) { + m_drawingBuffer->publishToPlatformLayer(); + m_contentsDirty = false; + } +} + +void Canvas2DLayerChromium::setTextureChanged() +{ + m_textureChanged = true; +} + +unsigned Canvas2DLayerChromium::textureId() const +{ + return m_textureId; +} + +void Canvas2DLayerChromium::setDrawingBuffer(DrawingBuffer* drawingBuffer) +{ + if (drawingBuffer != m_drawingBuffer) { + m_drawingBuffer = drawingBuffer; + m_textureChanged = true; + } +} + +} +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h b/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h new file mode 100644 index 0000000..0031229 --- /dev/null +++ b/WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h @@ -0,0 +1,65 @@ +/* + * 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 Canvas2DLayerChromium_h +#define Canvas2DLayerChromium_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "CanvasLayerChromium.h" + +namespace WebCore { + +class DrawingBuffer; + +// A layer containing an accelerated 2d canvas +class Canvas2DLayerChromium : public CanvasLayerChromium { +public: + static PassRefPtr<Canvas2DLayerChromium> create(DrawingBuffer*, GraphicsLayerChromium* owner); + virtual ~Canvas2DLayerChromium(); + virtual bool drawsContent() { return true; } + virtual void updateContents(); + + void setTextureChanged(); + unsigned textureId() const; + void setDrawingBuffer(DrawingBuffer*); + +private: + explicit Canvas2DLayerChromium(DrawingBuffer*, GraphicsLayerChromium* owner); + DrawingBuffer* m_drawingBuffer; + + static unsigned m_shaderProgramId; +}; + +} +#endif // USE(ACCELERATED_COMPOSITING) + +#endif diff --git a/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp b/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp index bbf091c..56a7262 100644 --- a/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp @@ -34,12 +34,14 @@ #include "CanvasLayerChromium.h" -#include "GraphicsContext3D.h" #include "LayerRendererChromium.h" + #include <GLES2/gl2.h> namespace WebCore { +unsigned CanvasLayerChromium::m_shaderProgramId = 0; + CanvasLayerChromium::SharedValues::SharedValues() : m_canvasShaderProgram(0) , m_shaderSamplerLocation(-1) @@ -93,49 +95,15 @@ CanvasLayerChromium::SharedValues::~SharedValues() GLC(glDeleteProgram(m_canvasShaderProgram)); } -PassRefPtr<CanvasLayerChromium> CanvasLayerChromium::create(GraphicsLayerChromium* owner) -{ - return adoptRef(new CanvasLayerChromium(owner)); -} - CanvasLayerChromium::CanvasLayerChromium(GraphicsLayerChromium* owner) : LayerChromium(owner) - , m_context(0) + , m_textureChanged(true) , m_textureId(0) - , m_textureChanged(false) -{ -} - -void CanvasLayerChromium::updateContents() { - ASSERT(m_context); - if (m_textureChanged) { - glBindTexture(GL_TEXTURE_2D, m_textureId); - // Set the min-mag filters to linear and wrap modes to GL_CLAMP_TO_EDGE - // to get around NPOT texture limitations of GLES. - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - m_textureChanged = false; - } - // Update the contents of the texture used by the compositor. - if (m_contentsDirty) { - if (m_prepareTextureCallback) - m_prepareTextureCallback->willPrepareTexture(); - m_context->prepareTexture(); - m_contentsDirty = false; - } } -void CanvasLayerChromium::setContext(const GraphicsContext3D* context) +CanvasLayerChromium::~CanvasLayerChromium() { - m_context = const_cast<GraphicsContext3D*>(context); - - unsigned int textureId = m_context->platformTexture(); - if (textureId != m_textureId) - m_textureChanged = true; - m_textureId = textureId; } void CanvasLayerChromium::draw() @@ -150,6 +118,7 @@ void CanvasLayerChromium::draw() drawTexturedQuad(layerRenderer()->projectionMatrix(), drawTransform(), bounds().width(), bounds().height(), drawOpacity(), sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); + } } diff --git a/WebCore/platform/graphics/chromium/CanvasLayerChromium.h b/WebCore/platform/graphics/chromium/CanvasLayerChromium.h index 053efff..d591c73 100644 --- a/WebCore/platform/graphics/chromium/CanvasLayerChromium.h +++ b/WebCore/platform/graphics/chromium/CanvasLayerChromium.h @@ -38,17 +38,12 @@ namespace WebCore { -class GraphicsContext3D; - -// A Layer containing a WebGL or accelerated 2d canvas +// Base class for WebGL and accelerated 2d canvases. class CanvasLayerChromium : public LayerChromium { public: - static PassRefPtr<CanvasLayerChromium> create(GraphicsLayerChromium* owner = 0); - virtual bool drawsContent() { return m_context; } - virtual void updateContents(); - virtual void draw(); + virtual ~CanvasLayerChromium(); - void setContext(const GraphicsContext3D* context); + virtual void draw(); class SharedValues { public: @@ -69,21 +64,16 @@ public: bool m_initialized; }; - class PrepareTextureCallback : public Noncopyable { - public: - virtual void willPrepareTexture() = 0; - }; - void setPrepareTextureCallback(PassOwnPtr<PrepareTextureCallback> callback) { m_prepareTextureCallback = callback; } - -private: +protected: explicit CanvasLayerChromium(GraphicsLayerChromium* owner); - GraphicsContext3D* m_context; - unsigned m_textureId; bool m_textureChanged; - OwnPtr<PrepareTextureCallback> m_prepareTextureCallback; + unsigned m_textureId; + +private: + static unsigned m_shaderProgramId; }; } #endif // USE(ACCELERATED_COMPOSITING) -#endif +#endif // CanvasLayerChromium_h diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index 974933d..48119bb 100644 --- a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -42,6 +42,8 @@ #include "PlatformContextSkia.h" #include "skia/ext/platform_canvas.h" #elif PLATFORM(CG) +#include "LocalCurrentGraphicsContext.h" + #include <CoreGraphics/CGBitmapContext.h> #endif @@ -152,12 +154,6 @@ void ContentLayerChromium::updateContents() IntSize requiredTextureSize; IntSize bitmapSize; -#if PLATFORM(SKIA) - const SkBitmap* skiaBitmap = 0; - OwnPtr<skia::PlatformCanvas> canvas; - OwnPtr<PlatformContextSkia> skiaContext; - OwnPtr<GraphicsContext> graphicsContext; - requiredTextureSize = m_bounds; IntRect boundsRect(IntPoint(0, 0), m_bounds); @@ -171,17 +167,18 @@ void ContentLayerChromium::updateContents() dirtyRect.intersect(boundsRect); } +#if PLATFORM(SKIA) + const SkBitmap* skiaBitmap = 0; + OwnPtr<skia::PlatformCanvas> canvas; + OwnPtr<PlatformContextSkia> skiaContext; + OwnPtr<GraphicsContext> graphicsContext; + canvas.set(new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), false)); skiaContext.set(new PlatformContextSkia(canvas.get())); -#if OS(WINDOWS) - // 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. + // This is needed to get text to show up correctly. // FIXME: Does this take us down a very slow text rendering path? - // FIXME: why is this is a windows-only call ? skiaContext->setDrawingToImageBuffer(true); -#endif graphicsContext.set(new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(skiaContext.get()))); @@ -201,19 +198,6 @@ void ContentLayerChromium::updateContents() bitmapSize = IntSize(skiaBitmap->width(), skiaBitmap->height()); } #elif PLATFORM(CG) - requiredTextureSize = m_bounds; - IntRect boundsRect(IntPoint(0, 0), m_bounds); - - // If the texture needs to be reallocated then we must redraw the entire - // contents of the layer. - if (requiredTextureSize != m_allocatedTextureSize) - dirtyRect = boundsRect; - else { - // Clip the dirtyRect to the size of the layer to avoid drawing outside - // the bounds of the backing texture. - dirtyRect.intersect(boundsRect); - } - Vector<uint8_t> tempVector; int rowBytes = 4 * dirtyRect.width(); tempVector.resize(rowBytes * dirtyRect.height()); @@ -225,6 +209,7 @@ void ContentLayerChromium::updateContents() kCGImageAlphaPremultipliedLast)); GraphicsContext graphicsContext(contextCG.get()); + LocalCurrentGraphicsContext scopedNSGraphicsContext(&graphicsContext); // Translate the graphics contxt into the coordinate system of the dirty rect. graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y()); diff --git a/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp new file mode 100644 index 0000000..64981ee --- /dev/null +++ b/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp @@ -0,0 +1,142 @@ +/* + * 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" + +#include "DrawingBuffer.h" + +#include "GraphicsContext3D.h" +#include "SharedGraphicsContext3D.h" + +#if USE(ACCELERATED_COMPOSITING) +#include "Canvas2DLayerChromium.h" +#endif + +#include <GLES2/gl2.h> +#ifndef GL_GLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES 1 +#endif +#include <GLES2/gl2ext.h> + +namespace WebCore { + +struct DrawingBufferInternal { + unsigned offscreenColorTexture; +#if USE(ACCELERATED_COMPOSITING) + RefPtr<Canvas2DLayerChromium> platformLayer; +#endif +}; + +static unsigned generateColorTexture(SharedGraphicsContext3D* context, const IntSize& size) +{ + unsigned offscreenColorTexture = context->createTexture(); + if (!offscreenColorTexture) + return 0; + + context->bindTexture(GraphicsContext3D::TEXTURE_2D, offscreenColorTexture); + context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST); + context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST); + context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); + context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); + context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0); + context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, offscreenColorTexture, 0); + + return offscreenColorTexture; +} + + +DrawingBuffer::DrawingBuffer(SharedGraphicsContext3D* context, const IntSize& size, unsigned framebuffer) + : m_context(context) + , m_size(size) + , m_framebuffer(framebuffer) + , m_internal(new DrawingBufferInternal) +{ + context->bindFramebuffer(framebuffer); + m_internal->offscreenColorTexture = generateColorTexture(context, size); +} + +DrawingBuffer::~DrawingBuffer() +{ +#if USE(ACCELERATED_COMPOSITING) + if (m_internal->platformLayer) + m_internal->platformLayer->setDrawingBuffer(0); +#endif + m_context->bindFramebuffer(m_framebuffer); + m_context->deleteTexture(m_internal->offscreenColorTexture); + m_context->deleteFramebuffer(m_framebuffer); +} + +#if USE(ACCELERATED_COMPOSITING) +void DrawingBuffer::publishToPlatformLayer() +{ + if (m_callback) + m_callback->willPublish(); + unsigned parentTexture = m_internal->platformLayer->textureId(); + // FIXME: We do the copy in the canvas' (child) context so that it executes in the correct order relative to + // other commands in the child context. This ensures that the parent texture always contains a complete + // frame and not some intermediate result. However, there is no synchronization to ensure that this copy + // happens before the compositor draws. This means we might draw stale frames sometimes. Ideally this + // would insert a fence into the child command stream that the compositor could wait for. + m_context->makeContextCurrent(); + glCopyTextureToParentTexture(m_internal->offscreenColorTexture, parentTexture); + glFlush(); +} +#endif + +void DrawingBuffer::reset(const IntSize& newSize) +{ + if (m_size == newSize) + return; + m_size = newSize; + + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_internal->offscreenColorTexture); + m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_size.width(), m_size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0); + +#if USE(ACCELERATED_COMPOSITING) + if (m_internal->platformLayer) + m_internal->platformLayer->setTextureChanged(); +#endif +} + +#if USE(ACCELERATED_COMPOSITING) +PlatformLayer* DrawingBuffer::platformLayer() +{ + if (!m_internal->platformLayer) + m_internal->platformLayer = Canvas2DLayerChromium::create(this, 0); + return m_internal->platformLayer.get(); +} +#endif + +unsigned DrawingBuffer::getRenderingResultsAsTexture() +{ + return m_internal->offscreenColorTexture; +} + +} diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 78b7517..8a77501 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -372,6 +372,8 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, int numGlyphs, const FloatPoint& point) const { + graphicsContext->platformContext()->prepareForSoftwareDraw(); + SkColor color = graphicsContext->platformContext()->effectiveFillColor(); unsigned char alpha = SkColorGetA(color); // Skip 100% transparent text; no need to draw anything. diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index ec79b82..696cd9c 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -65,13 +65,13 @@ static bool isCanvasMultiLayered(SkCanvas* canvas) return !layerIterator.done(); } -static void adjustTextRenderMode(SkPaint* paint, bool isCanvasMultiLayered) +static void adjustTextRenderMode(SkPaint* paint, PlatformContextSkia* skiaContext) { // Our layers only have a single alpha channel. This means that subpixel // rendered text cannot be compositied correctly when the layer is // collapsed. Therefore, subpixel text is disabled when we are drawing - // onto a layer. - if (isCanvasMultiLayered) + // onto a layer or when the compositor is being used. + if (isCanvasMultiLayered(skiaContext->canvas()) || skiaContext->isDrawingToImageBuffer()) paint->setLCDRenderText(false); } @@ -100,16 +100,17 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, y += SkFloatToScalar(adv[i].height()); } + gc->platformContext()->prepareForSoftwareDraw(); + SkCanvas* canvas = gc->platformContext()->canvas(); int textMode = gc->platformContext()->getTextDrawingMode(); - bool haveMultipleLayers = isCanvasMultiLayered(canvas); // We draw text up to two times (once for fill, once for stroke). if (textMode & cTextFill) { SkPaint paint; gc->platformContext()->setupPaintForFilling(&paint); font->platformData().setupPaint(&paint); - adjustTextRenderMode(&paint, haveMultipleLayers); + adjustTextRenderMode(&paint, gc->platformContext()); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->fillColor().rgb()); canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); @@ -122,7 +123,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, SkPaint paint; gc->platformContext()->setupPaintForStroking(&paint, 0, 0); font->platformData().setupPaint(&paint); - adjustTextRenderMode(&paint, haveMultipleLayers); + adjustTextRenderMode(&paint, gc->platformContext()); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->strokeColor().rgb()); @@ -499,7 +500,11 @@ private: // We overflowed our arrays. Resize and retry. // HB_ShapeItem fills in m_item.num_glyphs with the needed size. deleteGlyphArrays(); - createGlyphArrays(m_item.num_glyphs); + // The |+ 1| here is a workaround for a bug in Harfbuzz: the Khmer + // shaper (at least) can fail because of insufficient glyph buffers + // and request 0 additional glyphs: throwing us into an infinite + // loop. + createGlyphArrays(m_item.num_glyphs + 1); } } @@ -522,8 +527,11 @@ private: m_xPositions[i] = m_offsetX + position + offsetX; double advance = truncateFixedPointToInteger(m_item.advances[i]); - unsigned glyphIndex = m_item.item.pos + logClustersIndex; - if (isWordBreak(glyphIndex, isRTL)) { + // The first half of the conjuction works around the case where + // output glyphs aren't associated with any codepoints by the + // clusters log. + if (logClustersIndex < m_item.item.length + && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) { advance += m_wordSpacingAdjustment; if (m_padding > 0) { @@ -547,7 +555,7 @@ private: while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i) logClustersIndex--; } else { - while (logClustersIndex < m_item.num_glyphs && logClusters()[logClustersIndex] == i) + while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i) logClustersIndex++; } @@ -637,7 +645,6 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, } TextRunWalker walker(run, point.x(), this); - bool haveMultipleLayers = isCanvasMultiLayered(canvas); walker.setWordSpacingAdjustment(wordSpacing()); walker.setLetterSpacingAdjustment(letterSpacing()); walker.setPadding(run.padding()); @@ -645,13 +652,13 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run, while (walker.nextScriptRun()) { if (fill) { walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint); - adjustTextRenderMode(&fillPaint, haveMultipleLayers); + adjustTextRenderMode(&fillPaint, gc->platformContext()); canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), fillPaint); } if (stroke) { walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint); - adjustTextRenderMode(&strokePaint, haveMultipleLayers); + adjustTextRenderMode(&strokePaint, gc->platformContext()); canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), strokePaint); } } diff --git a/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/WebCore/platform/graphics/chromium/GLES2Canvas.cpp index 82d4c0b..46aecf4 100644 --- a/WebCore/platform/graphics/chromium/GLES2Canvas.cpp +++ b/WebCore/platform/graphics/chromium/GLES2Canvas.cpp @@ -32,10 +32,12 @@ #include "GLES2Canvas.h" +#include "DrawingBuffer.h" #include "FloatRect.h" #include "GraphicsContext3D.h" #include "IntRect.h" #include "PlatformString.h" +#include "SharedGraphicsContext3D.h" #include "SolidFillShader.h" #include "TexShader.h" #include "Texture.h" @@ -61,37 +63,35 @@ struct GLES2Canvas::State { AffineTransform m_ctm; }; -GLES2Canvas::GLES2Canvas(GraphicsContext3D* context, const IntSize& size) - : m_context(context) +GLES2Canvas::GLES2Canvas(SharedGraphicsContext3D* context, DrawingBuffer* drawingBuffer, const IntSize& size) + : m_size(size) + , m_context(context) + , m_drawingBuffer(drawingBuffer) , m_state(0) - , m_quadVertices(0) - , m_solidFillShader(SolidFillShader::create(context)) - , m_texShader(TexShader::create(context)) { m_flipMatrix.translate(-1.0f, 1.0f); m_flipMatrix.scale(2.0f / size.width(), -2.0f / size.height()); - m_context->reshape(size.width(), size.height()); - m_context->viewport(0, 0, size.width(), size.height()); - m_stateStack.append(State()); m_state = &m_stateStack.last(); - - // Force the source over composite mode to be applied. - m_lastCompositeOp = CompositeClear; - applyCompositeOperator(CompositeSourceOver); } GLES2Canvas::~GLES2Canvas() { - m_context->deleteBuffer(m_quadVertices); +} + +void GLES2Canvas::bindFramebuffer() +{ + m_drawingBuffer->bind(); } void GLES2Canvas::clearRect(const FloatRect& rect) { + bindFramebuffer(); if (m_state->m_ctm.isIdentity()) { - m_context->scissor(rect.x(), rect.y(), rect.width(), rect.height()); + m_context->scissor(rect); m_context->enable(GraphicsContext3D::SCISSOR_TEST); + m_context->clearColor(Color(RGBA32(0))); m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT); m_context->disable(GraphicsContext3D::SCISSOR_TEST); } else { @@ -104,16 +104,17 @@ void GLES2Canvas::clearRect(const FloatRect& rect) void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { - applyCompositeOperator(m_state->m_compositeOp); - - m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, getQuadVertices()); + m_context->applyCompositeOperator(m_state->m_compositeOp); + m_context->useQuadVertices(); AffineTransform matrix(m_flipMatrix); matrix.multLeft(m_state->m_ctm); matrix.translate(rect.x(), rect.y()); matrix.scale(rect.width(), rect.height()); - m_solidFillShader->use(matrix, color); + m_context->useFillSolidProgram(matrix, color); + + bindFramebuffer(); m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4); } @@ -165,21 +166,33 @@ void GLES2Canvas::restore() m_state = &m_stateStack.last(); } +void GLES2Canvas::drawTexturedRect(unsigned texture, const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace colorSpace, CompositeOperator compositeOp) +{ + m_context->applyCompositeOperator(compositeOp); + + m_context->useQuadVertices(); + m_context->setActiveTexture(GraphicsContext3D::TEXTURE0); + + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, texture); + + drawQuad(textureSize, srcRect, dstRect, m_state->m_ctm, m_state->m_alpha); +} + void GLES2Canvas::drawTexturedRect(Texture* texture, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace colorSpace, CompositeOperator compositeOp) { drawTexturedRect(texture, srcRect, dstRect, m_state->m_ctm, m_state->m_alpha, colorSpace, compositeOp); } + void GLES2Canvas::drawTexturedRect(Texture* texture, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha, ColorSpace colorSpace, CompositeOperator compositeOp) { - applyCompositeOperator(compositeOp); - - m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, getQuadVertices()); - checkGLError("glBindBuffer"); - + m_context->applyCompositeOperator(compositeOp); const TilingData& tiles = texture->tiles(); IntRect tileIdxRect = tiles.overlappedTileIndices(srcRect); + m_context->useQuadVertices(); + m_context->setActiveTexture(GraphicsContext3D::TEXTURE0); + for (int y = tileIdxRect.y(); y <= tileIdxRect.bottom(); y++) { for (int x = tileIdxRect.x(); x <= tileIdxRect.right(); x++) drawTexturedRectTile(texture, tiles.tileIndex(x, y), srcRect, dstRect, transform, alpha); @@ -193,7 +206,6 @@ void GLES2Canvas::drawTexturedRectTile(Texture* texture, int tile, const FloatRe const TilingData& tiles = texture->tiles(); - m_context->activeTexture(GraphicsContext3D::TEXTURE0); texture->bindTile(tile); FloatRect srcRectClippedInTileSpace; @@ -202,18 +214,24 @@ void GLES2Canvas::drawTexturedRectTile(Texture* texture, int tile, const FloatRe IntRect tileBoundsWithBorder = tiles.tileBoundsWithBorder(tile); + drawQuad(tileBoundsWithBorder.size(), srcRectClippedInTileSpace, dstRectIntersected, transform, alpha); +} + +void GLES2Canvas::drawQuad(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform& transform, float alpha) +{ AffineTransform matrix(m_flipMatrix); matrix.multLeft(transform); - matrix.translate(dstRectIntersected.x(), dstRectIntersected.y()); - matrix.scale(dstRectIntersected.width(), dstRectIntersected.height()); + matrix.translate(dstRect.x(), dstRect.y()); + matrix.scale(dstRect.width(), dstRect.height()); AffineTransform texMatrix; - texMatrix.scale(1.0f / tileBoundsWithBorder.width(), 1.0f / tileBoundsWithBorder.height()); - texMatrix.translate(srcRectClippedInTileSpace.x(), srcRectClippedInTileSpace.y()); - texMatrix.scale(srcRectClippedInTileSpace.width(), srcRectClippedInTileSpace.height()); + texMatrix.scale(1.0f / textureSize.width(), 1.0f / textureSize.height()); + texMatrix.translate(srcRect.x(), srcRect.y()); + texMatrix.scale(srcRect.width(), srcRect.height()); - m_texShader->use(matrix, texMatrix, 0, alpha); + bindFramebuffer(); + m_context->useTextureProgram(matrix, texMatrix, alpha); m_context->drawArrays(GraphicsContext3D::TRIANGLE_STRIP, 0, 4); checkGLError("glDrawArrays"); } @@ -223,98 +241,14 @@ void GLES2Canvas::setCompositeOperation(CompositeOperator op) m_state->m_compositeOp = op; } -void GLES2Canvas::applyCompositeOperator(CompositeOperator op) -{ - if (op == m_lastCompositeOp) - return; - - switch (op) { - case CompositeClear: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::ZERO); - break; - case CompositeCopy: - m_context->disable(GraphicsContext3D::BLEND); - break; - case CompositeSourceOver: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); - break; - case CompositeSourceIn: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::DST_ALPHA, GraphicsContext3D::ZERO); - break; - case CompositeSourceOut: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ZERO); - break; - case CompositeSourceAtop: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::DST_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); - break; - case CompositeDestinationOver: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ONE); - break; - case CompositeDestinationIn: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::SRC_ALPHA); - break; - case CompositeDestinationOut: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); - break; - case CompositeDestinationAtop: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::SRC_ALPHA); - break; - case CompositeXOR: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); - break; - case CompositePlusDarker: - case CompositeHighlight: - // unsupported - m_context->disable(GraphicsContext3D::BLEND); - break; - case CompositePlusLighter: - m_context->enable(GraphicsContext3D::BLEND); - m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE); - break; - } - m_lastCompositeOp = op; -} - -unsigned GLES2Canvas::getQuadVertices() -{ - if (!m_quadVertices) { - float vertices[] = { 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 1.0f, - 0.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f }; - m_quadVertices = m_context->createBuffer(); - m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices); - m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(vertices), vertices, GraphicsContext3D::STATIC_DRAW); - } - return m_quadVertices; -} - Texture* GLES2Canvas::createTexture(NativeImagePtr ptr, Texture::Format format, int width, int height) { - PassRefPtr<Texture> texture = m_textures.get(ptr); - if (texture) - return texture.get(); - - texture = Texture::create(m_context, format, width, height); - Texture* t = texture.get(); - m_textures.set(ptr, texture); - return t; + return m_context->createTexture(ptr, format, width, height); } Texture* GLES2Canvas::getTexture(NativeImagePtr ptr) { - PassRefPtr<Texture> texture = m_textures.get(ptr); - return texture ? texture.get() : 0; + return m_context->getTexture(ptr); } void GLES2Canvas::checkGLError(const char* header) diff --git a/WebCore/platform/graphics/chromium/GLES2Canvas.h b/WebCore/platform/graphics/chromium/GLES2Canvas.h index f49ac8b..6fc1a0e 100644 --- a/WebCore/platform/graphics/chromium/GLES2Canvas.h +++ b/WebCore/platform/graphics/chromium/GLES2Canvas.h @@ -45,16 +45,14 @@ namespace WebCore { class Color; +class DrawingBuffer; class FloatRect; class GraphicsContext3D; -class SolidFillShader; -class TexShader; - -typedef HashMap<NativeImagePtr, RefPtr<Texture> > TextureHashMap; +class SharedGraphicsContext3D; class GLES2Canvas : public Noncopyable { public: - GLES2Canvas(GraphicsContext3D*, const IntSize&); + GLES2Canvas(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&); ~GLES2Canvas(); void fillRect(const FloatRect&, const Color&, ColorSpace); @@ -74,28 +72,33 @@ public: // non-standard functions // These are not standard GraphicsContext functions, and should be pushed // down into a PlatformContextGLES2 at some point. + void drawTexturedRect(unsigned texture, const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace, CompositeOperator); void drawTexturedRect(Texture*, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha, ColorSpace, CompositeOperator); void drawTexturedRect(Texture*, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace, CompositeOperator); - GraphicsContext3D* context() { return m_context; } Texture* createTexture(NativeImagePtr, Texture::Format, int width, int height); Texture* getTexture(NativeImagePtr); + SharedGraphicsContext3D* context() const { return m_context; } + + void bindFramebuffer(); + + DrawingBuffer* drawingBuffer() const { return m_drawingBuffer; } + private: void drawTexturedRectTile(Texture* texture, int tile, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha); + void drawQuad(const IntSize& textureSize, const FloatRect& srcRect, const FloatRect& dstRect, const AffineTransform&, float alpha); void applyCompositeOperator(CompositeOperator); void checkGLError(const char* header); - unsigned getQuadVertices(); - GraphicsContext3D* m_context; + IntSize m_size; + + SharedGraphicsContext3D* m_context; + DrawingBuffer* m_drawingBuffer; + struct State; WTF::Vector<State> m_stateStack; State* m_state; - unsigned m_quadVertices; - OwnPtr<SolidFillShader> m_solidFillShader; - OwnPtr<TexShader> m_texShader; AffineTransform m_flipMatrix; - TextureHashMap m_textures; - CompositeOperator m_lastCompositeOp; // This is the one last set, not necessarily the one in the state stack. }; } diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp index 648e35f..bbae72a 100644 --- a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp @@ -45,7 +45,9 @@ #include "GraphicsLayerChromium.h" +#include "Canvas2DLayerChromium.h" #include "ContentLayerChromium.h" +#include "DrawingBuffer.h" #include "FloatConversion.h" #include "FloatRect.h" #include "Image.h" @@ -104,6 +106,12 @@ GraphicsLayerChromium::GraphicsLayerChromium(GraphicsLayerClient* client) GraphicsLayerChromium::~GraphicsLayerChromium() { + if (m_layer) + m_layer->setOwner(0); + if (m_contentsLayer) + m_contentsLayer->setOwner(0); + if (m_transformLayer) + m_transformLayer->setOwner(0); } void GraphicsLayerChromium::setName(const String& inName) @@ -290,6 +298,7 @@ void GraphicsLayerChromium::setContentsNeedsDisplay() if (m_contentsLayer) m_contentsLayer->setNeedsDisplay(); } + void GraphicsLayerChromium::setNeedsDisplay() { if (drawsContent()) @@ -344,13 +353,13 @@ void GraphicsLayerChromium::setContentsToCanvas(PlatformLayer* platformLayer) bool childrenChanged = false; if (platformLayer) { platformLayer->setOwner(this); - if (!m_contentsLayer.get() || m_contentsLayerPurpose != ContentsLayerForCanvas) { + if (m_contentsLayer.get() != platformLayer) { setupContentsLayer(platformLayer); m_contentsLayer = platformLayer; m_contentsLayerPurpose = ContentsLayerForCanvas; childrenChanged = true; } - platformLayer->setNeedsDisplay(); + m_contentsLayer->setNeedsDisplay(); updateContentsRect(); } else { if (m_contentsLayer) { diff --git a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h index 9dff66a..dde443d 100644 --- a/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h +++ b/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h @@ -138,7 +138,7 @@ private: NoContentsLayer = 0, ContentsLayerForImage, ContentsLayerForVideo, - ContentsLayerForCanvas + ContentsLayerForCanvas, }; ContentsLayerPurpose m_contentsLayerPurpose; diff --git a/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp index 4fd3ba0..59e8122 100644 --- a/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp +++ b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp @@ -38,6 +38,7 @@ #include "SkPath.h" #include "SkPoint.h" #include "SkRect.h" +#include "SkUtils.h" extern "C" { #include "harfbuzz-shaper.h" @@ -61,6 +62,15 @@ static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_u font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + + unsigned codepoints = 0; + for (hb_uint32 i = 0; i < length; i++) { + if (!SkUTF16_IsHighSurrogate(characters[i])) + codepoints++; + if (codepoints > *glyphsSize) + return 0; + } + int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs)); // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our diff --git a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp index 09b388d..060bb46 100644 --- a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp @@ -108,8 +108,9 @@ void ImageLayerChromium::updateContents() // completely overwrite its contents with the image below. // Try to reuse the color space from the image to preserve its colors. // Some images use a color space (such as indexed) unsupported by the bitmap context. - RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGImageGetColorSpace(cgImage)); - CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace.get()); + RetainPtr<CGColorSpaceRef> colorSpaceReleaser; + CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage); + CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace); switch (colorSpaceModel) { case kCGColorSpaceModelMonochrome: case kCGColorSpaceModelRGB: @@ -118,12 +119,13 @@ void ImageLayerChromium::updateContents() case kCGColorSpaceModelDeviceN: break; default: - colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); + colorSpaceReleaser.adoptCF(CGColorSpaceCreateDeviceRGB()); + colorSpace = colorSpaceReleaser.get(); break; } RetainPtr<CGContextRef> tempContext(AdoptCF, CGBitmapContextCreate(tempVector.data(), width, height, 8, tempRowBytes, - colorSpace.get(), + colorSpace, kCGImageAlphaPremultipliedLast)); CGContextSetBlendMode(tempContext.get(), kCGBlendModeCopy); CGContextDrawImage(tempContext.get(), diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index 50338d2..4708310 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -34,11 +34,11 @@ #if USE(ACCELERATED_COMPOSITING) #include "LayerRendererChromium.h" -#include "CanvasLayerChromium.h" -#include "ContentLayerChromium.h" +#include "Canvas2DLayerChromium.h" #include "GLES2Context.h" #include "LayerChromium.h" #include "NotImplemented.h" +#include "WebGLLayerChromium.h" #if PLATFORM(SKIA) #include "NativeImageSkia.h" #include "PlatformContextSkia.h" @@ -77,7 +77,14 @@ static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b) PassOwnPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<GLES2Context> gles2Context) { - return new LayerRendererChromium(gles2Context); + if (!gles2Context) + return 0; + + OwnPtr<LayerRendererChromium> layerRenderer(new LayerRendererChromium(gles2Context)); + if (!layerRenderer->hardwareCompositing()) + return 0; + + return layerRenderer.release(); } LayerRendererChromium::LayerRendererChromium(PassOwnPtr<GLES2Context> gles2Context) @@ -91,7 +98,7 @@ LayerRendererChromium::LayerRendererChromium(PassOwnPtr<GLES2Context> gles2Conte , m_currentShader(0) , m_gles2Context(gles2Context) { - m_hardwareCompositing = (m_gles2Context && initializeSharedObjects()); + m_hardwareCompositing = initializeSharedObjects(); } LayerRendererChromium::~LayerRendererChromium() @@ -118,10 +125,7 @@ void LayerRendererChromium::setRootLayerCanvasSize(const IntSize& size) // the old ones. m_rootLayerCanvas = new skia::PlatformCanvas(size.width(), size.height(), false); m_rootLayerSkiaContext = new PlatformContextSkia(m_rootLayerCanvas.get()); -#if OS(WINDOWS) - // FIXME: why is this is a windows-only call ? m_rootLayerSkiaContext->setDrawingToImageBuffer(true); -#endif m_rootLayerGraphicsContext = new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(m_rootLayerSkiaContext.get())); #elif PLATFORM(CG) // Release the previous CGBitmapContext before reallocating the backing store as a precaution. diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 7ff98b9..c0da285 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -96,14 +96,9 @@ void VideoLayerChromium::updateContents() m_canvas = new skia::PlatformCanvas(dirtyRect.width(), dirtyRect.height(), true); m_skiaContext = new PlatformContextSkia(m_canvas.get()); -#if OS(WINDOWS) - // 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. + // This is needed to get text to show up correctly. // FIXME: Does this take us down a very slow text rendering path? - // FIXME: Why is this is a windows-only call? m_skiaContext->setDrawingToImageBuffer(true); -#endif m_graphicsContext = new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(m_skiaContext.get())); } diff --git a/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp b/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp new file mode 100644 index 0000000..411f416 --- /dev/null +++ b/WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp @@ -0,0 +1,85 @@ +/* + * 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 "WebGLLayerChromium.h" + +#include "GraphicsContext3D.h" +#include "LayerRendererChromium.h" +#include <GLES2/gl2.h> + +namespace WebCore { + +PassRefPtr<WebGLLayerChromium> WebGLLayerChromium::create(GraphicsLayerChromium* owner) +{ + return adoptRef(new WebGLLayerChromium(owner)); +} + +WebGLLayerChromium::WebGLLayerChromium(GraphicsLayerChromium* owner) + : CanvasLayerChromium(owner) + , m_context(0) +{ +} + +void WebGLLayerChromium::updateContents() +{ + ASSERT(m_context); + if (m_textureChanged) { + glBindTexture(GL_TEXTURE_2D, m_textureId); + // Set the min-mag filters to linear and wrap modes to GL_CLAMP_TO_EDGE + // to get around NPOT texture limitations of GLES. + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + m_textureChanged = false; + } + // Update the contents of the texture used by the compositor. + if (m_contentsDirty) { + m_context->prepareTexture(); + m_contentsDirty = false; + } +} + +void WebGLLayerChromium::setContext(const GraphicsContext3D* context) +{ + m_context = const_cast<GraphicsContext3D*>(context); + + unsigned int textureId = m_context->platformTexture(); + if (textureId != m_textureId) + m_textureChanged = true; + m_textureId = textureId; +} + +} +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/WebGLLayerChromium.h b/WebCore/platform/graphics/chromium/WebGLLayerChromium.h new file mode 100644 index 0000000..11b8db7 --- /dev/null +++ b/WebCore/platform/graphics/chromium/WebGLLayerChromium.h @@ -0,0 +1,60 @@ +/* + * 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 WebGLLayerChromium_h +#define WebGLLayerChromium_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "CanvasLayerChromium.h" + +namespace WebCore { + +class GraphicsContext3D; + +// A Layer containing a WebGL canvas +class WebGLLayerChromium : public CanvasLayerChromium { +public: + static PassRefPtr<WebGLLayerChromium> create(GraphicsLayerChromium* owner = 0); + virtual bool drawsContent() { return m_context; } + virtual void updateContents(); + + void setContext(const GraphicsContext3D* context); + +private: + explicit WebGLLayerChromium(GraphicsLayerChromium* owner); + GraphicsContext3D* m_context; +}; + +} +#endif // USE(ACCELERATED_COMPOSITING) + +#endif diff --git a/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/WebCore/platform/graphics/gpu/DrawingBuffer.cpp new file mode 100644 index 0000000..dc80954 --- /dev/null +++ b/WebCore/platform/graphics/gpu/DrawingBuffer.cpp @@ -0,0 +1,60 @@ +/* + * 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" + +#include "DrawingBuffer.h" + +#include "GraphicsContext3D.h" +#include "SharedGraphicsContext3D.h" + +namespace WebCore { + +PassOwnPtr<DrawingBuffer> DrawingBuffer::create(SharedGraphicsContext3D* context, const IntSize& size) +{ + unsigned framebuffer = context->createFramebuffer(); + ASSERT(framebuffer); + if (!framebuffer) + return 0; + return adoptPtr(new DrawingBuffer(context, size, framebuffer)); +} + +void DrawingBuffer::bind() +{ + m_context->bindFramebuffer(m_framebuffer); + m_context->setViewport(m_size); +} + +void DrawingBuffer::setWillPublishCallback(PassOwnPtr<WillPublishCallback> callback) +{ + m_callback = callback; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/gpu/DrawingBuffer.h b/WebCore/platform/graphics/gpu/DrawingBuffer.h new file mode 100644 index 0000000..23e6f4a --- /dev/null +++ b/WebCore/platform/graphics/gpu/DrawingBuffer.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 DrawingBuffer_h +#define DrawingBuffer_h + +#include "GraphicsLayer.h" +#include "IntSize.h" + +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +class SharedGraphicsContext3D; + +struct DrawingBufferInternal; + +// Manages a rendering target (framebuffer + attachment) for a canvas. Can publish its rendering +// results to a PlatformLayer for compositing. +class DrawingBuffer : public Noncopyable { +public: + static PassOwnPtr<DrawingBuffer> create(SharedGraphicsContext3D*, const IntSize&); + ~DrawingBuffer(); + + void reset(const IntSize&); + void bind(); + IntSize size() const { return m_size; } + +#if USE(ACCELERATED_COMPOSITING) + PlatformLayer* platformLayer(); + void publishToPlatformLayer(); +#endif + + unsigned getRenderingResultsAsTexture(); + + class WillPublishCallback : public Noncopyable { + public: + virtual void willPublish() = 0; + }; + + void setWillPublishCallback(PassOwnPtr<WillPublishCallback>); +private: + DrawingBuffer(SharedGraphicsContext3D*, const IntSize&, unsigned framebuffer); + + SharedGraphicsContext3D* m_context; + IntSize m_size; + unsigned m_framebuffer; + + OwnPtr<WillPublishCallback> m_callback; + OwnPtr<DrawingBufferInternal> m_internal; +}; + +} // namespace WebCore + +#endif // DrawingBuffer_h diff --git a/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp b/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp new file mode 100644 index 0000000..e43dc37 --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp @@ -0,0 +1,122 @@ +/* + * 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: + * + * 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 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 "LoopBlinnClassifier.h" + +#include "LoopBlinnMathUtils.h" + +namespace WebCore { + +using LoopBlinnMathUtils::approxEqual; +using LoopBlinnMathUtils::roundToZero; + +LoopBlinnClassifier::Result LoopBlinnClassifier::classify(const FloatPoint& c0, + const FloatPoint& c1, + const FloatPoint& c2, + const FloatPoint& c3) +{ + // Consult the chapter for the definitions of the following + // (terse) variable names. Note that the b0..b3 coordinates are + // homogeneous, so the "z" value (actually the w coordinate) must + // be 1.0. + FloatPoint3D b0(c0.x(), c0.y(), 1.0f); + FloatPoint3D b1(c1.x(), c1.y(), 1.0f); + FloatPoint3D b2(c2.x(), c2.y(), 1.0f); + FloatPoint3D b3(c3.x(), c3.y(), 1.0f); + + // Compute a1..a3. + float a1 = b0 * b3.cross(b2); + float a2 = b1 * b0.cross(b3); + float a3 = b2 * b1.cross(b0); + + // Compute d1..d3. + float d1 = a1 - 2 * a2 + 3 * a3; + float d2 = -a2 + 3 * a3; + float d3 = 3 * a3; + + // Experimentation has shown that the texture coordinates computed + // from these values quickly become huge, leading to roundoff errors + // and artifacts in the shader. It turns out that if we normalize + // the vector defined by (d1, d2, d3), this fixes the problem of the + // texture coordinates getting too large without affecting the + // classification results. + FloatPoint3D nd(d1, d2, d3); + nd.normalize(); + d1 = nd.x(); + d2 = nd.y(); + d3 = nd.z(); + + // Compute the discriminant. + // term0 is a common term in the computation which helps decide + // which way to classify the cusp case: as serpentine or loop. + float term0 = (3 * d2 * d2 - 4 * d1 * d3); + float discriminant = d1 * d1 * term0; + + // Experimentation has also shown that when the classification is + // near the boundary between one curve type and another, the shader + // becomes numerically unstable, particularly with the cusp case. + // Correct for this by rounding d1..d3 and the discriminant to zero + // when they get near it. + d1 = roundToZero(d1); + d2 = roundToZero(d2); + d3 = roundToZero(d3); + discriminant = roundToZero(discriminant); + + // Do the classification. + if (approxEqual(b0, b1) && approxEqual(b0, b2) && approxEqual(b0, b3)) + return Result(kPoint, d1, d2, d3); + + if (!discriminant) { + if (!d1 && !d2) { + if (!d3) + return Result(kLine, d1, d2, d3); + return Result(kQuadratic, d1, d2, d3); + } + + if (!d1) + return Result(kCusp, d1, d2, d3); + + // This is the boundary case described in Loop and Blinn's + // SIGGRAPH '05 paper of a cusp with inflection at infinity. + // Because term0 might not be exactly 0, we decide between using + // the serpentine and loop cases depending on its sign to avoid + // taking the square root of a negative number when computing the + // cubic texture coordinates. + if (term0 < 0) + return Result(kLoop, d1, d2, d3); + + return Result(kSerpentine, d1, d2, d3); + } + + if (discriminant > 0) + return Result(kSerpentine, d1, d2, d3); + + // discriminant < 0 + return Result(kLoop, d1, d2, d3); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/gpu/LoopBlinnClassifier.h b/WebCore/platform/graphics/gpu/LoopBlinnClassifier.h new file mode 100644 index 0000000..c665844 --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnClassifier.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: + * + * 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 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. + */ + +// Cubic curve classification algorithm from "Rendering Vector Art on +// the GPU" by Loop and Blinn, GPU Gems 3, Chapter 25: +// http://http.developer.nvidia.com/GPUGems3/gpugems3_ch25.html . + +#ifndef LoopBlinnClassifier_h +#define LoopBlinnClassifier_h + +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class FloatPoint; + +// Classifies cubic curves into specific types. +class LoopBlinnClassifier : public Noncopyable { +public: + // The types of cubic curves. + enum CurveType { + kSerpentine, + kCusp, + kLoop, + kQuadratic, + kLine, + kPoint + }; + + // The result of the classifier. + struct Result { + public: + Result(CurveType inputCurveType, float inputD1, float inputD2, float inputD3) + : curveType(inputCurveType) + , d1(inputD1) + , d2(inputD2) + , d3(inputD3) { } + + CurveType curveType; + + // These are coefficients used later in the computation of + // texture coordinates per vertex. + float d1; + float d2; + float d3; + }; + + // Classifies the given cubic bezier curve starting at c0, ending + // at c3, and affected by control points c1 and c2. + static Result classify(const FloatPoint& c0, + const FloatPoint& c1, + const FloatPoint& c2, + const FloatPoint& c3); + +private: + // This class does not need to be instantiated. + LoopBlinnClassifier() { } +}; + +} // namespace WebCore + +#endif // LoopBlinnClassifier_h diff --git a/WebCore/platform/graphics/gpu/LoopBlinnConstants.h b/WebCore/platform/graphics/gpu/LoopBlinnConstants.h new file mode 100644 index 0000000..1997d9f --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnConstants.h @@ -0,0 +1,40 @@ +/* + * 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: + * + * 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 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. + */ + +#ifndef LoopBlinnConstants_h +#define LoopBlinnConstants_h + +namespace WebCore { +namespace LoopBlinnConstants { + +enum FillSide { + LeftSide, + RightSide +}; + +} // namespace LoopBlinnConstants +} // namespace WebCore + +#endif // LoopBlinnConstants_h diff --git a/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp b/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp new file mode 100644 index 0000000..61ebc9b --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp @@ -0,0 +1,565 @@ +/* + * 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: + * + * 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 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 "LoopBlinnMathUtils.h" + +#include "FloatPoint.h" +#include "MathExtras.h" +#include <algorithm> +#include <string.h> // for memcpy + +namespace WebCore { +namespace LoopBlinnMathUtils { + +namespace { + +// Utility functions local to this file. +int orientation(const FloatPoint& p1, + const FloatPoint& p2, + const FloatPoint& p3) +{ + float crossProduct = (p2.y() - p1.y()) * (p3.x() - p2.x()) - (p3.y() - p2.y()) * (p2.x() - p1.x()); + return (crossProduct < 0.0f) ? -1 : ((crossProduct > 0.0f) ? 1 : 0); +} + +bool edgeEdgeTest(const FloatSize& v0Delta, + const FloatPoint& v0, + const FloatPoint& u0, + const FloatPoint& u1) +{ + // This edge to edge test is based on Franlin Antonio's gem: "Faster + // Line Segment Intersection", in Graphics Gems III, pp. 199-202. + float ax = v0Delta.width(); + float ay = v0Delta.height(); + float bx = u0.x() - u1.x(); + float by = u0.y() - u1.y(); + float cx = v0.x() - u0.x(); + float cy = v0.y() - u0.y(); + float f = ay * bx - ax * by; + float d = by * cx - bx * cy; + if ((f > 0 && d >= 0 && d <= f) || (f < 0 && d <= 0 && d >= f)) { + float e = ax * cy - ay * cx; + + // This additional test avoids reporting coincident edges, which + // is the behavior we want. + if (approxEqual(e, 0) || approxEqual(f, 0) || approxEqual(e, f)) + return false; + + if (f > 0) + return e >= 0 && e <= f; + + return e <= 0 && e >= f; + } + return false; +} + +bool edgeAgainstTriangleEdges(const FloatPoint& v0, + const FloatPoint& v1, + const FloatPoint& u0, + const FloatPoint& u1, + const FloatPoint& u2) +{ + FloatSize delta = v1 - v0; + // Test edge u0, u1 against v0, v1. + if (edgeEdgeTest(delta, v0, u0, u1)) + return true; + // Test edge u1, u2 against v0, v1. + if (edgeEdgeTest(delta, v0, u1, u2)) + return true; + // Test edge u2, u1 against v0, v1. + if (edgeEdgeTest(delta, v0, u2, u0)) + return true; + return false; +} + +// A roundoff factor in the cubic classification and texture coordinate +// generation algorithms. It primarily determines the handling of corner +// cases during the classification process. Be careful when adjusting it; +// it has been determined empirically to work well. When changing it, you +// should look in particular at shapes that contain quadratic curves and +// ensure they still look smooth. Once pixel tests are running against this +// algorithm, they should provide sufficient coverage to ensure that +// adjusting the constant won't break anything. +const float Epsilon = 5.0e-4f; + +} // anonymous namespace + +// Exported routines + +float roundToZero(float val) +{ + if (val < Epsilon && val > -Epsilon) + return 0; + return val; +} + +bool approxEqual(const FloatPoint& v0, const FloatPoint& v1) +{ + return (v0 - v1).diagonalLengthSquared() < Epsilon * Epsilon; +} + +bool approxEqual(const FloatPoint3D& v0, const FloatPoint3D& v1) +{ + return (v0 - v1).lengthSquared() < Epsilon * Epsilon; +} + +bool approxEqual(float f0, float f1) +{ + return fabsf(f0 - f1) < Epsilon; +} + +bool linesIntersect(const FloatPoint& p1, + const FloatPoint& q1, + const FloatPoint& p2, + const FloatPoint& q2) +{ + return (orientation(p1, q1, p2) != orientation(p1, q1, q2) + && orientation(p2, q2, p1) != orientation(p2, q2, q1)); +} + +bool pointInTriangle(const FloatPoint& point, + const FloatPoint& a, + const FloatPoint& b, + const FloatPoint& c) +{ + // Algorithm from http://www.blackpawn.com/texts/pointinpoly/default.html + float x0 = c.x() - a.x(); + float y0 = c.y() - a.y(); + float x1 = b.x() - a.x(); + float y1 = b.y() - a.y(); + float x2 = point.x() - a.x(); + float y2 = point.y() - a.y(); + + float dot00 = x0 * x0 + y0 * y0; + float dot01 = x0 * x1 + y0 * y1; + float dot02 = x0 * x2 + y0 * y2; + float dot11 = x1 * x1 + y1 * y1; + float dot12 = x1 * x2 + y1 * y2; + float denominator = dot00 * dot11 - dot01 * dot01; + if (!denominator) + // Triangle is zero-area. Treat query point as not being inside. + return false; + // Compute + float inverseDenominator = 1.0f / denominator; + float u = (dot11 * dot02 - dot01 * dot12) * inverseDenominator; + float v = (dot00 * dot12 - dot01 * dot02) * inverseDenominator; + + return (u > 0.0f) && (v > 0.0f) && (u + v < 1.0f); +} + +bool trianglesOverlap(const FloatPoint& a1, + const FloatPoint& b1, + const FloatPoint& c1, + const FloatPoint& a2, + const FloatPoint& b2, + const FloatPoint& c2) +{ + // Derived from coplanar_tri_tri() at + // http://jgt.akpeters.com/papers/ShenHengTang03/tri_tri.html , + // simplified for the 2D case and modified so that overlapping edges + // do not report overlapping triangles. + + // Test all edges of triangle 1 against the edges of triangle 2. + if (edgeAgainstTriangleEdges(a1, b1, a2, b2, c2) + || edgeAgainstTriangleEdges(b1, c1, a2, b2, c2) + || edgeAgainstTriangleEdges(c1, a1, a2, b2, c2)) + return true; + // Finally, test if tri1 is totally contained in tri2 or vice versa. + // The paper above only performs the first two point-in-triangle tests. + // Because we define that triangles sharing a vertex or edge don't + // overlap, we must perform additional tests to see whether one + // triangle is contained in the other. + if (pointInTriangle(a1, a2, b2, c2) + || pointInTriangle(a2, a1, b1, c1) + || pointInTriangle(b1, a2, b2, c2) + || pointInTriangle(b2, a1, b1, c1) + || pointInTriangle(c1, a2, b2, c2) + || pointInTriangle(c2, a1, b1, c1)) + return true; + return false; +} + +namespace { + +// Helper routines for public XRay queries below. All of this code +// originated in Skia; see include/core/ and src/core/, SkScalar.h and +// SkGeometry.{cpp,h}. + +const float NearlyZeroConstant = (1.0f / (1 << 12)); + +bool nearlyZero(float x, float tolerance = NearlyZeroConstant) +{ + ASSERT(tolerance > 0.0f); + return ::fabsf(x) < tolerance; +} + +// Linearly interpolate between a and b, based on t. +// If t is 0, return a; if t is 1, return b; else interpolate. +// t must be [0..1]. +float interpolate(float a, float b, float t) +{ + ASSERT(t >= 0 && t <= 1); + return a + (b - a) * t; +} + +float evaluateCubic(float controlPoint0, float controlPoint1, float controlPoint2, float controlPoint3, float t) +{ + ASSERT(t >= 0 && t <= 1); + + if (!t) + return controlPoint0; + + float ab = interpolate(controlPoint0, controlPoint1, t); + float bc = interpolate(controlPoint1, controlPoint2, t); + float cd = interpolate(controlPoint2, controlPoint3, t); + float abc = interpolate(ab, bc, t); + float bcd = interpolate(bc, cd, t); + return interpolate(abc, bcd, t); +} + +// Evaluates the point on the source cubic specified by t, 0 <= t <= 1.0. +FloatPoint evaluateCubicAt(const FloatPoint cubic[4], float t) +{ + return FloatPoint(evaluateCubic(cubic[0].x(), cubic[1].x(), cubic[2].x(), cubic[3].x(), t), + evaluateCubic(cubic[0].y(), cubic[1].y(), cubic[2].y(), cubic[3].y(), t)); +} + +bool xRayCrossesMonotonicCubic(const XRay& xRay, const FloatPoint cubic[4], bool& ambiguous) +{ + ambiguous = false; + + // Find the minimum and maximum y of the extrema, which are the + // first and last points since this cubic is monotonic + float minY = std::min(cubic[0].y(), cubic[3].y()); + float maxY = std::max(cubic[0].y(), cubic[3].y()); + + if (xRay.y() == cubic[0].y() + || xRay.y() < minY + || xRay.y() > maxY) { + // The query line definitely does not cross the curve + ambiguous = (xRay.y() == cubic[0].y()); + return false; + } + + const bool pointAtExtremum = (xRay.y() == cubic[3].y()); + + float minX = std::min(std::min(std::min(cubic[0].x(), cubic[1].x()), + cubic[2].x()), + cubic[3].x()); + if (xRay.x() < minX) { + // The query line definitely crosses the curve + ambiguous = pointAtExtremum; + return true; + } + + float maxX = std::max(std::max(std::max(cubic[0].x(), cubic[1].x()), + cubic[2].x()), + cubic[3].x()); + if (xRay.x() > maxX) + // The query line definitely does not cross the curve + return false; + + // Do a binary search to find the parameter value which makes y as + // close as possible to the query point. See whether the query + // line's origin is to the left of the associated x coordinate. + + // MaxIterations is chosen as the number of mantissa bits for a float, + // since there's no way we are going to get more precision by + // iterating more times than that. + const int MaxIterations = 23; + FloatPoint evaluatedPoint; + int iter = 0; + float upperT; + float lowerT; + // Need to invert direction of t parameter if cubic goes up + // instead of down + if (cubic[3].y() > cubic[0].y()) { + upperT = 1; + lowerT = 0; + } else { + upperT = 0; + lowerT = 1; + } + do { + float t = 0.5f * (upperT + lowerT); + evaluatedPoint = evaluateCubicAt(cubic, t); + if (xRay.y() > evaluatedPoint.y()) + lowerT = t; + else + upperT = t; + } while (++iter < MaxIterations && !nearlyZero(evaluatedPoint.y() - xRay.y())); + + // FIXME: once we have more regression tests for this code, + // determine whether this should be using a fuzzy test. + if (xRay.x() <= evaluatedPoint.x()) { + ambiguous = pointAtExtremum; + return true; + } + return false; +} + +// Divides the numerator by the denominator safely for the case where +// the result must lie in the range (0..1). Result indicates whether +// the result is valid. +bool safeUnitDivide(float numerator, float denominator, float& ratio) +{ + if (numerator < 0) { + // Make the "numerator >= denominator" check below work. + numerator = -numerator; + denominator = -denominator; + } + if (!numerator || !denominator || numerator >= denominator) + return false; + float r = numerator / denominator; + if (isnan(r)) + return false; + ASSERT(r >= 0 && r < 1); + if (!r) // catch underflow if numerator <<<< denominator + return false; + ratio = r; + return true; +} + +// From Numerical Recipes in C. +// +// q = -1/2 (b + sign(b) sqrt[b*b - 4*a*c]) +// x1 = q / a +// x2 = c / q +// +// Returns the number of real roots of the equation [0..2]. Roots are +// returned in sorted order, smaller root first. +int findUnitQuadRoots(float a, float b, float c, float roots[2]) +{ + if (!a) + return safeUnitDivide(-c, b, roots[0]) ? 1 : 0; + + float discriminant = b*b - 4*a*c; + if (discriminant < 0 || isnan(discriminant)) // complex roots + return 0; + discriminant = sqrtf(discriminant); + + float q = (b < 0) ? -(b - discriminant) / 2 : -(b + discriminant) / 2; + int numberOfRoots = 0; + if (safeUnitDivide(q, a, roots[numberOfRoots])) + ++numberOfRoots; + if (safeUnitDivide(c, q, roots[numberOfRoots])) + ++numberOfRoots; + if (numberOfRoots == 2) { + // Seemingly have two roots. Check for equality and sort. + if (roots[0] == roots[1]) + return 1; + if (roots[0] > roots[1]) + std::swap(roots[0], roots[1]); + } + return numberOfRoots; +} + +// Cubic'(t) = pt^2 + qt + r, where +// p = 3(-a + 3(b - c) + d) +// q = 6(a - 2b + c) +// r = 3(b - a) +// Solve for t, keeping only those that fit between 0 < t < 1. +int findCubicExtrema(float a, float b, float c, float d, float tValues[2]) +{ + // Divide p, q, and r by 3 to simplify the equations. + float p = d - a + 3*(b - c); + float q = 2*(a - b - b + c); + float r = b - a; + + return findUnitQuadRoots(p, q, r, tValues); +} + +void interpolateCubicCoords(float controlPoint0, float controlPoint1, float controlPoint2, float controlPoint3, float* dst, float t) +{ + float ab = interpolate(controlPoint0, controlPoint1, t); + float bc = interpolate(controlPoint1, controlPoint2, t); + float cd = interpolate(controlPoint2, controlPoint3, t); + float abc = interpolate(ab, bc, t); + float bcd = interpolate(bc, cd, t); + float abcd = interpolate(abc, bcd, t); + + dst[0] = controlPoint0; + dst[2] = ab; + dst[4] = abc; + dst[6] = abcd; + dst[8] = bcd; + dst[10] = cd; + dst[12] = controlPoint3; +} + +#ifndef NDEBUG +bool isUnitInterval(float x) +{ + return x > 0 && x < 1; +} +#endif + +void chopCubicAtTValues(const FloatPoint src[4], FloatPoint dst[], const float tValues[], int roots) +{ +#ifndef NDEBUG + for (int i = 0; i < roots - 1; ++i) { + ASSERT(isUnitInterval(tValues[i])); + ASSERT(isUnitInterval(tValues[i+1])); + ASSERT(tValues[i] < tValues[i+1]); + } +#endif + + if (!roots) { + // nothing to chop + for (int j = 0; j < 4; ++j) + dst[j] = src[j]; + return; + } + + float t = tValues[0]; + FloatPoint tmp[4]; + for (int j = 0; j < 4; ++j) + tmp[j] = src[j]; + + for (int i = 0; i < roots; ++i) { + chopCubicAt(tmp, dst, t); + if (i == roots - 1) + break; + + dst += 3; + // Make tmp contain the remaining cubic (after the first chop). + for (int j = 0; j < 4; ++j) + tmp[j] = dst[j]; + + // Watch out for the case that the renormalized t isn't in range. + if (!safeUnitDivide(tValues[i+1] - tValues[i], 1.0f - tValues[i], t)) { + // If it isn't, just create a degenerate cubic. + dst[4] = dst[5] = dst[6] = tmp[3]; + break; + } + } +} + +void flattenDoubleCubicYExtrema(FloatPoint coords[7]) +{ + coords[2].setY(coords[3].y()); + coords[4].setY(coords[3].y()); +} + +int chopCubicAtYExtrema(const FloatPoint src[4], FloatPoint dst[10]) +{ + float tValues[2]; + int roots = findCubicExtrema(src[0].y(), src[1].y(), src[2].y(), src[3].y(), tValues); + + chopCubicAtTValues(src, dst, tValues, roots); + if (roots) { + // we do some cleanup to ensure our Y extrema are flat + flattenDoubleCubicYExtrema(&dst[0]); + if (roots == 2) + flattenDoubleCubicYExtrema(&dst[3]); + } + return roots; +} + +} // anonymous namespace + +// Public cubic operations. + +void chopCubicAt(const FloatPoint src[4], FloatPoint dst[7], float t) +{ + ASSERT(t >= 0 && t <= 1); + + float output[14]; + interpolateCubicCoords(src[0].x(), src[1].x(), src[2].x(), src[3].x(), &output[0], t); + interpolateCubicCoords(src[0].y(), src[1].y(), src[2].y(), src[3].y(), &output[1], t); + for (int i = 0; i < 7; i++) + dst[i].set(output[2 * i], output[2 * i + 1]); +} + +// Public XRay queries. + +bool xRayCrossesLine(const XRay& xRay, const FloatPoint pts[2], bool& ambiguous) +{ + ambiguous = false; + + // Determine quick discards. + // Consider query line going exactly through point 0 to not + // intersect, for symmetry with xRayCrossesMonotonicCubic. + if (xRay.y() == pts[0].y()) { + ambiguous = true; + return false; + } + if (xRay.y() < pts[0].y() && xRay.y() < pts[1].y()) + return false; + if (xRay.y() > pts[0].y() && xRay.y() > pts[1].y()) + return false; + if (xRay.x() > pts[0].x() && xRay.x() > pts[1].x()) + return false; + // Determine degenerate cases + if (nearlyZero(pts[0].y() - pts[1].y())) + return false; + if (nearlyZero(pts[0].x() - pts[1].x())) { + // We've already determined the query point lies within the + // vertical range of the line segment. + if (xRay.x() <= pts[0].x()) { + ambiguous = (xRay.y() == pts[1].y()); + return true; + } + return false; + } + // Ambiguity check + if (xRay.y() == pts[1].y()) { + if (xRay.x() <= pts[1].x()) { + ambiguous = true; + return true; + } + return false; + } + // Full line segment evaluation + float deltaY = pts[1].y() - pts[0].y(); + float deltaX = pts[1].x() - pts[0].x(); + float slope = deltaY / deltaX; + float b = pts[0].y() - slope * pts[0].x(); + // Solve for x coordinate at y = xRay.y() + float x = (xRay.y() - b) / slope; + return xRay.x() <= x; +} + +int numXRayCrossingsForCubic(const XRay& xRay, const FloatPoint cubic[4], bool& ambiguous) +{ + int numCrossings = 0; + FloatPoint monotonicCubics[10]; + int numMonotonicCubics = 1 + chopCubicAtYExtrema(cubic, monotonicCubics); + ambiguous = false; + FloatPoint* monotonicCubicsPointer = &monotonicCubics[0]; + for (int i = 0; i < numMonotonicCubics; ++i) { + if (xRayCrossesMonotonicCubic(xRay, monotonicCubicsPointer, ambiguous)) + ++numCrossings; + if (ambiguous) + return 0; + monotonicCubicsPointer += 3; + } + return numCrossings; +} + +} // namespace LoopBlinnMathUtils +} // namespace WebCore diff --git a/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h b/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h new file mode 100644 index 0000000..b9d19c5 --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h @@ -0,0 +1,108 @@ +/* + * 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: + * + * 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 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. + */ + +#ifndef LoopBlinnMathUtils_h +#define LoopBlinnMathUtils_h + +#include "FloatPoint.h" +#include "FloatPoint3D.h" +#include <math.h> + +namespace WebCore { + +// Use a namespace for these so we can easily import them. +namespace LoopBlinnMathUtils { + +float roundToZero(float val); +bool approxEqual(const FloatPoint& v0, const FloatPoint& v1); +bool approxEqual(const FloatPoint3D& v0, const FloatPoint3D& v1); +bool approxEqual(float f0, float f1); + +// Determines whether the line segment between (p1, q1) intersects +// that between (p2, q2). +bool linesIntersect(const FloatPoint& p1, + const FloatPoint& q1, + const FloatPoint& p2, + const FloatPoint& q2); + +// Determines whether "point" is inside the 2D triangle defined by +// vertices a, b, and c. This test defines that points exactly on an +// edge are not considered to be inside the triangle. +bool pointInTriangle(const FloatPoint& point, + const FloatPoint& a, + const FloatPoint& b, + const FloatPoint& c); + +// Determines whether the triangles defined by the points (a1, b1, c1) +// and (a2, b2, c2) overlap. The definition of this function is that +// if the two triangles only share an adjacent edge or vertex, they +// are not considered to overlap. +bool trianglesOverlap(const FloatPoint& a1, + const FloatPoint& b1, + const FloatPoint& c1, + const FloatPoint& a2, + const FloatPoint& b2, + const FloatPoint& c2); + +// Given a src cubic bezier, chops it at the specified t value, +// where 0 < t < 1, and returns the two new cubics in dst[0..3] +// and dst[3..6]. +void chopCubicAt(const FloatPoint src[4], FloatPoint dst[7], float t); + +// "X-Ray" queries. An XRay is a half-line originating at the given +// point and extending to x=+infinity. +typedef FloatPoint XRay; + +// Given an arbitrary cubic bezier, return the number of times an XRay +// crosses the cubic. Valid return values are [0..3]. +// +// By definition the cubic is open at the starting point; in other +// words, if pt.fY is equivalent to cubic[0].fY, and pt.fX is to the +// left of the curve, the line is not considered to cross the curve, +// but if it is equal to cubic[3].fY then it is considered to +// cross. +// +// Outgoing "ambiguous" argument indicates whether the answer is ambiguous +// because the query occurred exactly at one of the endpoints' y +// coordinates or at a tangent point, indicating that another query y +// coordinate is preferred for robustness. +int numXRayCrossingsForCubic(const XRay& xRay, + const FloatPoint cubic[4], + bool& ambiguous); + +// Given a line segment from lineEndpoints[0] to lineEndpoints[1], and an +// XRay, returns true if they intersect. Outgoing "ambiguous" argument +// indicates whether the answer is ambiguous because the query occurred +// exactly at one of the endpoints' y coordinates, indicating that another +// query y coordinate is preferred for robustness. +bool xRayCrossesLine(const XRay& xRay, + const FloatPoint lineEndpoints[2], + bool& ambiguous); + +} // namespace LoopBlinnMathUtils + +} // namespace WebCore + +#endif // LoopBlinnMathUtils_h diff --git a/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp b/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp new file mode 100644 index 0000000..ac82637 --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp @@ -0,0 +1,171 @@ +/* + * 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: + * + * 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 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 "LoopBlinnTextureCoords.h" + +#include <math.h> +#include <wtf/Assertions.h> + +namespace WebCore { + +LoopBlinnTextureCoords::Result LoopBlinnTextureCoords::compute(const LoopBlinnClassifier::Result& classification, LoopBlinnConstants::FillSide sideToFill) +{ + // Loop and Blinn's formulation states that the right side of the + // curve is defined to be the inside (filled region), but for some + // reason it looks like with the default orientation parameters we + // are filling the left side of the curve. Regardless, because we + // can receive arbitrarily oriented curves as input, we might have + // to reverse the orientation of the cubic texture coordinates even + // in cases where the paper doesn't say it is necessary. + bool reverseOrientation = false; + static const float OneThird = 1.0f / 3.0f; + static const float TwoThirds = 2.0f / 3.0f; + LoopBlinnClassifier::CurveType curveType = classification.curveType; + + LoopBlinnTextureCoords::Result result; + + switch (curveType) { + case LoopBlinnClassifier::kSerpentine: { + float t1 = sqrtf(9.0f * classification.d2 * classification.d2 - 12 * classification.d1 * classification.d3); + float ls = 3.0f * classification.d2 - t1; + float lt = 6.0f * classification.d1; + float ms = 3.0f * classification.d2 + t1; + float mt = lt; + float ltMinusLs = lt - ls; + float mtMinusMs = mt - ms; + result.klmCoordinates[0] = FloatPoint3D(ls * ms, + ls * ls * ls, + ms * ms * ms); + result.klmCoordinates[1] = FloatPoint3D(OneThird * (3.0f * ls * ms - ls * mt - lt * ms), + ls * ls * (ls - lt), + ms * ms * (ms - mt)); + result.klmCoordinates[2] = FloatPoint3D(OneThird * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt)), + ltMinusLs * ltMinusLs * ls, + mtMinusMs * mtMinusMs * ms); + result.klmCoordinates[3] = FloatPoint3D(ltMinusLs * mtMinusMs, + -(ltMinusLs * ltMinusLs * ltMinusLs), + -(mtMinusMs * mtMinusMs * mtMinusMs)); + if (classification.d1 < 0.0f) + reverseOrientation = true; + break; + } + + case LoopBlinnClassifier::kLoop: { + float t1 = sqrtf(4.0f * classification.d1 * classification.d3 - 3.0f * classification.d2 * classification.d2); + float ls = classification.d2 - t1; + float lt = 2.0f * classification.d1; + float ms = classification.d2 + t1; + float mt = lt; + + // Figure out whether there is a rendering artifact requiring + // the curve to be subdivided by the caller. + float ql = ls / lt; + float qm = ms / mt; + if (0.0f < ql && ql < 1.0f) { + result.hasRenderingArtifact = true; + result.subdivisionParameterValue = ql; + return result; + } + + if (0.0f < qm && qm < 1.0f) { + result.hasRenderingArtifact = true; + result.subdivisionParameterValue = qm; + return result; + } + + float ltMinusLs = lt - ls; + float mtMinusMs = mt - ms; + result.klmCoordinates[0] = FloatPoint3D(ls * ms, + ls * ls * ms, + ls * ms * ms); + result.klmCoordinates[1] = FloatPoint3D(OneThird * (-ls * mt - lt * ms + 3.0f * ls * ms), + -OneThird * ls * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms), + -OneThird * ms * (ls * (2.0f * mt - 3.0f * ms) + lt * ms)); + result.klmCoordinates[2] = FloatPoint3D(OneThird * (lt * (mt - 2.0f * ms) + ls * (3.0f * ms - 2.0f * mt)), + OneThird * (lt - ls) * (ls * (2.0f * mt - 3.0f * ms) + lt * ms), + OneThird * (mt - ms) * (ls * (mt - 3.0f * ms) + 2.0f * lt * ms)); + result.klmCoordinates[3] = FloatPoint3D(ltMinusLs * mtMinusMs, + -(ltMinusLs * ltMinusLs) * mtMinusMs, + -ltMinusLs * mtMinusMs * mtMinusMs); + reverseOrientation = ((classification.d1 > 0.0f && result.klmCoordinates[0].x() < 0.0f) + || (classification.d1 < 0.0f && result.klmCoordinates[0].x() > 0.0f)); + break; + } + + case LoopBlinnClassifier::kCusp: { + float ls = classification.d3; + float lt = 3.0f * classification.d2; + float lsMinusLt = ls - lt; + result.klmCoordinates[0] = FloatPoint3D(ls, + ls * ls * ls, + 1.0f); + result.klmCoordinates[1] = FloatPoint3D(ls - OneThird * lt, + ls * ls * lsMinusLt, + 1.0f); + result.klmCoordinates[2] = FloatPoint3D(ls - TwoThirds * lt, + lsMinusLt * lsMinusLt * ls, + 1.0f); + result.klmCoordinates[3] = FloatPoint3D(lsMinusLt, + lsMinusLt * lsMinusLt * lsMinusLt, + 1.0f); + break; + } + + case LoopBlinnClassifier::kQuadratic: { + result.klmCoordinates[0] = FloatPoint3D(0, 0, 0); + result.klmCoordinates[1] = FloatPoint3D(OneThird, 0, OneThird); + result.klmCoordinates[2] = FloatPoint3D(TwoThirds, OneThird, TwoThirds); + result.klmCoordinates[3] = FloatPoint3D(1, 1, 1); + if (classification.d3 < 0) + reverseOrientation = true; + break; + } + + case LoopBlinnClassifier::kLine: + case LoopBlinnClassifier::kPoint: + result.isLineOrPoint = true; + break; + + default: + ASSERT_NOT_REACHED(); + break; + } + + if (sideToFill == LoopBlinnConstants::RightSide) + reverseOrientation = !reverseOrientation; + + if (reverseOrientation) { + for (int i = 0; i < 4; ++i) { + result.klmCoordinates[i].setX(-result.klmCoordinates[i].x()); + result.klmCoordinates[i].setY(-result.klmCoordinates[i].y()); + } + } + + return result; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.h b/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.h new file mode 100644 index 0000000..5fdeb3b --- /dev/null +++ b/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.h @@ -0,0 +1,82 @@ +/* + * 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: + * + * 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 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. + */ + +#ifndef LoopBlinnTextureCoords_h +#define LoopBlinnTextureCoords_h + +#include "FloatPoint3D.h" +#include "LoopBlinnClassifier.h" +#include "LoopBlinnConstants.h" + +#include <wtf/Noncopyable.h> + +namespace WebCore { + +// Computes three-dimensional texture coordinates for the control +// points of a cubic curve for rendering via the shader in "Rendering +// Vector Art on the GPU" by Loop and Blinn, GPU Gems 3, Chapter 25. +class LoopBlinnTextureCoords { +public: + // Container for the cubic texture coordinates and other associated + // information. + struct Result { + Result() + : isLineOrPoint(false) + , hasRenderingArtifact(false) + , subdivisionParameterValue(0.0f) { } + + // The (k, l, m) texture coordinates that are to be associated + // with the four control points of the cubic curve. + FloatPoint3D klmCoordinates[4]; + + // Indicates whether the curve is a line or a point, in which case + // we do not need to add its triangles to the mesh. + bool isLineOrPoint; + + // For the loop case, indicates whether a rendering artifact was + // detected, in which case the curve needs to be further + // subdivided. + bool hasRenderingArtifact; + + // If a rendering artifact will occur for the given loop curve, + // this is the parameter value (0 <= value <= 1) at which the + // curve needs to be subdivided to fix the artifact. + float subdivisionParameterValue; + }; + + // Computes the texture coordinates for a cubic curve segment's + // control points, given the classification of the curve as well as + // an indication of which side is to be filled. + static Result compute(const LoopBlinnClassifier::Result& classification, + LoopBlinnConstants::FillSide sideToFill); + +private: + // This class does not need to be instantiated. + LoopBlinnTextureCoords() { } +}; + +} // namespace WebCore + +#endif // LoopBlinnTextureCoords_h diff --git a/WebCore/platform/graphics/gpu/PODArena.h b/WebCore/platform/graphics/gpu/PODArena.h new file mode 100644 index 0000000..f68baef --- /dev/null +++ b/WebCore/platform/graphics/gpu/PODArena.h @@ -0,0 +1,211 @@ +/* + * 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: + * + * 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 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. + */ + +#ifndef PODArena_h +#define PODArena_h + +#include <stdint.h> +#include <wtf/Assertions.h> +#include <wtf/FastMalloc.h> +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + +// An arena which allocates only Plain Old Data (POD), or classes and +// structs bottoming out in Plain Old Data. NOTE: the constructors of +// the objects allocated in this arena are called, but _not_ their +// destructors. + +class PODArena : public RefCounted<PODArena> { +public: + // The arena is configured with an allocator, which is responsible + // for allocating and freeing chunks of memory at a time. + class Allocator : public RefCounted<Allocator> { + public: + virtual void* allocate(size_t size) = 0; + virtual void free(void* ptr) = 0; + protected: + virtual ~Allocator() { } + friend class WTF::RefCounted<Allocator>; + }; + + // The Arena's default allocator, which uses fastMalloc and + // fastFree to allocate chunks of storage. + class FastMallocAllocator : public Allocator { + public: + static PassRefPtr<FastMallocAllocator> create() + { + return adoptRef(new FastMallocAllocator); + } + + virtual void* allocate(size_t size) { return fastMalloc(size); } + virtual void free(void* ptr) { fastFree(ptr); } + + protected: + FastMallocAllocator() { } + }; + + // Creates a new PODArena configured with a FastMallocAllocator. + static PassRefPtr<PODArena> create() + { + return adoptRef(new PODArena); + } + + // Creates a new PODArena configured with the given Allocator. + static PassRefPtr<PODArena> create(PassRefPtr<Allocator> allocator) + { + return adoptRef(new PODArena(allocator)); + } + + // Allocates an object from the arena. + template<class T> T* allocateObject() + { + void* ptr = allocateBase<T>(); + if (ptr) { + // Use placement operator new to allocate a T at this location. + new(ptr) T(); + } + return static_cast<T*>(ptr); + } + + // Allocates an object from the arena, calling a single-argument constructor. + template<class T, class Argument1Type> T* allocateObject(const Argument1Type& argument1) + { + void* ptr = allocateBase<T>(); + if (ptr) { + // Use placement operator new to allocate a T at this location. + new(ptr) T(argument1); + } + return static_cast<T*>(ptr); + } + + // The initial size of allocated chunks; increases as necessary to + // satisfy large allocations. Mainly public for unit tests. + enum { + DefaultChunkSize = 16384 + }; + +protected: + ~PODArena() { } + friend class WTF::RefCounted<PODArena>; + +private: + PODArena() + : m_allocator(FastMallocAllocator::create()) + , m_current(0) + , m_currentChunkSize(DefaultChunkSize) { } + + explicit PODArena(PassRefPtr<Allocator> allocator) + : m_allocator(allocator) + , m_current(0) + , m_currentChunkSize(DefaultChunkSize) { } + + // Returns the alignment requirement for classes and structs on the + // current platform. + template <class T> static size_t minAlignment() + { + return WTF_ALIGN_OF(T); + } + + template<class T> void* allocateBase() + { + void* ptr = 0; + size_t roundedSize = roundUp(sizeof(T), minAlignment<T>()); + if (m_current) + ptr = m_current->allocate(roundedSize); + + if (!ptr) { + if (roundedSize > m_currentChunkSize) + m_currentChunkSize = roundedSize; + m_chunks.append(adoptPtr(new Chunk(m_allocator.get(), m_currentChunkSize))); + m_current = m_chunks.last().get(); + ptr = m_current->allocate(roundedSize); + } + return ptr; + } + + // Rounds up the given allocation size to the specified alignment. + size_t roundUp(size_t size, size_t alignment) + { + ASSERT(!(alignment % 2)); + return (size + alignment - 1) & ~(alignment - 1); + } + + // Manages a chunk of memory and individual allocations out of it. + class Chunk : public Noncopyable { + public: + // Allocates a block of memory of the given size from the passed + // Allocator. + Chunk(Allocator* allocator, size_t size) + : m_allocator(allocator) + , m_size(size) + , m_currentOffset(0) + { + m_base = static_cast<uint8_t*>(m_allocator->allocate(size)); + } + + // Frees the memory allocated from the Allocator in the + // constructor. + ~Chunk() + { + m_allocator->free(m_base); + } + + // Returns a pointer to "size" bytes of storage, or 0 if this + // Chunk could not satisfy the allocation. + void* allocate(size_t size) + { + // Check for overflow + if (m_currentOffset + size < m_currentOffset) + return 0; + + if (m_currentOffset + size > m_size) + return 0; + + void* result = m_base + m_currentOffset; + m_currentOffset += size; + return result; + } + + private: + Allocator* m_allocator; + uint8_t* m_base; + size_t m_size; + size_t m_currentOffset; + }; + + RefPtr<Allocator> m_allocator; + Chunk* m_current; + size_t m_currentChunkSize; + Vector<OwnPtr<Chunk> > m_chunks; +}; + +} // namespace WebCore + +#endif // PODArena_h diff --git a/WebCore/platform/graphics/gpu/PODInterval.h b/WebCore/platform/graphics/gpu/PODInterval.h new file mode 100644 index 0000000..9df69ba --- /dev/null +++ b/WebCore/platform/graphics/gpu/PODInterval.h @@ -0,0 +1,155 @@ +/* + * 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: + * + * 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 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. + */ + +#ifndef PODInterval_h +#define PODInterval_h + +#ifndef NDEBUG +#include "StringBuilder.h" +#endif + +namespace WebCore { + +// Class representing a closed interval which can hold an arbitrary +// Plain Old Datatype (POD) as its endpoints and a piece of user +// data. An important characteristic for the algorithms we use is that +// if two intervals have identical endpoints but different user data, +// they are not considered to be equal. This situation can arise when +// representing the vertical extents of bounding boxes of overlapping +// triangles, where the pointer to the triangle is the user data of +// the interval. +// +// *Note* that the destructors of type T and UserData will *not* be +// called by this class. They must not allocate any memory that is +// required to be cleaned up in their destructors. +// +// The following constructors and operators must be implemented on +// type T: +// +// - Copy constructor (if user data is desired) +// - operator< +// - operator== +// - operator= +// +// If the UserData type is specified, it must support a copy +// constructor and assignment operator. +// +// In debug mode, printing of intervals and the data they contain is +// enabled. This requires the following functions to be available: +// +// String valueToString(const T&); +// String valueToString(const UserData&); +// +// Note that this class requires a copy constructor and assignment +// operator in order to be stored in the red-black tree. + +template<class T, class UserData = void*> +class PODInterval { +public: + // Constructor from endpoints. This constructor only works when the + // UserData type is a pointer or other type which can be initialized + // with 0. + PODInterval(const T& low, const T& high) + : m_low(low) + , m_high(high) + , m_data(0) + , m_maxHigh(high) + { + } + + // Constructor from two endpoints plus explicit user data. + PODInterval(const T& low, const T& high, const UserData data) + : m_low(low) + , m_high(high) + , m_data(data) + , m_maxHigh(high) + { + } + + const T& low() const { return m_low; } + const T& high() const { return m_high; } + const UserData& data() const { return m_data; } + + bool overlaps(const T& low, const T& high) const + { + if (this->high() < low) + return false; + if (high < this->low()) + return false; + return true; + } + + bool overlaps(const PODInterval& other) const + { + return overlaps(other.low(), other.high()); + } + + // Returns true if this interval is "less" than the other. The + // comparison is performed on the low endpoints of the intervals. + bool operator<(const PODInterval& other) const + { + return low() < other.low(); + } + + // Returns true if this interval is strictly equal to the other, + // including comparison of the user data. + bool operator==(const PODInterval& other) const + { + return (low() == other.low() + && high() == other.high() + && data() == other.data()); + } + + const T& maxHigh() const { return m_maxHigh; } + void setMaxHigh(const T& maxHigh) { m_maxHigh = maxHigh; } + +#ifndef NDEBUG + // Support for printing PODIntervals. + String toString() const + { + StringBuilder builder; + builder.append("[PODInterval ("); + builder.append(valueToString(low())); + builder.append(", "); + builder.append(valueToString(high())); + builder.append("), data="); + builder.append(valueToString(data())); + builder.append(", maxHigh="); + builder.append(valueToString(maxHigh())); + builder.append("]"); + return builder.toString(); + } +#endif + +private: + T m_low; + T m_high; + UserData m_data; + T m_maxHigh; +}; + +} // namespace WebCore + +#endif // PODInterval_h diff --git a/WebCore/platform/graphics/gpu/PODIntervalTree.h b/WebCore/platform/graphics/gpu/PODIntervalTree.h new file mode 100644 index 0000000..c0a86aa --- /dev/null +++ b/WebCore/platform/graphics/gpu/PODIntervalTree.h @@ -0,0 +1,217 @@ +/* + * 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: + * + * 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 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. + */ + +#ifndef PODIntervalTree_h +#define PODIntervalTree_h + +#include "PODArena.h" +#include "PODInterval.h" +#include "PODRedBlackTree.h" +#include <wtf/Assertions.h> +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +namespace WebCore { + +// An interval tree, which is a form of augmented red-black tree. It +// supports efficient (O(lg n)) insertion, removal and querying of +// intervals in the tree. +template<class T, class UserData = void*> +class PODIntervalTree : public Noncopyable, + public PODRedBlackTree<PODInterval<T, UserData> > { +public: + // Typedef to reduce typing when declaring intervals to be stored in + // this tree. + typedef PODInterval<T, UserData> IntervalType; + + PODIntervalTree() + : PODRedBlackTree<IntervalType>() + { + init(); + } + + explicit PODIntervalTree(PassRefPtr<PODArena> arena) + : PODRedBlackTree<IntervalType>(arena) + { + init(); + } + + // Returns all intervals in the tree which overlap the given query + // interval. The returned intervals are sorted by increasing low + // endpoint. + Vector<IntervalType> allOverlaps(const IntervalType& interval) const + { + Vector<IntervalType> result; + allOverlaps(interval, result); + return result; + } + + // Returns all intervals in the tree which overlap the given query + // interval. The returned intervals are sorted by increasing low + // endpoint. + void allOverlaps(const IntervalType& interval, Vector<IntervalType>& result) const + { + // Explicit dereference of "this" required because of + // inheritance rules in template classes. + searchForOverlapsFrom(this->root(), interval, result); + } + + // Helper to create interval objects. + static IntervalType createInterval(const T& low, const T& high, const UserData data = 0) + { + return IntervalType(low, high, data); + } + + virtual bool checkInvariants() const + { + if (!PODRedBlackTree<IntervalType>::checkInvariants()) + return false; + if (!this->root()) + return true; + return checkInvariantsFromNode(this->root(), 0); + } + +private: + typedef typename PODRedBlackTree<IntervalType>::Node IntervalNode; + + // Initializes the tree. + void init() + { + // Explicit dereference of "this" required because of + // inheritance rules in template classes. + this->setNeedsFullOrderingComparisons(true); + } + + // Starting from the given node, adds all overlaps with the given + // interval to the result vector. The intervals are sorted by + // increasing low endpoint. + void searchForOverlapsFrom(IntervalNode* node, const IntervalType& interval, Vector<IntervalType>& res) const + { + if (!node) + return; + + // Because the intervals are sorted by left endpoint, inorder + // traversal produces results sorted as desired. + + // See whether we need to traverse the left subtree. + IntervalNode* left = node->left(); + if (left + // This is phrased this way to avoid the need for operator + // <= on type T. + && !(left->data().maxHigh() < interval.low())) + searchForOverlapsFrom(left, interval, res); + + // Check for overlap with current node. + if (node->data().overlaps(interval)) + res.append(node->data()); + + // See whether we need to traverse the right subtree. + // This is phrased this way to avoid the need for operator <= + // on type T. + if (!(interval.high() < node->data().low())) + searchForOverlapsFrom(node->right(), interval, res); + } + + virtual bool updateNode(IntervalNode* node) + { + // Would use const T&, but need to reassign this reference in this + // function. + const T* curMax = &node->data().high(); + IntervalNode* left = node->left(); + if (left) { + if (*curMax < left->data().maxHigh()) + curMax = &left->data().maxHigh(); + } + IntervalNode* right = node->right(); + if (right) { + if (*curMax < right->data().maxHigh()) + curMax = &right->data().maxHigh(); + } + // This is phrased like this to avoid needing operator!= on type T. + if (!(*curMax == node->data().maxHigh())) { + node->data().setMaxHigh(*curMax); + return true; + } + return false; + } + + bool checkInvariantsFromNode(IntervalNode* node, T* currentMaxValue) const + { + // These assignments are only done in order to avoid requiring + // a default constructor on type T. + T leftMaxValue(node->data().maxHigh()); + T rightMaxValue(node->data().maxHigh()); + IntervalNode* left = node->left(); + IntervalNode* right = node->right(); + if (left) { + if (!checkInvariantsFromNode(left, &leftMaxValue)) + return false; + } + if (right) { + if (!checkInvariantsFromNode(right, &rightMaxValue)) + return false; + } + if (!left && !right) { + // Base case. + if (currentMaxValue) + *currentMaxValue = node->data().high(); + return (node->data().high() == node->data().maxHigh()); + } + T localMaxValue(node->data().maxHigh()); + if (!left || !right) { + if (left) + localMaxValue = leftMaxValue; + else + localMaxValue = rightMaxValue; + } else + localMaxValue = (leftMaxValue < rightMaxValue) ? rightMaxValue : leftMaxValue; + if (localMaxValue < node->data().high()) + localMaxValue = node->data().high(); + if (!(localMaxValue == node->data().maxHigh())) { +#ifndef NDEBUG + String localMaxValueString = valueToString(localMaxValue); + LOG_ERROR("PODIntervalTree verification failed at node 0x%p: localMaxValue=%s and data=%s", + node, localMaxValueString.utf8().data(), node->data().toString().utf8().data()); +#endif + return false; + } + if (currentMaxValue) + *currentMaxValue = localMaxValue; + return true; + } +}; + +#ifndef NDEBUG +// Support for printing PODIntervals at the PODRedBlackTree level. +template<class T, class UserData> +String valueToString(const PODInterval<T, UserData>& interval) +{ + return interval.toString(); +} +#endif + +} // namespace WebCore + +#endif // PODIntervalTree_h diff --git a/WebCore/platform/graphics/gpu/PODRedBlackTree.h b/WebCore/platform/graphics/gpu/PODRedBlackTree.h new file mode 100644 index 0000000..9b02037 --- /dev/null +++ b/WebCore/platform/graphics/gpu/PODRedBlackTree.h @@ -0,0 +1,750 @@ +/* + * 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: + * + * 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 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. + */ + +// A red-black tree, which is a form of a balanced binary tree. It +// supports efficient insertion, deletion and queries of comparable +// elements. The same element may be inserted multiple times. The +// algorithmic complexity of common operations is: +// +// Insertion: O(lg(n)) +// Deletion: O(lg(n)) +// Querying: O(lg(n)) +// +// The data type T that is stored in this red-black tree must be only +// Plain Old Data (POD), or bottom out into POD. It must _not_ rely on +// having its destructor called. This implementation internally +// allocates storage in large chunks and does not call the destructor +// on each object. +// +// Type T must supply a default constructor, a copy constructor, and +// the "<" and "==" operators. +// +// In debug mode, printing of the data contained in the tree is +// enabled. This requires the following function to be available: +// +// String valueToString(const T&); +// +// Note that when complex types are stored in this red/black tree, it +// is possible that single invocations of the "<" and "==" operators +// will be insufficient to describe the ordering of elements in the +// tree during queries. As a concrete example, consider the case where +// intervals are stored in the tree sorted by low endpoint. The "<" +// operator on the Interval class only compares the low endpoint, but +// the "==" operator takes into account the high endpoint as well. +// This makes the necessary logic for querying and deletion somewhat +// more complex. In order to properly handle such situations, the +// property "needsFullOrderingComparisons" must be set to true on +// the tree. +// +// This red-black tree is designed to be _augmented_; subclasses can +// add additional and summary information to each node to efficiently +// store and index more complex data structures. A concrete example is +// the IntervalTree, which extends each node with a summary statistic +// to efficiently store one-dimensional intervals. +// +// The design of this red-black tree comes from Cormen, Leiserson, +// and Rivest, _Introduction to Algorithms_, MIT Press, 1990. + +#ifndef PODRedBlackTree_h +#define PODRedBlackTree_h + +#include "PODArena.h" +#include <wtf/Assertions.h> +#include <wtf/Noncopyable.h> +#include <wtf/RefPtr.h> +#ifndef NDEBUG +#include "Logging.h" +#include "PlatformString.h" +#include "StringBuilder.h" +#include <wtf/text/CString.h> +#endif + +namespace WebCore { + +template<class T> +class PODRedBlackTree { +public: + // Visitor interface for walking all of the tree's elements. + class Visitor { + public: + virtual void visit(const T& data) = 0; + protected: + virtual ~Visitor() { } + }; + + // Constructs a new red-black tree, allocating temporary objects + // from a newly constructed PODArena. + PODRedBlackTree() + : m_arena(PODArena::create()) + , m_root(0) + , m_needsFullOrderingComparisons(false) +#ifndef NDEBUG + , m_verboseDebugging(false) +#endif + { + } + + // Constructs a new red-black tree, allocating temporary objects + // from the given PODArena. + explicit PODRedBlackTree(PassRefPtr<PODArena> arena) + : m_arena(arena) + , m_root(0) + , m_needsFullOrderingComparisons(false) +#ifndef NDEBUG + , m_verboseDebugging(false) +#endif + { + } + + virtual ~PODRedBlackTree() { } + + void add(const T& data) + { + Node* node = m_arena->allocateObject<Node, T>(data); + insertNode(node); + } + + // Returns true if the datum was found in the tree. + bool remove(const T& data) + { + Node* node = treeSearch(data); + if (node) { + deleteNode(node); + return true; + } + return false; + } + + bool contains(const T& data) const { return treeSearch(data); } + + void visitInorder(Visitor* visitor) const + { + if (!m_root) + return; + visitInorderImpl(m_root, visitor); + } + + int size() const + { + Counter counter; + visitInorder(&counter); + return counter.count(); + } + + // See the class documentation for an explanation of this property. + void setNeedsFullOrderingComparisons(bool needsFullOrderingComparisons) + { + m_needsFullOrderingComparisons = needsFullOrderingComparisons; + } + + virtual bool checkInvariants() const + { + int blackCount; + return checkInvariantsFromNode(m_root, &blackCount); + } + +#ifndef NDEBUG + // Dumps the tree's contents to the logging info stream for + // debugging purposes. + void dump() const + { + dumpFromNode(m_root, 0); + } + + // Turns on or off verbose debugging of the tree, causing many + // messages to be logged during insertion and other operations in + // debug mode. + void setVerboseDebugging(bool verboseDebugging) + { + m_verboseDebugging = verboseDebugging; + } +#endif + +protected: + enum Color { + Red = 1, + Black + }; + + // The base Node class which is stored in the tree. Nodes are only + // an internal concept; users of the tree deal only with the data + // they store in it. + class Node : public Noncopyable { + public: + // Constructor. Newly-created nodes are colored red. + explicit Node(const T& data) + : m_left(0) + , m_right(0) + , m_parent(0) + , m_color(Red) + , m_data(data) + { + } + + virtual ~Node() { } + + Color color() const { return m_color; } + void setColor(Color color) { m_color = color; } + + // Fetches the user data. + T& data() { return m_data; } + + // Copies all user-level fields from the source node, but not + // internal fields. For example, the base implementation of this + // method copies the "m_data" field, but not the child or parent + // fields. Any augmentation information also does not need to be + // copied, as it will be recomputed. Subclasses must call the + // superclass implementation. + virtual void copyFrom(Node* src) { m_data = src->data(); } + + Node* left() const { return m_left; } + void setLeft(Node* node) { m_left = node; } + + Node* right() const { return m_right; } + void setRight(Node* node) { m_right = node; } + + Node* parent() const { return m_parent; } + void setParent(Node* node) { m_parent = node; } + + private: + Node* m_left; + Node* m_right; + Node* m_parent; + Color m_color; + T m_data; + }; + + // Returns the root of the tree, which is needed by some subclasses. + Node* root() const { return m_root; } + +private: + // This virtual method is the hook that subclasses should use when + // augmenting the red-black tree with additional per-node summary + // information. For example, in the case of an interval tree, this + // is used to compute the maximum endpoint of the subtree below the + // given node based on the values in the left and right children. It + // is guaranteed that this will be called in the correct order to + // properly update such summary information based only on the values + // in the left and right children. This method should return true if + // the node's summary information changed. + virtual bool updateNode(Node* node) { return false; } + + //---------------------------------------------------------------------- + // Generic binary search tree operations + // + + // Searches the tree for the given datum. + Node* treeSearch(const T& data) const + { + if (m_needsFullOrderingComparisons) + return treeSearchFullComparisons(m_root, data); + + return treeSearchNormal(m_root, data); + } + + // Searches the tree using the normal comparison operations, + // suitable for simple data types such as numbers. + Node* treeSearchNormal(Node* current, const T& data) const + { + while (current) { + if (current->data() == data) + return current; + if (data < current->data()) + current = current->left(); + else + current = current->right(); + } + return 0; + } + + // Searches the tree using multiple comparison operations, required + // for data types with more complex behavior such as intervals. + Node* treeSearchFullComparisons(Node* current, const T& data) const + { + if (!current) + return 0; + if (data < current->data()) + return treeSearchFullComparisons(current->left(), data); + if (current->data() < data) + return treeSearchFullComparisons(current->right(), data); + if (data == current->data()) + return current; + + // We may need to traverse both the left and right subtrees. + Node* result = treeSearchFullComparisons(current->left(), data); + if (!result) + result = treeSearchFullComparisons(current->right(), data); + return result; + } + + void treeInsert(Node* z) + { + Node* y = 0; + Node* x = m_root; + while (x) { + y = x; + if (z->data() < x->data()) + x = x->left(); + else + x = x->right(); + } + z->setParent(y); + if (!y) + m_root = z; + else { + if (z->data() < y->data()) + y->setLeft(z); + else + y->setRight(z); + } + } + + // Finds the node following the given one in sequential ordering of + // their data, or null if none exists. + Node* treeSuccessor(Node* x) + { + if (x->right()) + return treeMinimum(x->right()); + Node* y = x->parent(); + while (y && x == y->right()) { + x = y; + y = y->parent(); + } + return y; + } + + // Finds the minimum element in the sub-tree rooted at the given + // node. + Node* treeMinimum(Node* x) + { + while (x->left()) + x = x->left(); + return x; + } + + // Helper for maintaining the augmented red-black tree. + void propagateUpdates(Node* start) + { + bool shouldContinue = true; + while (start && shouldContinue) { + shouldContinue = updateNode(start); + start = start->parent(); + } + } + + //---------------------------------------------------------------------- + // Red-Black tree operations + // + + // Left-rotates the subtree rooted at x. + // Returns the new root of the subtree (x's right child). + Node* leftRotate(Node* x) + { + // Set y. + Node* y = x->right(); + + // Turn y's left subtree into x's right subtree. + x->setRight(y->left()); + if (y->left()) + y->left()->setParent(x); + + // Link x's parent to y. + y->setParent(x->parent()); + if (!x->parent()) + m_root = y; + else { + if (x == x->parent()->left()) + x->parent()->setLeft(y); + else + x->parent()->setRight(y); + } + + // Put x on y's left. + y->setLeft(x); + x->setParent(y); + + // Update nodes lowest to highest. + updateNode(x); + updateNode(y); + return y; + } + + // Right-rotates the subtree rooted at y. + // Returns the new root of the subtree (y's left child). + Node* rightRotate(Node* y) + { + // Set x. + Node* x = y->left(); + + // Turn x's right subtree into y's left subtree. + y->setLeft(x->right()); + if (x->right()) + x->right()->setParent(y); + + // Link y's parent to x. + x->setParent(y->parent()); + if (!y->parent()) + m_root = x; + else { + if (y == y->parent()->left()) + y->parent()->setLeft(x); + else + y->parent()->setRight(x); + } + + // Put y on x's right. + x->setRight(y); + y->setParent(x); + + // Update nodes lowest to highest. + updateNode(y); + updateNode(x); + return x; + } + + // Inserts the given node into the tree. + void insertNode(Node* x) + { + treeInsert(x); + x->setColor(Red); + updateNode(x); + + logIfVerbose(" PODRedBlackTree::InsertNode"); + + // The node from which to start propagating updates upwards. + Node* updateStart = x->parent(); + + while (x != m_root && x->parent()->color() == Red) { + if (x->parent() == x->parent()->parent()->left()) { + Node* y = x->parent()->parent()->right(); + if (y && y->color() == Red) { + // Case 1 + logIfVerbose(" Case 1/1"); + x->parent()->setColor(Black); + y->setColor(Black); + x->parent()->parent()->setColor(Red); + updateNode(x->parent()); + x = x->parent()->parent(); + updateNode(x); + updateStart = x->parent(); + } else { + if (x == x->parent()->right()) { + logIfVerbose(" Case 1/2"); + // Case 2 + x = x->parent(); + leftRotate(x); + } + // Case 3 + logIfVerbose(" Case 1/3"); + x->parent()->setColor(Black); + x->parent()->parent()->setColor(Red); + Node* newSubTreeRoot = rightRotate(x->parent()->parent()); + updateStart = newSubTreeRoot->parent(); + } + } else { + // Same as "then" clause with "right" and "left" exchanged. + Node* y = x->parent()->parent()->left(); + if (y && y->color() == Red) { + // Case 1 + logIfVerbose(" Case 2/1"); + x->parent()->setColor(Black); + y->setColor(Black); + x->parent()->parent()->setColor(Red); + updateNode(x->parent()); + x = x->parent()->parent(); + updateNode(x); + updateStart = x->parent(); + } else { + if (x == x->parent()->left()) { + // Case 2 + logIfVerbose(" Case 2/2"); + x = x->parent(); + rightRotate(x); + } + // Case 3 + logIfVerbose(" Case 2/3"); + x->parent()->setColor(Black); + x->parent()->parent()->setColor(Red); + Node* newSubTreeRoot = leftRotate(x->parent()->parent()); + updateStart = newSubTreeRoot->parent(); + } + } + } + + propagateUpdates(updateStart); + + m_root->setColor(Black); + } + + // Restores the red-black property to the tree after splicing out + // a node. Note that x may be null, which is why xParent must be + // supplied. + void deleteFixup(Node* x, Node* xParent) + { + while (x != m_root && (!x || x->color() == Black)) { + if (x == xParent->left()) { + // Note: the text points out that w can not be null. + // The reason is not obvious from simply looking at + // the code; it comes about from the properties of the + // red-black tree. + Node* w = xParent->right(); + ASSERT(w); // x's sibling should not be null. + if (w->color() == Red) { + // Case 1 + w->setColor(Black); + xParent->setColor(Red); + leftRotate(xParent); + w = xParent->right(); + } + if ((!w->left() || w->left()->color() == Black) + && (!w->right() || w->right()->color() == Black)) { + // Case 2 + w->setColor(Red); + x = xParent; + xParent = x->parent(); + } else { + if (!w->right() || w->right()->color() == Black) { + // Case 3 + w->left()->setColor(Black); + w->setColor(Red); + rightRotate(w); + w = xParent->right(); + } + // Case 4 + w->setColor(xParent->color()); + xParent->setColor(Black); + if (w->right()) + w->right()->setColor(Black); + leftRotate(xParent); + x = m_root; + xParent = x->parent(); + } + } else { + // Same as "then" clause with "right" and "left" + // exchanged. + + // Note: the text points out that w can not be null. + // The reason is not obvious from simply looking at + // the code; it comes about from the properties of the + // red-black tree. + Node* w = xParent->left(); + ASSERT(w); // x's sibling should not be null. + if (w->color() == Red) { + // Case 1 + w->setColor(Black); + xParent->setColor(Red); + rightRotate(xParent); + w = xParent->left(); + } + if ((!w->right() || w->right()->color() == Black) + && (!w->left() || w->left()->color() == Black)) { + // Case 2 + w->setColor(Red); + x = xParent; + xParent = x->parent(); + } else { + if (!w->left() || w->left()->color() == Black) { + // Case 3 + w->right()->setColor(Black); + w->setColor(Red); + leftRotate(w); + w = xParent->left(); + } + // Case 4 + w->setColor(xParent->color()); + xParent->setColor(Black); + if (w->left()) + w->left()->setColor(Black); + rightRotate(xParent); + x = m_root; + xParent = x->parent(); + } + } + } + if (x) + x->setColor(Black); + } + + // Deletes the given node from the tree. Note that this + // particular node may not actually be removed from the tree; + // instead, another node might be removed and its contents + // copied into z. + void deleteNode(Node* z) + { + // Y is the node to be unlinked from the tree. + Node* y; + if (!z->left() || !z->right()) + y = z; + else + y = treeSuccessor(z); + + // Y is guaranteed to be non-null at this point. + Node* x; + if (y->left()) + x = y->left(); + else + x = y->right(); + + // X is the child of y which might potentially replace y in + // the tree. X might be null at this point. + Node* xParent; + if (x) { + x->setParent(y->parent()); + xParent = x->parent(); + } else + xParent = y->parent(); + if (!y->parent()) + m_root = x; + else { + if (y == y->parent()->left()) + y->parent()->setLeft(x); + else + y->parent()->setRight(x); + } + if (y != z) { + z->copyFrom(y); + // This node has changed location in the tree and must be updated. + updateNode(z); + // The parent and its parents may now be out of date. + propagateUpdates(z->parent()); + } + + // If we haven't already updated starting from xParent, do so now. + if (xParent && xParent != y && xParent != z) + propagateUpdates(xParent); + if (y->color() == Black) + deleteFixup(x, xParent); + } + + // Visits the subtree rooted at the given node in order. + void visitInorderImpl(Node* node, Visitor* visitor) const + { + if (node->left()) + visitInorderImpl(node->left(), visitor); + visitor->visit(node->data()); + if (node->right()) + visitInorderImpl(node->right(), visitor); + } + + //---------------------------------------------------------------------- + // Helper class for size() + + // A Visitor which simply counts the number of visited elements. + class Counter : public Visitor, public Noncopyable { + public: + Counter() + : m_count(0) { } + + virtual void visit(const T& data) { ++m_count; } + int count() const { return m_count; } + + private: + int m_count; + }; + + //---------------------------------------------------------------------- + // Verification and debugging routines + // + + // Returns in the "blackCount" parameter the number of black + // children along all paths to all leaves of the given node. + bool checkInvariantsFromNode(Node* node, int* blackCount) const + { + // Base case is a leaf node. + if (!node) { + *blackCount = 1; + return true; + } + + // Each node is either red or black. + if (!(node->color() == Red || node->color() == Black)) + return false; + + // Every leaf (or null) is black. + + if (node->color() == Red) { + // Both of its children are black. + if (!((!node->left() || node->left()->color() == Black))) + return false; + if (!((!node->right() || node->right()->color() == Black))) + return false; + } + + // Every simple path to a leaf node contains the same number of + // black nodes. + int leftCount = 0, rightCount = 0; + bool leftValid = checkInvariantsFromNode(node->left(), &leftCount); + bool rightValid = checkInvariantsFromNode(node->right(), &rightCount); + if (!leftValid || !rightValid) + return false; + *blackCount = leftCount + (node->color() == Black ? 1 : 0); + return leftCount == rightCount; + } + +#ifdef NDEBUG + void logIfVerbose(const char* output) const { } +#else + void logIfVerbose(const char* output) const + { + if (m_verboseDebugging) + LOG_ERROR("%s", output); + } +#endif + +#ifndef NDEBUG + // Dumps the subtree rooted at the given node. + void dumpFromNode(Node* node, int indentation) const + { + StringBuilder builder; + for (int i = 0; i < indentation; i++) + builder.append(" "); + builder.append("-"); + if (node) { + builder.append(" "); + builder.append(valueToString(node->data())); + builder.append((node->color() == Black) ? " (black)" : " (red)"); + } + LOG_ERROR("%s", builder.toString().ascii().data()); + if (node) { + dumpFromNode(node->left(), indentation + 2); + dumpFromNode(node->right(), indentation + 2); + } + } +#endif + + //---------------------------------------------------------------------- + // Data members + + RefPtr<PODArena> m_arena; + Node* m_root; + bool m_needsFullOrderingComparisons; +#ifndef NDEBUG + bool m_verboseDebugging; +#endif +}; + +} // namespace WebCore + +#endif // PODRedBlackTree_h diff --git a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp new file mode 100644 index 0000000..6424293 --- /dev/null +++ b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp @@ -0,0 +1,296 @@ +/* + * 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" + +#include "SharedGraphicsContext3D.h" + +#include "AffineTransform.h" +#include "Color.h" +#include "FloatRect.h" +#include "GraphicsContext3D.h" +#include "GraphicsTypes.h" +#include "IntSize.h" +#include "SolidFillShader.h" +#include "TexShader.h" + +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +// static +PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(PassOwnPtr<GraphicsContext3D> context) +{ + return adoptRef(new SharedGraphicsContext3D(context)); +} + +SharedGraphicsContext3D::SharedGraphicsContext3D(PassOwnPtr<GraphicsContext3D> context) + : m_context(context) + , m_quadVertices(0) + , m_solidFillShader(SolidFillShader::create(m_context.get())) + , m_texShader(TexShader::create(m_context.get())) +{ +} + +SharedGraphicsContext3D::~SharedGraphicsContext3D() +{ + m_context->deleteBuffer(m_quadVertices); +} + +void SharedGraphicsContext3D::makeContextCurrent() +{ + m_context->makeContextCurrent(); +} + +void SharedGraphicsContext3D::scissor(const FloatRect& rect) +{ + m_context->scissor(rect.x(), rect.y(), rect.width(), rect.height()); +} + +void SharedGraphicsContext3D::enable(unsigned capacity) +{ + m_context->enable(capacity); +} + +void SharedGraphicsContext3D::disable(unsigned capacity) +{ + m_context->disable(capacity); +} + +void SharedGraphicsContext3D::clearColor(const Color& color) +{ + float rgba[4]; + color.getRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); + m_context->clearColor(rgba[0], rgba[1], rgba[2], rgba[3]); +} + +void SharedGraphicsContext3D::clear(unsigned mask) +{ + m_context->clear(mask); +} + +void SharedGraphicsContext3D::drawArrays(unsigned long mode, long first, long count) +{ + m_context->drawArrays(mode, first, count); +} + +unsigned long SharedGraphicsContext3D::getError() +{ + return m_context->getError(); +} + +void SharedGraphicsContext3D::getIntegerv(unsigned long pname, int* value) +{ + m_context->getIntegerv(pname, value); +} + +unsigned SharedGraphicsContext3D::createFramebuffer() +{ + return m_context->createFramebuffer(); +} + +unsigned SharedGraphicsContext3D::createTexture() +{ + return m_context->createTexture(); +} + +void SharedGraphicsContext3D::deleteFramebuffer(unsigned framebuffer) +{ + m_context->deleteFramebuffer(framebuffer); +} + +void SharedGraphicsContext3D::deleteTexture(unsigned texture) +{ + m_context->deleteTexture(texture); +} + +void SharedGraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, unsigned texture, long level) +{ + m_context->framebufferTexture2D(target, attachment, textarget, texture, level); +} + +void SharedGraphicsContext3D::texParameteri(unsigned target, unsigned pname, int param) +{ + m_context->texParameteri(target, pname, param); +} + +int SharedGraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels) +{ + return m_context->texImage2D(target, level, internalformat, width, height, border, format, type, pixels); +} + +int SharedGraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, unsigned format, unsigned type, void* pixels) +{ + return m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); +} + +void SharedGraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* data) +{ + m_context->readPixels(x, y, width, height, format, type, data); +} + +bool SharedGraphicsContext3D::supportsBGRA() +{ + return m_context->supportsBGRA(); +} + +Texture* SharedGraphicsContext3D::createTexture(NativeImagePtr ptr, Texture::Format format, int width, int height) +{ + RefPtr<Texture> texture = m_textures.get(ptr); + if (texture) + return texture.get(); + + texture = Texture::create(m_context.get(), format, width, height); + Texture* t = texture.get(); + m_textures.set(ptr, texture); + return t; +} + +Texture* SharedGraphicsContext3D::getTexture(NativeImagePtr ptr) +{ + RefPtr<Texture> texture = m_textures.get(ptr); + return texture ? texture.get() : 0; +} + +PassRefPtr<Texture> SharedGraphicsContext3D::createTexture(Texture::Format format, int width, int height) +{ + return Texture::create(m_context.get(), format, width, height); +} + +void SharedGraphicsContext3D::applyCompositeOperator(CompositeOperator op) +{ + switch (op) { + case CompositeClear: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::ZERO); + break; + case CompositeCopy: + m_context->disable(GraphicsContext3D::BLEND); + break; + case CompositeSourceOver: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); + break; + case CompositeSourceIn: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::DST_ALPHA, GraphicsContext3D::ZERO); + break; + case CompositeSourceOut: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ZERO); + break; + case CompositeSourceAtop: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::DST_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); + break; + case CompositeDestinationOver: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ONE); + break; + case CompositeDestinationIn: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::SRC_ALPHA); + break; + case CompositeDestinationOut: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); + break; + case CompositeDestinationAtop: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::SRC_ALPHA); + break; + case CompositeXOR: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ONE_MINUS_DST_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); + break; + case CompositePlusDarker: + case CompositeHighlight: + // unsupported + m_context->disable(GraphicsContext3D::BLEND); + break; + case CompositePlusLighter: + m_context->enable(GraphicsContext3D::BLEND); + m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE); + break; + } +} + +void SharedGraphicsContext3D::useQuadVertices() +{ + if (!m_quadVertices) { + float vertices[] = { 0.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 1.0f, + 0.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f }; + m_quadVertices = m_context->createBuffer(); + m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices); + m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, sizeof(vertices), vertices, GraphicsContext3D::STATIC_DRAW); + } else { + m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_quadVertices); + } +} + +void SharedGraphicsContext3D::setActiveTexture(unsigned textureUnit) +{ + m_context->activeTexture(textureUnit); +} + +void SharedGraphicsContext3D::bindTexture(unsigned target, unsigned texture) +{ + m_context->bindTexture(target, texture); +} + +void SharedGraphicsContext3D::useFillSolidProgram(const AffineTransform& transform, const Color& color) +{ + m_solidFillShader->use(transform, color); +} + +void SharedGraphicsContext3D::useTextureProgram(const AffineTransform& transform, const AffineTransform& texTransform, float alpha) +{ + m_texShader->use(transform, texTransform, 0, alpha); +} + +void SharedGraphicsContext3D::bindFramebuffer(unsigned framebuffer) +{ + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, framebuffer); +} + +void SharedGraphicsContext3D::setViewport(const IntSize& size) +{ + m_context->viewport(0, 0, size.width(), size.height()); +} + +bool SharedGraphicsContext3D::paintsIntoCanvasBuffer() const +{ + return m_context->paintsIntoCanvasBuffer(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h new file mode 100644 index 0000000..1baa0f6 --- /dev/null +++ b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h @@ -0,0 +1,124 @@ +/* + * 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 SharedGraphicsContext3D_h +#define SharedGraphicsContext3D_h + +#include "GraphicsTypes.h" +#include "ImageSource.h" +#include "Texture.h" + +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class AffineTransform; +class Color; +class GraphicsContext3D; +class FloatRect; +class IntSize; +class SolidFillShader; +class TexShader; + +typedef HashMap<NativeImagePtr, RefPtr<Texture> > TextureHashMap; + +class SharedGraphicsContext3D : public RefCounted<SharedGraphicsContext3D> { +public: + static PassRefPtr<SharedGraphicsContext3D> create(PassOwnPtr<GraphicsContext3D>); + ~SharedGraphicsContext3D(); + + // Functions that delegate directly to GraphicsContext3D, with caching + void makeContextCurrent(); + void bindFramebuffer(unsigned framebuffer); + void setViewport(const IntSize&); + void scissor(const FloatRect&); + void enable(unsigned capacity); + void disable(unsigned capacity); + void clearColor(const Color&); + void clear(unsigned mask); + void drawArrays(unsigned long mode, long first, long count); + unsigned long getError(); + void getIntegerv(unsigned long pname, int* value); + + unsigned createFramebuffer(); + unsigned createTexture(); + + void deleteFramebuffer(unsigned framebuffer); + void deleteTexture(unsigned texture); + + void framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, unsigned, long level); + void texParameteri(unsigned target, unsigned pname, int param); + int texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, unsigned format, unsigned type, void* pixels); + + void readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* data); + + bool paintsIntoCanvasBuffer() const; + + // Shared logic for canvas 2d + void applyCompositeOperator(CompositeOperator); + void useQuadVertices(); + + void useFillSolidProgram(const AffineTransform&, const Color&); + void useTextureProgram(const AffineTransform&, const AffineTransform&, float alpha); + + void setActiveTexture(unsigned textureUnit); + void bindTexture(unsigned target, unsigned texture); + + bool supportsBGRA(); + + // Creates a texture associated with the given image. Is owned by this context's + // TextureHashMap. + Texture* createTexture(NativeImagePtr, Texture::Format, int width, int height); + Texture* getTexture(NativeImagePtr); + + // Creates a texture that is not associated with any image. The caller takes ownership of + // the texture. + PassRefPtr<Texture> createTexture(Texture::Format, int width, int height); + +private: + SharedGraphicsContext3D(PassOwnPtr<GraphicsContext3D> context); + + OwnPtr<GraphicsContext3D> m_context; + + unsigned m_quadVertices; + + OwnPtr<SolidFillShader> m_solidFillShader; + OwnPtr<TexShader> m_texShader; + + TextureHashMap m_textures; +}; + +} // namespace WebCore + +#endif // SharedGraphicsContext3D_h diff --git a/WebCore/platform/graphics/gpu/Texture.cpp b/WebCore/platform/graphics/gpu/Texture.cpp index 557603c..95436ba 100644 --- a/WebCore/platform/graphics/gpu/Texture.cpp +++ b/WebCore/platform/graphics/gpu/Texture.cpp @@ -32,10 +32,15 @@ #include "Texture.h" +#include "FloatRect.h" #include "GraphicsContext3D.h" #include "IntRect.h" + +#include <algorithm> #include <wtf/OwnArrayPtr.h> +using namespace std; + namespace WebCore { @@ -81,7 +86,6 @@ PassRefPtr<Texture> Texture::create(GraphicsContext3D* context, Format format, i { int maxTextureSize = 0; context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize); - TilingData tiling(maxTextureSize, width, height, true); int numTiles = tiling.numTiles(); @@ -120,15 +124,18 @@ static uint32_t* copySubRect(uint32_t* src, int srcX, int srcY, uint32_t* dst, i if (!swizzle && width == srcStride) return srcOffset; - uint32_t* dstPixel = dst; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width ; x++) { - uint32_t pixel = srcOffset[x + y * srcStride]; - if (swizzle) + if (swizzle) { + uint32_t* dstPixel = dst; + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width ; ++x) { + uint32_t pixel = srcOffset[x + y * srcStride]; *dstPixel = pixel & 0xFF00FF00 | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16); - else - *dstPixel = pixel; - dstPixel++; + dstPixel++; + } + } + } else { + for (int y = 0; y < height; ++y) { + memcpy(dst + y * width, srcOffset + y * srcStride, 4 * width); } } return dst; @@ -136,6 +143,11 @@ static uint32_t* copySubRect(uint32_t* src, int srcX, int srcY, uint32_t* dst, i void Texture::load(void* pixels) { + updateSubRect(pixels, IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY())); +} + +void Texture::updateSubRect(void* pixels, const IntRect updateRect) +{ uint32_t* pixels32 = static_cast<uint32_t*>(pixels); unsigned int glFormat = 0; unsigned int glType = 0; @@ -145,26 +157,42 @@ void Texture::load(void* pixels) ASSERT(glFormat == GraphicsContext3D::RGBA && glType == GraphicsContext3D::UNSIGNED_BYTE); // FIXME: This could use PBO's to save doing an extra copy here. } - OwnArrayPtr<uint32_t> tempBuff(new uint32_t[m_tiles.maxTextureSize() * m_tiles.maxTextureSize()]); + int tempBuffSize = // Temporary buffer size is the smaller of the max texture size or the updateRect + min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRect.width()) * + min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRect.height()); + OwnArrayPtr<uint32_t> tempBuff(new uint32_t[tempBuffSize]); + + for (int tile = 0; tile < m_tiles.numTiles(); tile++) { + // Intersect with tile + IntRect tileBoundsWithBorder = m_tiles.tileBoundsWithBorder(tile); - for (int i = 0; i < m_tiles.numTiles(); i++) { - IntRect tileBoundsWithBorder = m_tiles.tileBoundsWithBorder(i); + IntRect updateRectIntersected = updateRect; + updateRectIntersected.intersect(tileBoundsWithBorder); + IntRect dstRect = updateRectIntersected; + dstRect.move(-tileBoundsWithBorder.x(), -tileBoundsWithBorder.y()); + + if (updateRectIntersected.isEmpty()) + continue; + + // Copy sub rectangle out of larger pixel data uint32_t* uploadBuff = 0; if (swizzle) { uploadBuff = copySubRect<true>( - pixels32, tileBoundsWithBorder.x(), tileBoundsWithBorder.y(), - tempBuff.get(), tileBoundsWithBorder.width(), tileBoundsWithBorder.height(), m_tiles.totalSizeX()); + pixels32, updateRectIntersected.x(), updateRectIntersected.y(), + tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSizeX()); } else { uploadBuff = copySubRect<false>( - pixels32, tileBoundsWithBorder.x(), tileBoundsWithBorder.y(), - tempBuff.get(), tileBoundsWithBorder.width(), tileBoundsWithBorder.height(), m_tiles.totalSizeX()); + pixels32, updateRectIntersected.x(), updateRectIntersected.y(), + tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSizeX()); } - m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(i)); - m_context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, - tileBoundsWithBorder.width(), - tileBoundsWithBorder.height(), glFormat, glType, uploadBuff); + m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(tile)); + m_context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0 /* level */, + dstRect.x(), + dstRect.y(), + updateRectIntersected.width(), + updateRectIntersected.height(), glFormat, glType, uploadBuff); } } diff --git a/WebCore/platform/graphics/gpu/Texture.h b/WebCore/platform/graphics/gpu/Texture.h index 7e4a72b..eda475e 100644 --- a/WebCore/platform/graphics/gpu/Texture.h +++ b/WebCore/platform/graphics/gpu/Texture.h @@ -41,6 +41,8 @@ namespace WebCore { class GraphicsContext3D; +class IntRect; + class Texture : public RefCounted<Texture> { public: ~Texture(); @@ -48,6 +50,7 @@ public: static PassRefPtr<Texture> create(GraphicsContext3D*, Format, int width, int height); void bindTile(int tile); void load(void* pixels); + void updateSubRect(void* pixels, const IntRect); Format format() const { return m_format; } const TilingData& tiles() const { return m_tiles; } private: diff --git a/WebCore/platform/graphics/gpu/TilingData.h b/WebCore/platform/graphics/gpu/TilingData.h index f12e66e..1bdc51a 100644 --- a/WebCore/platform/graphics/gpu/TilingData.h +++ b/WebCore/platform/graphics/gpu/TilingData.h @@ -44,6 +44,7 @@ public: int maxTextureSize() const { return m_maxTextureSize; } int totalSizeX() const { return m_totalSizeX; } int totalSizeY() const { return m_totalSizeY; } + int borderTexels() const { return m_borderTexels; } int numTiles() const { return numTilesX() * numTilesY(); } int numTilesX() const { return m_numTilesX; } diff --git a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp index 567da74..63555bf 100644 --- a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp @@ -18,6 +18,7 @@ #include "config.h" #include "DataSourceGStreamer.h" +#if ENABLE(VIDEO) #include <gio/gio.h> #include <glib.h> @@ -241,3 +242,5 @@ static void webkit_data_src_uri_handler_init(gpointer g_iface, gpointer iface_da iface->get_uri = webkit_data_src_uri_get_uri; iface->set_uri = webkit_data_src_uri_set_uri; } + +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h index 38f69b1..453685a 100644 --- a/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h @@ -19,6 +19,8 @@ #ifndef DataSourceGStreamer_h #define DataSourceGStreamer_h +#if ENABLE(VIDEO) + #include <glib-object.h> #include <gst/base/gstbasesrc.h> @@ -51,4 +53,5 @@ GType webkit_data_src_get_type(void); G_END_DECLS +#endif // ENABLE(VIDEO) #endif diff --git a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp index 75bf5e7..6333437 100644 --- a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp @@ -32,4 +32,4 @@ template <> void freeOwnedGPtr<GstElement>(GstElement* ptr) } } -#endif +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h index 6655f38..84a3e30 100644 --- a/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h @@ -19,6 +19,7 @@ #ifndef GOwnPtrGStreamer_h #define GOwnPtrGStreamer_h +#if ENABLE(VIDEO) #include "GOwnPtr.h" @@ -30,4 +31,5 @@ template<> void freeOwnedGPtr<GstElement>(GstElement* ptr); } +#endif // ENABLE(VIDEO) #endif diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp index e1efdd4..2ff4f38 100644 --- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp +++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp @@ -18,11 +18,10 @@ */ #include "config.h" - #include "GStreamerGWorld.h" +#if ENABLE(VIDEO) #include "GOwnPtrGStreamer.h" - #include <gst/gst.h> #include <gst/interfaces/xoverlay.h> @@ -200,3 +199,4 @@ void GStreamerGWorld::setWindowOverlay(GstMessage* message) } } +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h index 659052a..282f13c 100644 --- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h +++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.h @@ -20,7 +20,6 @@ #ifndef GStreamerGWorld_h #define GStreamerGWorld_h - #if ENABLE(VIDEO) #include "PlatformVideoWindow.h" @@ -63,5 +62,5 @@ private: }; } -#endif +#endif // ENABLE(VIDEO) #endif diff --git a/WebCore/platform/graphics/gstreamer/ImageGStreamer.h b/WebCore/platform/graphics/gstreamer/ImageGStreamer.h index 9288df9..4a4ff2b 100644 --- a/WebCore/platform/graphics/gstreamer/ImageGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/ImageGStreamer.h @@ -23,7 +23,6 @@ #if ENABLE(VIDEO) #include "BitmapImage.h" - #include <gst/gst.h> #include <gst/video/video.h> #include <wtf/PassRefPtr.h> @@ -60,6 +59,5 @@ class ImageGStreamer : public RefCounted<ImageGStreamer> { }; } -#endif - +#endif // ENABLE(VIDEO) #endif diff --git a/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm b/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm index 421b90f..076df4a 100644 --- a/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm +++ b/WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm @@ -19,6 +19,7 @@ #include "config.h" #include "ImageGStreamer.h" +#if ENABLE(VIDEO) using namespace WebCore; @@ -55,3 +56,5 @@ ImageGStreamer::~ImageGStreamer() m_image = 0; } + +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp b/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp index aeaee19..2fed892 100644 --- a/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp +++ b/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp @@ -18,12 +18,13 @@ */ #include "config.h" +#include "ImageGStreamer.h" + +#if ENABLE(VIDEO) #include "GOwnPtr.h" -#include "ImageGStreamer.h" using namespace std; - using namespace WebCore; PassRefPtr<ImageGStreamer> ImageGStreamer::createImage(GstBuffer* buffer) @@ -64,3 +65,4 @@ ImageGStreamer::~ImageGStreamer() m_image = 0; } +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index 5628eb3..4791b4c 100644 --- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -22,11 +22,8 @@ */ #include "config.h" - -#if ENABLE(VIDEO) - #include "MediaPlayerPrivateGStreamer.h" - +#if ENABLE(VIDEO) #include "ColorSpace.h" #include "DataSourceGStreamer.h" @@ -49,14 +46,13 @@ #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/video/video.h> #include <limits> #include <math.h> +#include <wtf/text/CString.h> // GstPlayFlags flags from playbin2. It is the policy of GStreamer to // not publicly expose element-specific enums. That's why this @@ -843,8 +839,12 @@ void MediaPlayerPrivateGStreamer::updateStates() // Try to figure out ready and network states. if (state == GST_STATE_READY) { - m_readyState = MediaPlayer::HaveNothing; + m_readyState = MediaPlayer::HaveMetadata; m_networkState = MediaPlayer::Empty; + // Cache the duration without emiting the durationchange + // event because it's taken care of by the media element + // in this precise case. + cacheDuration(); } else if (maxTimeLoaded() == duration()) { m_networkState = MediaPlayer::Loaded; m_readyState = MediaPlayer::HaveEnoughData; @@ -880,13 +880,6 @@ void MediaPlayerPrivateGStreamer::updateStates() m_readyState = MediaPlayer::HaveEnoughData; m_paused = false; - if (!m_mediaDuration) { - float newDuration = duration(); - m_mediaDurationKnown = !isinf(newDuration); - if (m_mediaDurationKnown) - m_mediaDuration = newDuration; - } - if (m_buffering) { m_readyState = MediaPlayer::HaveCurrentData; m_networkState = MediaPlayer::Loading; @@ -1119,7 +1112,7 @@ void MediaPlayerPrivateGStreamer::didEnd() timeChanged(); } -void MediaPlayerPrivateGStreamer::durationChanged() +void MediaPlayerPrivateGStreamer::cacheDuration() { // Reset cached media duration m_mediaDuration = 0; @@ -1143,8 +1136,16 @@ void MediaPlayerPrivateGStreamer::durationChanged() if (!isinf(newDuration)) m_mediaDuration = newDuration; +} - m_player->durationChanged(); +void MediaPlayerPrivateGStreamer::durationChanged() +{ + float previousDuration = m_mediaDuration; + + cacheDuration(); + + if (m_mediaDuration != previousDuration) + m_player->durationChanged(); } bool MediaPlayerPrivateGStreamer::supportsMuting() const @@ -1266,6 +1267,7 @@ static HashSet<String> mimeTypeCache() if (g_str_equal(name, "audio/x-vorbis")) { cache.add(String("audio/ogg")); + cache.add(String("audio/x-vorbis+ogg")); cached = true; } @@ -1460,4 +1462,4 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin() } -#endif +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h index f2f684b..6d1392d 100644 --- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h @@ -22,7 +22,6 @@ #ifndef MediaPlayerPrivateGStreamer_h #define MediaPlayerPrivateGStreamer_h - #if ENABLE(VIDEO) #include <wtf/Forward.h> @@ -132,6 +131,7 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); static bool isAvailable(); + void cacheDuration(); void updateStates(); void cancelSeek(); void endPointTimerFired(Timer<MediaPlayerPrivateGStreamer>*); @@ -179,5 +179,5 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface { }; } -#endif +#endif // ENABLE(VIDEO) #endif diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h index 8d99f05..3c4904b 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h @@ -19,7 +19,6 @@ #ifndef PlatformVideoWindow_h #define PlatformVideoWindow_h - #if ENABLE(VIDEO) #include "Widget.h" @@ -45,6 +44,5 @@ class PlatformVideoWindow : public RefCounted<PlatformVideoWindow> { }; } -#endif - +#endif // ENABLE(VIDEO) #endif diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp index 5c0e6ea..68ab7ac 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp @@ -19,6 +19,7 @@ #include "config.h" #include "PlatformVideoWindow.h" +#if ENABLE(VIDEO) #include "NotImplemented.h" @@ -33,3 +34,5 @@ PlatformVideoWindow::~PlatformVideoWindow() { notImplemented(); } + +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp index c5f835c..88b6552 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp @@ -19,8 +19,10 @@ #include "config.h" #include "PlatformVideoWindow.h" +#if ENABLE(VIDEO) #include <gtk/gtk.h> + #ifdef GDK_WINDOWING_X11 #include <gdk/gdkx.h> // for GDK_WINDOW_XID #endif @@ -59,3 +61,4 @@ PlatformVideoWindow::~PlatformVideoWindow() m_videoWindowId = 0; } +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp index dd8c3ee..00fef4b 100644 --- a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp @@ -28,6 +28,7 @@ #include "config.h" #include "VideoSinkGStreamer.h" +#if ENABLE(VIDEO) #include <glib.h> #include <gst/gst.h> @@ -370,3 +371,4 @@ webkit_video_sink_new(void) return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, 0); } +#endif // ENABLE(VIDEO) diff --git a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h index 4fb0b73..767e83f 100644 --- a/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h @@ -20,6 +20,8 @@ #ifndef VideoSinkGStreamer_h #define VideoSinkGStreamer_h +#if ENABLE(VIDEO) + #include <glib-object.h> #include <gst/video/gstvideosink.h> @@ -75,4 +77,5 @@ GstElement *webkit_video_sink_new(void); G_END_DECLS +#endif // ENABLE(VIDEO) #endif diff --git a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index 1059b59..bcd59c6 100644 --- a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -18,6 +18,7 @@ #include "config.h" #include "WebKitWebSourceGStreamer.h" +#if ENABLE(VIDEO) #include "Document.h" #include "GOwnPtr.h" @@ -790,3 +791,5 @@ void StreamingClient::cannotShowURL(ResourceHandle*) GST_ELEMENT_ERROR(m_src, RESOURCE, OPEN_READ, ("Can't show \"%s\"", m_src->priv->uri), (0)); } +#endif // ENABLE(VIDEO) + diff --git a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h index ae19640..1594062 100644 --- a/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h +++ b/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h @@ -18,6 +18,7 @@ #ifndef WebKitWebSourceGStreamer_h #define WebKitWebSourceGStreamer_h +#if ENABLE(VIDEO) #include "Frame.h" #include <gst/gst.h> @@ -49,4 +50,5 @@ void webKitWebSrcSetFrame(WebKitWebSrc* src, WebCore::Frame* frame); G_END_DECLS +#endif // ENABLE(VIDEO) #endif diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm index ab4ef4b..54b261c 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm @@ -31,7 +31,6 @@ #import "BlockExceptions.h" -#include "ANGLE/ResourceLimits.h" #include "ArrayBuffer.h" #include "ArrayBufferView.h" #include "WebGLObject.h" @@ -186,23 +185,23 @@ GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWi TBuiltInResource ANGLEResources; - ANGLEResources.maxVertexAttribs = 0; - getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.maxVertexAttribs); - ANGLEResources.maxVertexUniformVectors = 0; - getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.maxVertexUniformVectors); - ANGLEResources.maxVaryingVectors = 0; - getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.maxVaryingVectors); - ANGLEResources.maxVertexTextureImageUnits = 0; - getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.maxVertexTextureImageUnits); - ANGLEResources.maxCombinedTextureImageUnits = 0; - getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.maxCombinedTextureImageUnits); - ANGLEResources.maxTextureImageUnits = 0; - getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.maxTextureImageUnits); - ANGLEResources.maxFragmentUniformVectors = 0; - getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.maxFragmentUniformVectors); + ANGLEResources.MaxVertexAttribs = 0; + getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs); + ANGLEResources.MaxVertexUniformVectors = 0; + getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors); + ANGLEResources.MaxVaryingVectors = 0; + getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors); + ANGLEResources.MaxVertexTextureImageUnits = 0; + getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits); + ANGLEResources.MaxCombinedTextureImageUnits = 0; + getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits); + ANGLEResources.MaxTextureImageUnits = 0; + getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits); + ANGLEResources.MaxFragmentUniformVectors = 0; + getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors); // Always set to 1 for OpenGL ES. - ANGLEResources.maxDrawBuffers = 1; + ANGLEResources.MaxDrawBuffers = 1; m_compiler.setResources(ANGLEResources); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index 315cc00..5fedaff 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -272,16 +272,16 @@ static TransformationMatrix flipTransform() } #endif -static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& timingFunction) -{ - switch (timingFunction.type()) { - case LinearTimingFunction: - return [CAMediaTimingFunction functionWithName:@"linear"]; - case CubicBezierTimingFunction: - return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(timingFunction.x1()) :static_cast<float>(timingFunction.y1()) - :static_cast<float>(timingFunction.x2()) :static_cast<float>(timingFunction.y2())]; - } - return 0; +static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction* timingFunction) +{ + // By this point, timing functions can only be linear or cubic, not steps. + ASSERT(!timingFunction->isStepsTimingFunction()); + if (timingFunction->isCubicBezierTimingFunction()) { + const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); + return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(ctf->x1()) :static_cast<float>(ctf->y1()) + :static_cast<float>(ctf->x2()) :static_cast<float>(ctf->y2())]; + } else + return [CAMediaTimingFunction functionWithName:@"linear"]; } static void setLayerBorderColor(PlatformLayer* layer, const Color& color) @@ -356,6 +356,20 @@ static NSDictionary* nullActionsDictionary() return actions; } +static bool animationHasStepsTimingFunction(const KeyframeValueList& valueList, const Animation* anim) +{ + if (anim->timingFunction()->isStepsTimingFunction()) + return true; + + for (unsigned i = 0; i < valueList.size(); ++i) { + const TimingFunction* timingFunction = valueList.at(i)->timingFunction(); + if (timingFunction && timingFunction->isStepsTimingFunction()) + return true; + } + + return false; +} + PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) { return new GraphicsLayerCA(client); @@ -716,6 +730,11 @@ bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const Int return false; #endif + // CoreAnimation does not handle the steps() timing function. Fall back + // to software animation in that case. + if (animationHasStepsTimingFunction(valueList, anim)) + return false; + bool createdAnimations = false; if (valueList.property() == AnimatedPropertyWebkitTransform) createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, timeOffset, boxSize); @@ -1913,9 +1932,9 @@ CAMediaTimingFunction* GraphicsLayerCA::timingFunctionForAnimationValue(const An if (animValue->timingFunction()) tf = animValue->timingFunction(); else if (anim->isTimingFunctionSet()) - tf = &anim->timingFunction(); + tf = anim->timingFunction().get(); - return getCAMediaTimingFunction(tf ? *tf : TimingFunction()); + return getCAMediaTimingFunction(tf ? tf : CubicBezierTimingFunction::create().get()); } bool GraphicsLayerCA::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, CABasicAnimation* basicAnim) diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp index 89badcc..e164f8c 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp @@ -1213,7 +1213,7 @@ PlatformLayer* GraphicsLayerQt::platformLayer() const template <typename T> struct KeyframeValueQt { - TimingFunction timingFunction; + const TimingFunction* timingFunction; T value; }; @@ -1230,23 +1230,32 @@ static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, q return bezier.solve(t, solveEpsilon(duration)); } -static inline qreal applyTimingFunction(const TimingFunction& timingFunction, qreal progress, double duration) +static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t) +{ + if (stepAtStart) + return qMin(1.0, (floor(numSteps * t) + 1) / numSteps); + return floor(numSteps * t) / numSteps; +} + +static inline qreal applyTimingFunction(const TimingFunction* timingFunction, qreal progress, double duration) { // 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. - if (timingFunction.type() == LinearTimingFunction) - return progress; - if (timingFunction.type() == CubicBezierTimingFunction) { - return solveCubicBezierFunction(timingFunction.x1(), - timingFunction.y1(), - timingFunction.x2(), - timingFunction.y2(), + if (timingFunction->isCubicBezierTimingFunction()) { + const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction); + return solveCubicBezierFunction(ctf->x1(), + ctf->y1(), + ctf->x2(), + ctf->y2(), double(progress), double(duration) / 1000); - } - return progress; + } else if (timingFunction->isStepsTimingFunction()) { + const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(timingFunction); + return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), double(progress)); + } else + return progress; } // Helper functions to safely get a value out of WebCore's AnimationValue*. @@ -1322,9 +1331,9 @@ public: const AnimationValue* animationValue = values.at(i); KeyframeValueQt<T> keyframeValue; if (animationValue->timingFunction()) - keyframeValue.timingFunction = *animationValue->timingFunction(); + keyframeValue.timingFunction = animationValue->timingFunction(); else - keyframeValue.timingFunction = anim->timingFunction(); + keyframeValue.timingFunction = anim->timingFunction().get(); webkitAnimationToQtAnimationValue(animationValue, keyframeValue.value); m_keyframeValues[animationValue->keyTime()] = keyframeValue; } @@ -1381,7 +1390,7 @@ protected: const KeyframeValueQt<T>& fromKeyframe = it.value(); const KeyframeValueQt<T>& toKeyframe = it2.value(); - const TimingFunction& timingFunc = fromKeyframe.timingFunction; + const TimingFunction* timingFunc = fromKeyframe.timingFunction; const T& fromValue = fromKeyframe.value; const T& toValue = toKeyframe.value; diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index 4ad5571..605dcb7 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -604,6 +604,14 @@ PlatformLayer* MediaPlayerPrivate::platformLayer() const } #endif +PlatformMedia MediaPlayerPrivate::platformMedia() const +{ + PlatformMedia pm; + pm.type = PlatformMedia::QtMediaPlayerType; + pm.media.qtMediaPlayer = const_cast<MediaPlayerPrivate*>(this); + return pm; +} + } // namespace WebCore #include "moc_MediaPlayerPrivateQt.cpp" diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h index 165efde..117187d 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h @@ -99,6 +99,7 @@ public: virtual PlatformLayer* platformLayer() const; #endif + virtual PlatformMedia platformMedia() const; private slots: void mediaStatusChanged(QMediaPlayer::MediaStatus); void handleError(QMediaPlayer::Error); diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp index ce5da2e..df54684 100644 --- a/WebCore/platform/graphics/qt/PathQt.cpp +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -264,6 +264,11 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) void Path::closeSubpath() { + m_path.closeSubpath(); +} + +void Path::closeCanvasSubpath() +{ const int elementCount = m_path.elementCount(); if (!elementCount) @@ -469,6 +474,31 @@ void Path::transform(const AffineTransform& transform) m_path = qTransform.map(m_path); } +float Path::length() +{ + return m_path.length(); +} + +FloatPoint Path::pointAtLength(float length, bool& ok) +{ + ok = (length >= 0 && length <= m_path.length()); + + qreal percent = m_path.percentAtLength(length); + QPointF point = m_path.pointAtPercent(percent); + + return point; +} + +float Path::normalAngleAtLength(float length, bool& ok) +{ + ok = (length >= 0 && length <= m_path.length()); + + qreal percent = m_path.percentAtLength(length); + qreal angle = m_path.angleAtPercent(percent); + + return angle; +} + } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp index b6d6e65..b6d6e65 100644 --- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/skia/FontCustomPlatformData.cpp diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h b/WebCore/platform/graphics/skia/FontCustomPlatformData.h index d451c9c..d451c9c 100644 --- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/skia/FontCustomPlatformData.h diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index 1c80d49..d618c19 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -1,10 +1,10 @@ /* * Copyright (c) 2006, 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 @@ -14,7 +14,7 @@ * * 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 @@ -65,7 +65,7 @@ namespace { inline int fastMod(int value, int max) { int sign = SkExtractSign(value); - + value = SkApplySign(value, sign); if (value >= max) value %= max; @@ -391,7 +391,7 @@ void GraphicsContext::canvasClip(const Path& path) if (!isPathSkiaSafe(getCTM(), p)) return; - platformContext()->canvas()->clipPath(p); + platformContext()->canvasClipPath(p); } void GraphicsContext::clipOut(const IntRect& rect) @@ -499,7 +499,7 @@ void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* poin if (numPoints <= 1) return; - + // FIXME: IMPLEMENT!! } @@ -767,7 +767,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) ClipRectToCanvas(*platformContext()->canvas(), r, &r); } - if (platformContext()->useGPU() && !m_common->state.fillPattern && !m_common->state.fillGradient && !platformContext()->getDrawLooper()) { + if (platformContext()->useGPU() && platformContext()->canAccelerate()) { platformContext()->prepareForHardwareDraw(); platformContext()->gpuCanvas()->fillRect(rect); return; @@ -789,7 +789,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS if (paintingDisabled()) return; - if (platformContext()->useGPU() && !m_common->state.fillPattern && !m_common->state.fillGradient) { + if (platformContext()->useGPU() && platformContext()->canAccelerate()) { platformContext()->prepareForHardwareDraw(); platformContext()->gpuCanvas()->fillRect(rect, color, colorSpace); return; @@ -1240,14 +1240,19 @@ void GraphicsContext::translate(float w, float h) WebCoreFloatToSkScalar(h)); } -void GraphicsContext::setGraphicsContext3D(GraphicsContext3D* context3D, const IntSize& size) +void GraphicsContext::syncSoftwareCanvas() { - platformContext()->setGraphicsContext3D(context3D, size); + platformContext()->syncSoftwareCanvas(); } -void GraphicsContext::syncSoftwareCanvas() +void GraphicsContext::setSharedGraphicsContext3D(SharedGraphicsContext3D* context, DrawingBuffer* framebuffer, const IntSize& size) { - platformContext()->syncSoftwareCanvas(); + platformContext()->setSharedGraphicsContext3D(context, framebuffer, size); +} + +void GraphicsContext::markDirtyRect(const IntRect& rect) +{ + platformContext()->markDirtyRect(rect); } } // namespace WebCore diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 9403406..2be7dc5 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -36,10 +36,12 @@ #include "Base64.h" #include "BitmapImage.h" #include "BitmapImageSingleFrameSkia.h" +#include "DrawingBuffer.h" +#include "GLES2Canvas.h" #include "GraphicsContext.h" #include "ImageData.h" -#include "PlatformContextSkia.h" #include "PNGImageEncoder.h" +#include "PlatformContextSkia.h" #include "SkColorPriv.h" #include "SkiaUtils.h" @@ -67,9 +69,7 @@ ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, b m_data.m_platformContext.setCanvas(&m_data.m_canvas); m_context.set(new GraphicsContext(&m_data.m_platformContext)); -#if OS(WINDOWS) m_context->platformContext()->setDrawingToImageBuffer(true); -#endif // Make the background transparent. It would be nice if this wasn't // required, but the canvas is currently filled with the magic transparency @@ -100,14 +100,26 @@ PassRefPtr<Image> ImageBuffer::copyImage() const void ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const { -#if OS(LINUX) || OS(WINDOWS) context->platformContext()->beginLayerClippedToImage(rect, this); -#endif } void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, bool useLowQualityScale) { + if (m_data.m_platformContext.useGPU() && context->platformContext()->useGPU()) { + if (context->platformContext()->canAccelerate()) { + DrawingBuffer* sourceDrawingBuffer = m_data.m_platformContext.gpuCanvas()->drawingBuffer(); + unsigned sourceTexture = sourceDrawingBuffer->getRenderingResultsAsTexture(); + FloatRect destRectFlipped(destRect); + destRectFlipped.setY(destRect.y() + destRect.height()); + destRectFlipped.setHeight(-destRect.height()); + context->platformContext()->prepareForHardwareDraw(); + context->platformContext()->gpuCanvas()->drawTexturedRect(sourceTexture, m_size, srcRect, destRectFlipped, styleColorSpace, op); + return; + } + m_data.m_platformContext.syncSoftwareCanvas(); + } + RefPtr<Image> image = BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), context == m_context); context->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); } diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index aed289f..9625b34 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -47,6 +47,7 @@ #include "SkRect.h" #include "SkShader.h" #include "SkiaUtils.h" +#include "Texture.h" #include "skia/ext/image_operations.h" #include "skia/ext/platform_canvas.h" @@ -468,7 +469,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, if (normSrcRect.isEmpty() || normDstRect.isEmpty()) return; // Nothing to draw. - if (ctxt->platformContext()->useGPU()) { + if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) { drawBitmapGLES2(ctxt, bm, normSrcRect, normDstRect, colorSpace, compositeOp); return; } @@ -496,7 +497,7 @@ void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, if (normSrcRect.isEmpty() || normDstRect.isEmpty()) return; // Nothing to draw. - if (ctxt->platformContext()->useGPU()) { + if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) { drawBitmapGLES2(ctxt, &m_nativeImage, srcRect, dstRect, styleColorSpace, compositeOp); return; } diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index 3b1d015..88fbcdd 100644..100755 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -1,10 +1,10 @@ /* * Copyright (c) 2008, Google Inc. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * 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 @@ -33,12 +33,13 @@ #include "PlatformContextSkia.h" #include "AffineTransform.h" -#include "CanvasLayerChromium.h" +#include "DrawingBuffer.h" #include "GLES2Canvas.h" #include "GraphicsContext.h" #include "GraphicsContext3D.h" #include "ImageBuffer.h" #include "NativeImageSkia.h" +#include "SharedGraphicsContext3D.h" #include "SkiaUtils.h" #include "Texture.h" #include "TilingData.h" @@ -96,18 +97,19 @@ struct PlatformContextSkia::State { // color to produce a new output color. SkColor applyAlpha(SkColor) const; -#if OS(LINUX) || OS(WINDOWS) // If non-empty, the current State is clipped to this image. SkBitmap m_imageBufferClip; // If m_imageBufferClip is non-empty, this is the region the image is clipped to. FloatRect m_clip; -#endif // This is a list of clipping paths which are currently active, in the // order in which they were pushed. WTF::Vector<SkPath> m_antiAliasClipPaths; InterpolationQuality m_interpolationQuality; + // If we currently have a canvas (non-antialiased path) clip applied. + bool m_canvasClipApplied; + PlatformContextSkia::State cloneInheritedProperties(); private: // Not supported. @@ -133,6 +135,7 @@ PlatformContextSkia::State::State() , m_dash(0) , m_textDrawingMode(cTextFill) , m_interpolationQuality(InterpolationHigh) + , m_canvasClipApplied(false) { } @@ -153,12 +156,11 @@ PlatformContextSkia::State::State(const State& other) , m_lineJoin(other.m_lineJoin) , m_dash(other.m_dash) , m_textDrawingMode(other.m_textDrawingMode) -#if OS(LINUX) || OS(WINDOWS) , m_imageBufferClip(other.m_imageBufferClip) , m_clip(other.m_clip) -#endif , m_antiAliasClipPaths(other.m_antiAliasClipPaths) , m_interpolationQuality(other.m_interpolationQuality) + , m_canvasClipApplied(other.m_canvasClipApplied) { // Up the ref count of these. saveRef does nothing if 'this' is NULL. m_looper->safeRef(); @@ -181,7 +183,7 @@ PlatformContextSkia::State PlatformContextSkia::State::cloneInheritedProperties( PlatformContextSkia::State state(*this); // Everything is inherited except for the clip paths. - state.m_antiAliasClipPaths.clear(); + state.m_antiAliasClipPaths.clear(); return state; } @@ -203,9 +205,7 @@ SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const // Danger: canvas can be NULL. PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) : m_canvas(canvas) -#if OS(WINDOWS) , m_drawingToImageBuffer(false) -#endif , m_useGPU(false) , m_gpuCanvas(0) , m_backingStoreState(None) @@ -216,12 +216,8 @@ PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) PlatformContextSkia::~PlatformContextSkia() { -#if USE(ACCELERATED_COMPOSITING) - if (m_gpuCanvas) { - CanvasLayerChromium* layer = static_cast<CanvasLayerChromium*>(m_gpuCanvas->context()->platformLayer()); - layer->setPrepareTextureCallback(0); - } -#endif + if (m_gpuCanvas) + m_gpuCanvas->drawingBuffer()->setWillPublishCallback(0); } void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas) @@ -229,7 +225,6 @@ void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas) m_canvas = canvas; } -#if OS(WINDOWS) void PlatformContextSkia::setDrawingToImageBuffer(bool value) { m_drawingToImageBuffer = value; @@ -239,7 +234,6 @@ bool PlatformContextSkia::isDrawingToImageBuffer() const { return m_drawingToImageBuffer; } -#endif void PlatformContextSkia::save() { @@ -248,17 +242,14 @@ void PlatformContextSkia::save() m_stateStack.append(m_state->cloneInheritedProperties()); m_state = &m_stateStack.last(); -#if OS(LINUX) || OS(WINDOWS) // The clip image only needs to be applied once. Reset the image so that we // don't attempt to clip multiple times. m_state->m_imageBufferClip.reset(); -#endif // Save our native canvas. canvas()->save(); } -#if OS(LINUX) || OS(WINDOWS) void PlatformContextSkia::beginLayerClippedToImage(const FloatRect& rect, const ImageBuffer* imageBuffer) { @@ -287,7 +278,6 @@ void PlatformContextSkia::beginLayerClippedToImage(const FloatRect& rect, m_state->m_imageBufferClip = *bitmap; } } -#endif void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath) { @@ -306,12 +296,10 @@ void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath) void PlatformContextSkia::restore() { -#if OS(LINUX) || OS(WINDOWS) if (!m_state->m_imageBufferClip.empty()) { applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip); canvas()->restore(); } -#endif if (!m_state->m_antiAliasClipPaths.isEmpty()) applyAntiAliasedClipPaths(m_state->m_antiAliasClipPaths); @@ -337,7 +325,7 @@ void PlatformContextSkia::drawRect(SkRect rect) // We do a fill of four rects to simulate the stroke of a border. SkColor oldFillColor = m_state->m_fillColor; - // setFillColor() will set the shader to NULL, so save a ref to it now. + // setFillColor() will set the shader to NULL, so save a ref to it now. SkShader* oldFillShader = m_state->m_fillShader; oldFillShader->safeRef(); setFillColor(m_state->m_strokeColor); @@ -462,7 +450,7 @@ void PlatformContextSkia::setXfermodeMode(SkXfermode::Mode pdm) void PlatformContextSkia::setFillColor(SkColor color) { m_state->m_fillColor = color; - setFillShader(NULL); + setFillShader(0); } SkDrawLooper* PlatformContextSkia::getDrawLooper() const @@ -483,7 +471,7 @@ void PlatformContextSkia::setStrokeStyle(StrokeStyle strokeStyle) void PlatformContextSkia::setStrokeColor(SkColor strokeColor) { m_state->m_strokeColor = strokeColor; - setStrokeShader(NULL); + setStrokeShader(0); } float PlatformContextSkia::getStrokeThickness() const @@ -559,6 +547,12 @@ SkPath PlatformContextSkia::currentPathInLocalCoordinates() const return localPath; } +void PlatformContextSkia::canvasClipPath(const SkPath& path) +{ + m_state->m_canvasClipApplied = true; + m_canvas->clipPath(path); +} + void PlatformContextSkia::setFillRule(SkPath::FillType fr) { m_path.setFillType(fr); @@ -630,7 +624,6 @@ bool PlatformContextSkia::hasImageResamplingHint() const return !m_imageResamplingHintSrcSize.isEmpty() && !m_imageResamplingHintDstSize.isEmpty(); } -#if OS(LINUX) || OS(WINDOWS) void PlatformContextSkia::applyClipFromImage(const FloatRect& rect, const SkBitmap& imageBuffer) { // NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we @@ -639,7 +632,6 @@ void PlatformContextSkia::applyClipFromImage(const FloatRect& rect, const SkBitm paint.setXfermodeMode(SkXfermode::kDstIn_Mode); m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint); } -#endif void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths) { @@ -678,33 +670,47 @@ void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths) m_canvas->restore(); } -#if USE(ACCELERATED_COMPOSITING) -class PrepareTextureCallbackImpl : public CanvasLayerChromium::PrepareTextureCallback { +bool PlatformContextSkia::canAccelerate() const +{ + return !m_state->m_fillShader // Can't accelerate with a fill gradient or pattern. + && !m_state->m_looper // Can't accelerate with a shadow. + && !m_state->m_canvasClipApplied; // Can't accelerate with a clip to path applied. +} + +class WillPublishCallbackImpl : public DrawingBuffer::WillPublishCallback { public: - static PassOwnPtr<PrepareTextureCallbackImpl> create(PlatformContextSkia* pcs) + static PassOwnPtr<WillPublishCallback> create(PlatformContextSkia* pcs) { - return new PrepareTextureCallbackImpl(pcs); + return adoptPtr(new WillPublishCallbackImpl(pcs)); } - virtual void willPrepareTexture() + virtual void willPublish() { m_pcs->prepareForHardwareDraw(); } + private: - explicit PrepareTextureCallbackImpl(PlatformContextSkia* pcs) : m_pcs(pcs) {} + explicit WillPublishCallbackImpl(PlatformContextSkia* pcs) + : m_pcs(pcs) + { + } + PlatformContextSkia* m_pcs; }; -#endif -void PlatformContextSkia::setGraphicsContext3D(GraphicsContext3D* context, const WebCore::IntSize& size) +void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* context, DrawingBuffer* drawingBuffer, const WebCore::IntSize& size) { - m_useGPU = true; - m_gpuCanvas = new GLES2Canvas(context, size); - m_uploadTexture.clear(); -#if USE(ACCELERATED_COMPOSITING) - CanvasLayerChromium* layer = static_cast<CanvasLayerChromium*>(context->platformLayer()); - layer->setPrepareTextureCallback(PrepareTextureCallbackImpl::create(this)); -#endif + if (context && drawingBuffer) { + m_useGPU = true; + m_gpuCanvas = new GLES2Canvas(context, drawingBuffer, size); + m_uploadTexture.clear(); + drawingBuffer->setWillPublishCallback(WillPublishCallbackImpl::create(this)); + } else { + syncSoftwareCanvas(); + m_uploadTexture.clear(); + m_gpuCanvas.clear(); + m_useGPU = false; + } } void PlatformContextSkia::prepareForSoftwareDraw() const @@ -725,9 +731,7 @@ void PlatformContextSkia::prepareForSoftwareDraw() const // of a compositing operation). if (m_state->m_xferMode == SkXfermode::kSrcOver_Mode) { - // Last drawn on hardware; clear out the canvas. - m_canvas->getDevice()->eraseColor(0); - // Start compositing into the empty canvas. + // Note that we have rendering results in both the hardware and software backing stores. m_backingStoreState = Mixed; } else { readbackHardwareToSoftware(); @@ -780,17 +784,42 @@ void PlatformContextSkia::syncSoftwareCanvas() const m_backingStoreState = Software; } +void PlatformContextSkia::markDirtyRect(const IntRect& rect) +{ + if (!m_useGPU) + return; + + switch (m_backingStoreState) { + case Software: + case Mixed: + m_softwareDirtyRect.unite(rect); + return; + case Hardware: + return; + default: + ASSERT_NOT_REACHED(); + } +} + void PlatformContextSkia::uploadSoftwareToHardware(CompositeOperator op) const { const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(false); SkAutoLockPixels lock(bitmap); - GraphicsContext3D* context = m_gpuCanvas->context(); + SharedGraphicsContext3D* context = m_gpuCanvas->context(); if (!m_uploadTexture || m_uploadTexture->tiles().totalSizeX() < bitmap.width() || m_uploadTexture->tiles().totalSizeY() < bitmap.height()) - m_uploadTexture = Texture::create(context, Texture::BGRA8, bitmap.width(), bitmap.height()); - m_uploadTexture->load(bitmap.getPixels()); - IntRect rect(0, 0, bitmap.width(), bitmap.height()); + m_uploadTexture = context->createTexture(Texture::BGRA8, bitmap.width(), bitmap.height()); + + m_uploadTexture->updateSubRect(bitmap.getPixels(), m_softwareDirtyRect); AffineTransform identity; - gpuCanvas()->drawTexturedRect(m_uploadTexture.get(), rect, rect, identity, 1.0, DeviceColorSpace, op); + gpuCanvas()->drawTexturedRect(m_uploadTexture.get(), m_softwareDirtyRect, m_softwareDirtyRect, identity, 1.0, DeviceColorSpace, op); + // Clear out the region of the software canvas we just uploaded. + m_canvas->save(); + m_canvas->resetMatrix(); + SkRect bounds = m_softwareDirtyRect; + m_canvas->clipRect(bounds, SkRegion::kReplace_Op); + m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); + m_canvas->restore(); + m_softwareDirtyRect.setWidth(0); // Clear dirty rect. } void PlatformContextSkia::readbackHardwareToSoftware() const @@ -799,7 +828,8 @@ void PlatformContextSkia::readbackHardwareToSoftware() const SkAutoLockPixels lock(bitmap); int width = bitmap.width(), height = bitmap.height(); OwnArrayPtr<uint32_t> buf(new uint32_t[width]); - GraphicsContext3D* context = m_gpuCanvas->context(); + SharedGraphicsContext3D* context = m_gpuCanvas->context(); + m_gpuCanvas->bindFramebuffer(); // Flips the image vertically. for (int y = 0; y < height; ++y) { uint32_t* pixels = bitmap.getAddr32(0, y); @@ -814,6 +844,7 @@ void PlatformContextSkia::readbackHardwareToSoftware() const } } } + m_softwareDirtyRect.unite(IntRect(0, 0, width, height)); // Mark everything as dirty. } } // namespace WebCore diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h index 82edc16..4ba85d1 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -1,10 +1,10 @@ /* * Copyright (c) 2008, Google Inc. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -14,7 +14,7 @@ * * 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 @@ -35,7 +35,6 @@ #include "Noncopyable.h" #include "SkDashPathEffect.h" -#include "SkDeque.h" #include "SkDrawLooper.h" #include "SkPaint.h" #include "SkPath.h" @@ -46,9 +45,10 @@ namespace WebCore { enum CompositeOperator; +class DrawingBuffer; class GLES2Canvas; -class Texture; class GraphicsContext3D; +class Texture; // This class holds the platform-specific state for GraphicsContext. We put // most of our Skia wrappers on this class. In theory, a lot of this stuff could @@ -78,7 +78,6 @@ public: // to the constructor. void setCanvas(skia::PlatformCanvas*); -#if OS(WINDOWS) // If false we're rendering to a GraphicsContext for a web page, if false // we're not (as is the case when rendering to a canvas object). // If this is true the contents have not been marked up with the magic @@ -86,7 +85,6 @@ public: // correctly updated. void setDrawingToImageBuffer(bool); bool isDrawingToImageBuffer() const; -#endif void save(); void restore(); @@ -95,9 +93,7 @@ public: // |rect|. This layer is implicitly restored when the next restore is // invoked. // NOTE: |imageBuffer| may be deleted before the |restore| is invoked. -#if OS(LINUX) || OS(WINDOWS) void beginLayerClippedToImage(const FloatRect&, const ImageBuffer*); -#endif void clipPathAntiAliased(const SkPath&); // Sets up the common flags on a paint for antialiasing, effects, etc. @@ -143,6 +139,8 @@ public: void addPath(const SkPath&); SkPath currentPathInLocalCoordinates() const; + void canvasClipPath(const SkPath&); + // Returns the fill color. The returned color has it's alpha adjusted // by the current alpha. SkColor effectiveFillColor() const; @@ -180,8 +178,10 @@ public: void setImageResamplingHint(const IntSize& srcSize, const FloatSize& dstSize); void clearImageResamplingHint(); bool hasImageResamplingHint() const; + + bool canAccelerate() const; bool useGPU() { return m_useGPU; } - void setGraphicsContext3D(GraphicsContext3D*, const IntSize&); + void setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&); GLES2Canvas* gpuCanvas() const { return m_gpuCanvas.get(); } // Call these before making a call that manipulates the underlying @@ -190,13 +190,12 @@ public: void prepareForHardwareDraw() const; // Call to force the skia::PlatformCanvas to contain all rendering results. void syncSoftwareCanvas() const; + void markDirtyRect(const IntRect& rect); private: -#if OS(LINUX) || OS(WINDOWS) // Used when restoring and the state has an image clip. Only shows the pixels in // m_canvas that are also in imageBuffer. void applyClipFromImage(const FloatRect&, const SkBitmap&); -#endif void applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths); void uploadSoftwareToHardware(CompositeOperator) const; @@ -218,17 +217,16 @@ private: // Current path in global coordinates. SkPath m_path; - // Stores image sizes for a hint to compute image resampling modes. + // Stores image sizes for a hint to compute image resampling modes. // Values are used in ImageSkia.cpp IntSize m_imageResamplingHintSrcSize; FloatSize m_imageResamplingHintDstSize; -#if OS(WINDOWS) bool m_drawingToImageBuffer; -#endif bool m_useGPU; OwnPtr<GLES2Canvas> m_gpuCanvas; mutable enum { None, Software, Mixed, Hardware } m_backingStoreState; mutable RefPtr<Texture> m_uploadTexture; + mutable IntRect m_softwareDirtyRect; }; } diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index 7b65e96..0203d42 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -79,37 +79,37 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha) // suitable for all clients? void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { - if (mayCreateBitmap && hdc && inTransparencyLayer()) { - if (dstRect.isEmpty()) - return; - - HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); - - // Need to make a CGImage out of the bitmap's pixel buffer and then draw - // it into our context. - BITMAP info; - GetObject(bitmap, sizeof(info), &info); - ASSERT(info.bmBitsPixel == 32); - - CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); - CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, - info.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | - (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst)); - CGColorSpaceRelease(deviceRGB); - - CGImageRef image = CGBitmapContextCreateImage(bitmapContext); - CGContextDrawImage(m_data->m_cgContext.get(), dstRect, image); - - // Delete all our junk. - CGImageRelease(image); - CGContextRelease(bitmapContext); - ::DeleteDC(hdc); - ::DeleteObject(bitmap); - + bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer()); + if (!createdBitmap) { + m_data->restore(); return; } - m_data->restore(); + if (dstRect.isEmpty()) + return; + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + + // Need to make a CGImage out of the bitmap's pixel buffer and then draw + // it into our context. + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); + CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, + info.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | + (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst)); + CGColorSpaceRelease(deviceRGB); + + CGImageRef image = CGBitmapContextCreateImage(bitmapContext); + CGContextDrawImage(m_data->m_cgContext.get(), dstRect, image); + + // Delete all our junk. + CGImageRelease(image); + CGContextRelease(bitmapContext); + ::DeleteDC(hdc); + ::DeleteObject(bitmap); } void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point) diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 94df6ae..a989c24 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -92,7 +92,8 @@ static void setRGBABitmapAlpha(unsigned char* bytes, size_t length, unsigned cha void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { - if (!mayCreateBitmap || !hdc || !inTransparencyLayer()) { + bool createdBitmap = mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer()); + if (!hdc || !createdBitmap) { m_data->restore(); return; } diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp index 161b9c6..f1953e4 100644 --- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp @@ -101,7 +101,7 @@ GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize siz HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { // FIXME: Should a bitmap be created also when a shadow is set? - if (mayCreateBitmap && inTransparencyLayer()) { + if (mayCreateBitmap && (!m_data->m_hdc || inTransparencyLayer())) { if (dstRect.isEmpty()) return 0; diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp index cc9343a..05959e0 100644 --- a/WebCore/platform/graphics/win/IconWin.cpp +++ b/WebCore/platform/graphics/win/IconWin.cpp @@ -23,6 +23,7 @@ #include "Icon.h" #include "GraphicsContext.h" +#include "LocalWindowsContext.h" #include "PlatformString.h" #include <tchar.h> #include <windows.h> @@ -90,11 +91,8 @@ void Icon::paint(GraphicsContext* context, const IntRect& r) #if OS(WINCE) context->drawIcon(m_hIcon, r, DI_NORMAL); #else - HDC hdc = context->getWindowsContext(r); - - DrawIconEx(hdc, r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL); - - context->releaseWindowsContext(hdc, r); + LocalWindowsContext windowContext(context, r); + DrawIconEx(windowContext.hdc(), r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL); #endif } diff --git a/WebCore/platform/graphics/win/LocalWindowsContext.h b/WebCore/platform/graphics/win/LocalWindowsContext.h new file mode 100755 index 0000000..c216140 --- /dev/null +++ b/WebCore/platform/graphics/win/LocalWindowsContext.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 LocalWindowsContext_h +#define LocalWindowsContext_h + +#include "config.h" +#include "GraphicsContext.h" + +namespace WebCore { + +class LocalWindowsContext : public Noncopyable { +public: + LocalWindowsContext(GraphicsContext* graphicsContext, const IntRect& rect, bool supportAlphaBlend = true, bool mayCreateBitmap = true) + : m_graphicsContext(graphicsContext) + , m_rect(rect) + , m_supportAlphaBlend(supportAlphaBlend) + , m_mayCreateBitmap(mayCreateBitmap) + { + m_hdc = m_graphicsContext->getWindowsContext(m_rect, m_supportAlphaBlend, m_mayCreateBitmap); + } + + ~LocalWindowsContext() + { + m_graphicsContext->releaseWindowsContext(m_hdc, m_rect, m_supportAlphaBlend, m_mayCreateBitmap); + } + + HDC hdc() const { return m_hdc; } + +private: + GraphicsContext* m_graphicsContext; + HDC m_hdc; + IntRect m_rect; + bool m_supportAlphaBlend; + bool m_mayCreateBitmap; +}; + +} // namespace WebCore +#endif // LocalWindowsContext_h diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index 34f1135..c37f5d5 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -600,6 +600,7 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) bool usingTempBitmap = false; OwnPtr<GraphicsContext::WindowsBitmap> bitmap; + // FIXME: use LocalWindowsContext. HDC hdc = p->getWindowsContext(r); if (!hdc) { // The graphics context doesn't have an associated HDC so create a temporary diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp index 2a355c2..630a8af 100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp @@ -408,10 +408,7 @@ bool WKCACFLayerRenderer::createRenderer() m_d3dDevice = device; - D3DXMATRIXA16 projection; - D3DXMatrixOrthoOffCenterRH(&projection, rect.left, rect.right, rect.top, rect.bottom, -1.0f, 1.0f); - - m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); + initD3DGeometry(); m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0); |