summaryrefslogtreecommitdiffstats
path: root/WebCore/platform
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform')
-rw-r--r--WebCore/platform/ScrollAnimator.cpp76
-rw-r--r--WebCore/platform/ScrollAnimator.h65
-rw-r--r--WebCore/platform/ScrollAnimatorWin.cpp296
-rw-r--r--WebCore/platform/ScrollAnimatorWin.h71
-rw-r--r--WebCore/platform/ScrollView.cpp25
-rw-r--r--WebCore/platform/ScrollView.h11
-rw-r--r--WebCore/platform/Scrollbar.cpp21
-rw-r--r--WebCore/platform/Scrollbar.h9
-rw-r--r--WebCore/platform/ScrollbarClient.cpp57
-rw-r--r--WebCore/platform/ScrollbarClient.h21
-rw-r--r--WebCore/platform/ScrollbarThemeComposite.cpp7
-rw-r--r--WebCore/platform/UUID.cpp7
-rw-r--r--WebCore/platform/android/TemporaryLinkStubs.cpp2
-rw-r--r--WebCore/platform/animation/Animation.cpp34
-rw-r--r--WebCore/platform/animation/Animation.h9
-rw-r--r--WebCore/platform/animation/TimingFunction.h123
-rw-r--r--WebCore/platform/audio/AudioArray.h71
-rw-r--r--WebCore/platform/audio/AudioBus.cpp363
-rw-r--r--WebCore/platform/audio/AudioBus.h139
-rw-r--r--WebCore/platform/audio/AudioChannel.cpp102
-rw-r--r--WebCore/platform/audio/AudioChannel.h112
-rw-r--r--WebCore/platform/audio/AudioDSPKernel.h65
-rw-r--r--WebCore/platform/audio/AudioDSPKernelProcessor.cpp116
-rw-r--r--WebCore/platform/audio/AudioDSPKernelProcessor.h76
-rw-r--r--WebCore/platform/audio/AudioProcessor.h75
-rw-r--r--WebCore/platform/audio/AudioSourceProvider.h46
-rw-r--r--WebCore/platform/audio/Biquad.cpp280
-rw-r--r--WebCore/platform/audio/Biquad.h99
-rw-r--r--WebCore/platform/audio/Distance.cpp93
-rw-r--r--WebCore/platform/audio/Distance.h80
-rw-r--r--WebCore/platform/audio/FFTFrame.cpp269
-rw-r--r--WebCore/platform/audio/FFTFrame.h102
-rw-r--r--WebCore/platform/audio/Panner.cpp71
-rw-r--r--WebCore/platform/audio/Panner.h69
-rw-r--r--WebCore/platform/audio/mac/FFTFrameMac.cpp191
-rw-r--r--WebCore/platform/chromium/ChromiumBridge.h3
-rw-r--r--WebCore/platform/chromium/ClipboardChromium.cpp2
-rw-r--r--WebCore/platform/chromium/PasteboardChromium.cpp2
-rw-r--r--WebCore/platform/efl/ScrollbarEfl.cpp2
-rw-r--r--WebCore/platform/graphics/Font.cpp10
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp29
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h8
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.h12
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp6
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h6
-rw-r--r--WebCore/platform/graphics/Path.cpp2
-rw-r--r--WebCore/platform/graphics/Path.h5
-rw-r--r--WebCore/platform/graphics/cairo/FontCacheCairo.cpp8
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp2
-rw-r--r--WebCore/platform/graphics/cairo/OwnPtrCairo.cpp (renamed from WebCore/platform/graphics/cairo/GOwnPtrCairo.cpp)8
-rw-r--r--WebCore/platform/graphics/cairo/OwnPtrCairo.h (renamed from WebCore/platform/graphics/cairo/GOwnPtrCairo.h)12
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp1
-rw-r--r--WebCore/platform/graphics/chromium/Canvas2DLayerChromium.cpp112
-rw-r--r--WebCore/platform/graphics/chromium/Canvas2DLayerChromium.h65
-rw-r--r--WebCore/platform/graphics/chromium/CanvasLayerChromium.cpp43
-rw-r--r--WebCore/platform/graphics/chromium/CanvasLayerChromium.h28
-rw-r--r--WebCore/platform/graphics/chromium/ContentLayerChromium.cpp35
-rw-r--r--WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp142
-rw-r--r--WebCore/platform/graphics/chromium/FontChromiumWin.cpp2
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp33
-rw-r--r--WebCore/platform/graphics/chromium/GLES2Canvas.cpp166
-rw-r--r--WebCore/platform/graphics/chromium/GLES2Canvas.h29
-rw-r--r--WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp13
-rw-r--r--WebCore/platform/graphics/chromium/GraphicsLayerChromium.h2
-rw-r--r--WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp10
-rw-r--r--WebCore/platform/graphics/chromium/ImageLayerChromium.cpp10
-rw-r--r--WebCore/platform/graphics/chromium/LayerRendererChromium.cpp18
-rw-r--r--WebCore/platform/graphics/chromium/VideoLayerChromium.cpp7
-rw-r--r--WebCore/platform/graphics/chromium/WebGLLayerChromium.cpp85
-rw-r--r--WebCore/platform/graphics/chromium/WebGLLayerChromium.h60
-rw-r--r--WebCore/platform/graphics/gpu/DrawingBuffer.cpp60
-rw-r--r--WebCore/platform/graphics/gpu/DrawingBuffer.h84
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp122
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnClassifier.h84
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnConstants.h40
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp565
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnMathUtils.h108
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp171
-rw-r--r--WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.h82
-rw-r--r--WebCore/platform/graphics/gpu/PODArena.h211
-rw-r--r--WebCore/platform/graphics/gpu/PODInterval.h155
-rw-r--r--WebCore/platform/graphics/gpu/PODIntervalTree.h217
-rw-r--r--WebCore/platform/graphics/gpu/PODRedBlackTree.h750
-rw-r--r--WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp296
-rw-r--r--WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h124
-rw-r--r--WebCore/platform/graphics/gpu/Texture.cpp68
-rw-r--r--WebCore/platform/graphics/gpu/Texture.h3
-rw-r--r--WebCore/platform/graphics/gpu/TilingData.h1
-rw-r--r--WebCore/platform/graphics/gstreamer/DataSourceGStreamer.cpp3
-rw-r--r--WebCore/platform/graphics/gstreamer/DataSourceGStreamer.h3
-rw-r--r--WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.cpp2
-rw-r--r--WebCore/platform/graphics/gstreamer/GOwnPtrGStreamer.h2
-rw-r--r--WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp4
-rw-r--r--WebCore/platform/graphics/gstreamer/GStreamerGWorld.h3
-rw-r--r--WebCore/platform/graphics/gstreamer/ImageGStreamer.h4
-rw-r--r--WebCore/platform/graphics/gstreamer/ImageGStreamerCG.mm3
-rw-r--r--WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp6
-rw-r--r--WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp36
-rw-r--r--WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h4
-rw-r--r--WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h4
-rw-r--r--WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp3
-rw-r--r--WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp3
-rw-r--r--WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp2
-rw-r--r--WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.h3
-rw-r--r--WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp3
-rw-r--r--WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h2
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContext3DMac.mm31
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm43
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.cpp37
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp8
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h1
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp30
-rw-r--r--WebCore/platform/graphics/skia/FontCustomPlatformData.cpp (renamed from WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp)0
-rw-r--r--WebCore/platform/graphics/skia/FontCustomPlatformData.h (renamed from WebCore/platform/graphics/chromium/FontCustomPlatformData.h)0
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextSkia.cpp29
-rw-r--r--WebCore/platform/graphics/skia/ImageBufferSkia.cpp22
-rw-r--r--WebCore/platform/graphics/skia/ImageSkia.cpp5
-rwxr-xr-x[-rw-r--r--]WebCore/platform/graphics/skia/PlatformContextSkia.cpp139
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.h28
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp56
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp3
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp2
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp8
-rwxr-xr-xWebCore/platform/graphics/win/LocalWindowsContext.h61
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp1
-rw-r--r--WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp5
-rw-r--r--WebCore/platform/gtk/ClipboardGtk.cpp2
-rw-r--r--WebCore/platform/gtk/GeolocationServiceGtk.cpp2
-rw-r--r--WebCore/platform/gtk/GeolocationServiceGtk.h2
-rw-r--r--WebCore/platform/gtk/MainFrameScrollbarGtk.cpp118
-rw-r--r--WebCore/platform/gtk/MainFrameScrollbarGtk.h52
-rw-r--r--WebCore/platform/gtk/PasteboardGtk.cpp2
-rw-r--r--WebCore/platform/gtk/ScrollViewGtk.cpp106
-rw-r--r--WebCore/platform/gtk/ScrollbarGtk.cpp253
-rw-r--r--WebCore/platform/gtk/ScrollbarGtk.h71
-rw-r--r--WebCore/platform/gtk/ScrollbarThemeGtk.cpp66
-rw-r--r--WebCore/platform/gtk/ScrollbarThemeGtk.h2
-rw-r--r--WebCore/platform/gtk/gtk2drawing.c2
-rw-r--r--WebCore/platform/gtk/gtkdrawing.h2
-rw-r--r--WebCore/platform/network/FormData.cpp2
-rw-r--r--WebCore/platform/network/android/ResourceHandleAndroid.cpp8
-rw-r--r--WebCore/platform/network/cf/ResourceHandleCFNet.cpp2
-rw-r--r--WebCore/platform/network/curl/ResourceHandleCurl.cpp2
-rw-r--r--WebCore/platform/network/curl/ResourceHandleManager.cpp3
-rw-r--r--WebCore/platform/network/curl/ResourceRequest.h5
-rw-r--r--WebCore/platform/network/curl/ResourceResponse.h5
-rw-r--r--WebCore/platform/network/mac/ResourceHandleMac.mm2
-rw-r--r--WebCore/platform/network/qt/ResourceHandleQt.cpp2
-rw-r--r--WebCore/platform/network/qt/ResourceRequestQt.cpp5
-rw-r--r--WebCore/platform/network/soup/ResourceHandleSoup.cpp2
-rw-r--r--WebCore/platform/network/soup/SocketStreamHandle.h13
-rw-r--r--WebCore/platform/network/soup/SocketStreamHandleSoup.cpp209
-rw-r--r--WebCore/platform/network/win/ResourceHandleWin.cpp2
-rw-r--r--WebCore/platform/qt/ClipboardQt.cpp2
-rw-r--r--WebCore/platform/qt/PasteboardQt.cpp2
-rw-r--r--WebCore/platform/qt/ScrollbarQt.cpp6
-rw-r--r--WebCore/platform/text/CharacterNames.h1
-rw-r--r--WebCore/platform/text/wince/TextCodecWinCE.cpp86
-rw-r--r--WebCore/platform/win/ClipboardWin.cpp2
-rw-r--r--WebCore/platform/win/PasteboardWin.cpp2
-rw-r--r--WebCore/platform/win/PopupMenuWin.cpp15
-rw-r--r--WebCore/platform/win/PopupMenuWin.h2
-rw-r--r--WebCore/platform/win/ScrollbarThemeWin.cpp16
163 files changed, 7944 insertions, 1103 deletions
diff --git a/WebCore/platform/ScrollAnimator.cpp b/WebCore/platform/ScrollAnimator.cpp
new file mode 100644
index 0000000..c863c1d
--- /dev/null
+++ b/WebCore/platform/ScrollAnimator.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "ScrollAnimator.h"
+
+#include "ScrollbarClient.h"
+#include <algorithm>
+
+namespace WebCore {
+
+#if !OS(WINDOWS)
+ScrollAnimator* ScrollAnimator::create(ScrollbarClient* client)
+{
+ return new ScrollAnimator(client);
+}
+#endif
+
+ScrollAnimator::ScrollAnimator(ScrollbarClient* client)
+ : m_client(client)
+ , m_currentPosX(0)
+ , m_currentPosY(0)
+{
+}
+
+ScrollAnimator::~ScrollAnimator()
+{
+}
+
+bool ScrollAnimator::scroll(ScrollbarOrientation orientation, ScrollGranularity, float step, float multiplier)
+{
+ float* currentPos = (orientation == HorizontalScrollbar) ? &m_currentPosX : &m_currentPosY;
+ float newPos = std::max(std::min(*currentPos + (step * multiplier), static_cast<float>(m_client->scrollSize(orientation))), 0.0f);
+ if (*currentPos == newPos)
+ return false;
+ *currentPos = newPos;
+ m_client->setScrollOffsetFromAnimation(IntPoint(m_currentPosX, m_currentPosY));
+ return true;
+}
+
+void ScrollAnimator::setScrollPositionAndStopAnimation(ScrollbarOrientation orientation, float pos)
+{
+ if (orientation == HorizontalScrollbar)
+ m_currentPosX = pos;
+ else
+ m_currentPosY = pos;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/ScrollAnimator.h b/WebCore/platform/ScrollAnimator.h
new file mode 100644
index 0000000..e674339
--- /dev/null
+++ b/WebCore/platform/ScrollAnimator.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 ScrollAnimator_h
+#define ScrollAnimator_h
+
+#include "ScrollTypes.h"
+
+namespace WebCore {
+
+class ScrollbarClient;
+
+class ScrollAnimator {
+public:
+ static ScrollAnimator* create(ScrollbarClient*);
+
+ ScrollAnimator(ScrollbarClient* client);
+ virtual ~ScrollAnimator();
+
+ // Computes a scroll destination for the given parameters. Returns false if
+ // already at the destination. Otherwise, starts scrolling towards the
+ // destination and returns true. Scrolling may be immediate or animated.
+ // The base class implementation always scrolls immediately, never animates.
+ virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier);
+
+ // Stops any animation in the given direction and updates the ScrollAnimator
+ // with the current scroll position. This does not cause a callback to the
+ // ScrollbarClient.
+ virtual void setScrollPositionAndStopAnimation(ScrollbarOrientation, float);
+
+protected:
+ ScrollbarClient* m_client;
+ float m_currentPosX; // We avoid using a FloatPoint in order to reduce
+ float m_currentPosY; // subclass code complexity.
+};
+
+} // namespace WebCore
+#endif
diff --git a/WebCore/platform/ScrollAnimatorWin.cpp b/WebCore/platform/ScrollAnimatorWin.cpp
new file mode 100644
index 0000000..8b7d0f6
--- /dev/null
+++ b/WebCore/platform/ScrollAnimatorWin.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 "ScrollAnimatorWin.h"
+
+#include "ScrollbarClient.h"
+#include "ScrollbarTheme.h"
+#include <algorithm>
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+// static
+ScrollAnimator* ScrollAnimator::create(ScrollbarClient* client)
+{
+ return new ScrollAnimatorWin(client);
+}
+
+const double ScrollAnimatorWin::animationTimerDelay = 0.01;
+
+ScrollAnimatorWin::PerAxisData::PerAxisData(ScrollAnimatorWin* parent, float* currentPos)
+ : m_currentPos(currentPos)
+ , m_desiredPos(0)
+ , m_currentVelocity(0)
+ , m_desiredVelocity(0)
+ , m_lastAnimationTime(0)
+ , m_animationTimer(parent, &ScrollAnimatorWin::animationTimerFired)
+{
+}
+
+
+ScrollAnimatorWin::ScrollAnimatorWin(ScrollbarClient* client)
+ : ScrollAnimator(client)
+ , m_horizontalData(this, &m_currentPosX)
+ , m_verticalData(this, &m_currentPosY)
+{
+}
+
+ScrollAnimatorWin::~ScrollAnimatorWin()
+{
+ stopAnimationTimerIfNeeded(&m_horizontalData);
+ stopAnimationTimerIfNeeded(&m_verticalData);
+}
+
+bool ScrollAnimatorWin::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier)
+{
+ // Don't animate jumping to the beginning or end of the document.
+ if (granularity == ScrollByDocument)
+ return ScrollAnimator::scroll(orientation, granularity, step, multiplier);
+
+ // This is an animatable scroll. Calculate the scroll delta.
+ PerAxisData* data = (orientation == VerticalScrollbar) ? &m_verticalData : &m_horizontalData;
+ float newPos = std::max(std::min(data->m_desiredPos + (step * multiplier), static_cast<float>(m_client->scrollSize(orientation))), 0.0f);
+ if (newPos == data->m_desiredPos)
+ return false;
+ data->m_desiredPos = newPos;
+
+ // Calculate the animation velocity.
+ if (*data->m_currentPos == data->m_desiredPos)
+ return false;
+ bool alreadyAnimating = data->m_animationTimer.isActive();
+ // There are a number of different sources of scroll requests. We want to
+ // make both keyboard and wheel-generated scroll requests (which can come at
+ // unpredictable rates) and autoscrolling from holding down the mouse button
+ // on a scrollbar part (where the request rate can be obtained from the
+ // scrollbar theme) feel smooth, responsive, and similar.
+ //
+ // When autoscrolling, the scrollbar's autoscroll timer will call us to
+ // increment the desired position by |step| (with |multiplier| == 1) every
+ // ScrollbarTheme::nativeTheme()->autoscrollTimerDelay() seconds. If we set
+ // the desired velocity to exactly this rate, smooth scrolling will neither
+ // race ahead (and then have to slow down) nor increasingly lag behind, but
+ // will be smooth and synchronized.
+ //
+ // Note that because of the acceleration period, the current position in
+ // this case would lag the desired one by a small, constant amount (see
+ // comments on animateScroll()); the exact amount is given by
+ // lag = |step| - v(0.5tA + tD)
+ // Where
+ // v = The steady-state velocity,
+ // |step| / ScrollbarTheme::nativeTheme()->autoscrollTimerDelay()
+ // tA = accelerationTime()
+ // tD = The time we pretend has already passed when starting to scroll,
+ // |animationTimerDelay|
+ //
+ // This lag provides some buffer against timer jitter so we're less likely
+ // to hit the desired position and stop (and thus have to re-accelerate,
+ // causing a visible hitch) while waiting for the next autoscroll increment.
+ //
+ // Thus, for autoscroll-timer-triggered requests, the ideal steady-state
+ // distance to travel in each time interval is:
+ // float animationStep = step;
+ // Note that when we're not already animating, this is exactly the same as
+ // the distance to the target position. We'll return to that in a moment.
+ //
+ // For keyboard and wheel scrolls, we don't know when the next increment
+ // will be requested. If we set the target velocity based on how far away
+ // from the target position we are, then for keyboard/wheel events that come
+ // faster than the autoscroll delay, we'll asymptotically approach the
+ // velocity needed to stay smoothly in sync with the user's actions; for
+ // events that come slower, we'll scroll one increment and then pause until
+ // the next event fires.
+ float animationStep = abs(newPos - *data->m_currentPos);
+ // If a key is held down (or the wheel continually spun), then once we have
+ // reached a velocity close to the steady-state velocity, we're likely to
+ // hit the desired position at around the same time we'd expect the next
+ // increment to occur -- bad because it leads to hitching as described above
+ // (if autoscroll-based requests didn't result in a small amount of constant
+ // lag). So if we're called again while already animating, we want to trim
+ // the animationStep slightly to maintain lag like what's described above.
+ // (I say "maintain" since we'll already be lagged due to the acceleration
+ // during the first scroll period.)
+ //
+ // Remember that trimming won't cause us to fall steadily further behind
+ // here, because the further behind we are, the larger the base step value
+ // above. Given the scrolling algorithm in animateScroll(), the practical
+ // effect will actually be that, assuming a constant trim factor, we'll lag
+ // by a constant amount depending on the rate at which increments occur
+ // compared to the autoscroll timer delay. The exact lag is given by
+ // lag = |step| * ((r / k) - 1)
+ // Where
+ // r = The ratio of the autoscroll repeat delay,
+ // ScrollbarTheme::nativeTheme()->autoscrollTimerDelay(), to the
+ // key/wheel repeat delay (i.e. > 1 when keys repeat faster)
+ // k = The velocity trim constant given below
+ //
+ // We want to choose the trim factor such that for calls that come at the
+ // autoscroll timer rate, we'll wind up with the same lag as in the
+ // "perfect" case described above (or, to put it another way, we'll end up
+ // with |animationStep| == |step| * |multiplier| despite the actual distance
+ // calculated above being larger than that). This will result in "perfect"
+ // behavior for autoscrolling without having to special-case it.
+ if (alreadyAnimating)
+ animationStep /= (2.0 - ((1.0 / ScrollbarTheme::nativeTheme()->autoscrollTimerDelay()) * (0.5 * accelerationTime() + animationTimerDelay)));
+ // The result of all this is that single keypresses or wheel flicks will
+ // scroll in the same time period as single presses of scrollbar elements;
+ // holding the mouse down on a scrollbar part will scroll as fast as
+ // possible without hitching; and other repeated scroll events will also
+ // scroll with the same time lag as holding down the mouse on a scrollbar
+ // part.
+ data->m_desiredVelocity = animationStep / ScrollbarTheme::nativeTheme()->autoscrollTimerDelay();
+
+ // If we're not already scrolling, start.
+ if (!alreadyAnimating)
+ animateScroll(data);
+ return true;
+}
+
+void ScrollAnimatorWin::setScrollPositionAndStopAnimation(ScrollbarOrientation orientation, float pos)
+{
+ PerAxisData* data = (orientation == HorizontalScrollbar) ? &m_horizontalData : &m_verticalData;
+ stopAnimationTimerIfNeeded(data);
+ *data->m_currentPos = pos;
+ data->m_desiredPos = pos;
+ data->m_currentVelocity = 0;
+ data->m_desiredVelocity = 0;
+}
+
+// static
+double ScrollAnimatorWin::accelerationTime()
+{
+ // We elect to use ScrollbarTheme::nativeTheme()->autoscrollTimerDelay() as
+ // the length of time we'll take to accelerate from 0 to our target
+ // velocity. Choosing a larger value would produce a more pronounced
+ // acceleration effect.
+ return ScrollbarTheme::nativeTheme()->autoscrollTimerDelay();
+}
+
+void ScrollAnimatorWin::animationTimerFired(Timer<ScrollAnimatorWin>* timer)
+{
+ animateScroll((timer == &m_horizontalData.m_animationTimer) ? &m_horizontalData : &m_verticalData);
+}
+
+void ScrollAnimatorWin::stopAnimationTimerIfNeeded(PerAxisData* data)
+{
+ if (data->m_animationTimer.isActive())
+ data->m_animationTimer.stop();
+}
+
+void ScrollAnimatorWin::animateScroll(PerAxisData* data)
+{
+ // Note on smooth scrolling perf versus non-smooth scrolling perf:
+ // The total time to perform a complete scroll is given by
+ // t = t0 + 0.5tA - tD + tS
+ // Where
+ // t0 = The time to perform the scroll without smooth scrolling
+ // tA = The acceleration time,
+ // ScrollbarTheme::nativeTheme()->autoscrollTimerDelay() (see below)
+ // tD = |animationTimerDelay|
+ // tS = A value less than or equal to the time required to perform a
+ // single scroll increment, i.e. the work done due to calling
+ // client()->valueChanged() (~0 for simple pages, larger for complex
+ // pages).
+ //
+ // Because tA and tD are fairly small, the total lag (as users perceive it)
+ // is negligible for simple pages and roughly tS for complex pages. Without
+ // knowing in advance how large tS is it's hard to do better than this.
+ // Perhaps we could try to remember previous values and forward-compensate.
+
+
+ // We want to update the scroll position based on the time it's been since
+ // our last update. This may be longer than our ideal time, especially if
+ // the page is complex or the system is slow.
+ //
+ // To avoid feeling laggy, if we've just started smooth scrolling we pretend
+ // we've already accelerated for one ideal interval, so that we'll scroll at
+ // least some distance immediately.
+ double lastScrollInterval = data->m_currentVelocity ? (WTF::currentTime() - data->m_lastAnimationTime) : animationTimerDelay;
+
+ // Figure out how far we've actually traveled and update our current
+ // velocity.
+ float distanceTraveled;
+ if (data->m_currentVelocity < data->m_desiredVelocity) {
+ // We accelerate at a constant rate until we reach the desired velocity.
+ float accelerationRate = data->m_desiredVelocity / accelerationTime();
+
+ // Figure out whether contant acceleration has caused us to reach our
+ // target velocity.
+ float potentialVelocityChange = accelerationRate * lastScrollInterval;
+ float potentialNewVelocity = data->m_currentVelocity + potentialVelocityChange;
+ if (potentialNewVelocity > data->m_desiredVelocity) {
+ // We reached the target velocity at some point between our last
+ // update and now. The distance traveled can be calculated in two
+ // pieces: the distance traveled while accelerating, and the
+ // distance traveled after reaching the target velocity.
+ float actualVelocityChange = data->m_desiredVelocity - data->m_currentVelocity;
+ float accelerationInterval = actualVelocityChange / accelerationRate;
+ // The distance traveled under constant acceleration is the area
+ // under a line segment with a constant rising slope. Break this
+ // into a triangular portion atop a rectangular portion and sum.
+ distanceTraveled = ((data->m_currentVelocity + (actualVelocityChange / 2)) * accelerationInterval);
+ // The distance traveled at the target velocity is simply
+ // (target velocity) * (remaining time after accelerating).
+ distanceTraveled += (data->m_desiredVelocity * (lastScrollInterval - accelerationInterval));
+ data->m_currentVelocity = data->m_desiredVelocity;
+ } else {
+ // Constant acceleration through the entire time interval.
+ distanceTraveled = (data->m_currentVelocity + (potentialVelocityChange / 2)) * lastScrollInterval;
+ data->m_currentVelocity = potentialNewVelocity;
+ }
+ } else {
+ // We've already reached the target velocity, so the distance we've
+ // traveled is simply (current velocity) * (elapsed time).
+ distanceTraveled = data->m_currentVelocity * lastScrollInterval;
+ // If our desired velocity has decreased, drop the current velocity too.
+ data->m_currentVelocity = data->m_desiredVelocity;
+ }
+
+ // Now update the scroll position based on the distance traveled.
+ if (distanceTraveled >= abs(data->m_desiredPos - *data->m_currentPos)) {
+ // We've traveled far enough to reach the desired position. Stop smooth
+ // scrolling.
+ *data->m_currentPos = data->m_desiredPos;
+ data->m_currentVelocity = 0;
+ data->m_desiredVelocity = 0;
+ } else {
+ // Not yet at the target position. Travel towards it and set up the
+ // next update.
+ if (*data->m_currentPos > data->m_desiredPos)
+ distanceTraveled = -distanceTraveled;
+ *data->m_currentPos += distanceTraveled;
+ data->m_animationTimer.startOneShot(animationTimerDelay);
+ data->m_lastAnimationTime = WTF::currentTime();
+ }
+ m_client->setScrollOffsetFromAnimation(IntPoint(*m_horizontalData.m_currentPos, *m_verticalData.m_currentPos));
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/ScrollAnimatorWin.h b/WebCore/platform/ScrollAnimatorWin.h
new file mode 100644
index 0000000..002a454
--- /dev/null
+++ b/WebCore/platform/ScrollAnimatorWin.h
@@ -0,0 +1,71 @@
+/*
+ * 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 ScrollAnimatorWin_h
+#define ScrollAnimatorWin_h
+
+#include "ScrollAnimator.h"
+#include "Timer.h"
+
+namespace WebCore {
+
+class ScrollAnimatorWin : public ScrollAnimator {
+public:
+ ScrollAnimatorWin(ScrollbarClient*);
+ virtual ~ScrollAnimatorWin();
+
+ virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier);
+ virtual void setScrollPositionAndStopAnimation(ScrollbarOrientation, float);
+
+private:
+ struct PerAxisData {
+ PerAxisData(ScrollAnimatorWin* parent, float* currentPos);
+
+ float* m_currentPos;
+ float m_desiredPos;
+ float m_currentVelocity;
+ float m_desiredVelocity;
+ double m_lastAnimationTime;
+ Timer<ScrollAnimatorWin> m_animationTimer;
+ };
+
+ static double accelerationTime();
+ static const double animationTimerDelay;
+
+ void animationTimerFired(Timer<ScrollAnimatorWin>*);
+ void stopAnimationTimerIfNeeded(PerAxisData*);
+ void animateScroll(PerAxisData*);
+
+ PerAxisData m_horizontalData;
+ PerAxisData m_verticalData;
+};
+
+}
+#endif
diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp
index 854fef5..43badd0 100644
--- a/WebCore/platform/ScrollView.cpp
+++ b/WebCore/platform/ScrollView.cpp
@@ -303,6 +303,20 @@ IntPoint ScrollView::maximumScrollPosition() const
return IntPoint(maximumOffset.width(), maximumOffset.height());
}
+int ScrollView::scrollSize(ScrollbarOrientation orientation) const
+{
+ Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
+ return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
+}
+
+void ScrollView::setScrollOffsetFromAnimation(const IntPoint& offset)
+{
+ if (m_horizontalScrollbar)
+ m_horizontalScrollbar->setValue(offset.x(), Scrollbar::FromScrollAnimator);
+ if (m_verticalScrollbar)
+ m_verticalScrollbar->setValue(offset.y(), Scrollbar::FromScrollAnimator);
+}
+
void ScrollView::valueChanged(Scrollbar* scrollbar)
{
// Figure out if we really moved.
@@ -471,7 +485,7 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset)
m_horizontalScrollbar->setSuppressInvalidation(true);
m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
- m_horizontalScrollbar->setValue(scroll.width());
+ m_horizontalScrollbar->setValue(scroll.width(), Scrollbar::NotFromScrollAnimator);
if (m_scrollbarsSuppressed)
m_horizontalScrollbar->setSuppressInvalidation(false);
}
@@ -493,7 +507,7 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset)
m_verticalScrollbar->setSuppressInvalidation(true);
m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
- m_verticalScrollbar->setValue(scroll.height());
+ m_verticalScrollbar->setValue(scroll.height(), Scrollbar::NotFromScrollAnimator);
if (m_scrollbarsSuppressed)
m_verticalScrollbar->setSuppressInvalidation(false);
}
@@ -703,7 +717,12 @@ void ScrollView::wheelEvent(PlatformWheelEvent& e)
if (negative)
deltaY = -deltaY;
}
- scrollBy(IntSize(-deltaX, -deltaY));
+
+ // Should we fall back on scrollBy() if there is no scrollbar for a non-zero delta?
+ if (deltaY && m_verticalScrollbar)
+ m_verticalScrollbar->scroll(ScrollUp, ScrollByPixel, deltaY);
+ if (deltaX && m_horizontalScrollbar)
+ m_horizontalScrollbar->scroll(ScrollLeft, ScrollByPixel, deltaX);
}
}
diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h
index 5624d70..a55fed4 100644
--- a/WebCore/platform/ScrollView.h
+++ b/WebCore/platform/ScrollView.h
@@ -40,6 +40,7 @@
#endif
#if PLATFORM(GTK)
+#include "GRefPtrGtk.h"
typedef struct _GtkAdjustment GtkAdjustment;
#endif
@@ -57,7 +58,9 @@ class ScrollView : public Widget, public ScrollbarClient {
public:
~ScrollView();
- // ScrollbarClient function. FrameView overrides the others.
+ // ScrollbarClient functions. FrameView overrides the others.
+ virtual int scrollSize(ScrollbarOrientation orientation) const;
+ virtual void setScrollOffsetFromAnimation(const IntPoint&);
virtual void valueChanged(Scrollbar*);
// The window thats hosts the ScrollView. The ScrollView will communicate scrolls and repaints to the
@@ -347,9 +350,11 @@ private:
#if PLATFORM(GTK)
public:
void setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj, bool resetValues = true);
- GtkAdjustment* m_horizontalAdjustment;
- GtkAdjustment* m_verticalAdjustment;
void setScrollOffset(const IntSize& offset) { m_scrollOffset = offset; }
+
+private:
+ PlatformRefPtr<GtkAdjustment> m_horizontalAdjustment;
+ PlatformRefPtr<GtkAdjustment> m_verticalAdjustment;
#endif
#if PLATFORM(WX)
diff --git a/WebCore/platform/Scrollbar.cpp b/WebCore/platform/Scrollbar.cpp
index ff8f66f..398584a 100644
--- a/WebCore/platform/Scrollbar.cpp
+++ b/WebCore/platform/Scrollbar.cpp
@@ -40,7 +40,7 @@
using namespace std;
-#if PLATFORM(CHROMIUM) && OS(LINUX)
+#if PLATFORM(CHROMIUM) && OS(LINUX) || PLATFORM(GTK)
// The position of the scrollbar thumb affects the appearance of the steppers, so
// when the thumb moves, we have to invalidate them for painting.
#define THUMB_POSITION_AFFECTS_BUTTONS
@@ -48,7 +48,7 @@ using namespace std;
namespace WebCore {
-#if !PLATFORM(GTK) && !PLATFORM(EFL)
+#if !PLATFORM(EFL)
PassRefPtr<Scrollbar> Scrollbar::createNativeScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
{
return adoptRef(new Scrollbar(client, orientation, size));
@@ -101,12 +101,12 @@ Scrollbar::~Scrollbar()
m_theme->unregisterScrollbar(this);
}
-bool Scrollbar::setValue(int v)
+bool Scrollbar::setValue(int v, ScrollSource source)
{
v = max(min(v, m_totalSize - m_visibleSize), 0);
if (value() == v)
return false; // Our value stayed the same.
- setCurrentPos(v);
+ setCurrentPos(v, source);
return true;
}
@@ -154,8 +154,10 @@ bool Scrollbar::scroll(ScrollDirection direction, ScrollGranularity granularity,
}
if (direction == ScrollUp || direction == ScrollLeft)
multiplier = -multiplier;
+ if (client())
+ return client()->scroll(m_orientation, granularity, step, multiplier);
- return setCurrentPos(max(min(m_currentPos + (step * multiplier), static_cast<float>(m_totalSize - m_visibleSize)), 0.0f));
+ return setCurrentPos(max(min(m_currentPos + (step * multiplier), static_cast<float>(m_totalSize - m_visibleSize)), 0.0f), NotFromScrollAnimator);
}
void Scrollbar::updateThumb()
@@ -287,11 +289,14 @@ void Scrollbar::moveThumb(int pos)
else if (delta < 0)
delta = max(-thumbPos, delta);
if (delta)
- setCurrentPos(static_cast<float>(thumbPos + delta) * maximum() / (trackLen - thumbLen));
+ setCurrentPos(static_cast<float>(thumbPos + delta) * maximum() / (trackLen - thumbLen), NotFromScrollAnimator);
}
-bool Scrollbar::setCurrentPos(float pos)
+bool Scrollbar::setCurrentPos(float pos, ScrollSource source)
{
+ if ((source != FromScrollAnimator) && client())
+ client()->setScrollPositionAndStopAnimation(m_orientation, pos);
+
if (pos == m_currentPos)
return false;
@@ -336,7 +341,7 @@ bool Scrollbar::mouseMoved(const PlatformMouseEvent& evt)
{
if (m_pressedPart == ThumbPart) {
if (theme()->shouldSnapBackToDragOrigin(this, evt))
- setCurrentPos(m_dragOrigin);
+ setCurrentPos(m_dragOrigin, NotFromScrollAnimator);
else {
moveThumb(m_orientation == HorizontalScrollbar ?
convertFromContainingWindow(evt.pos()).x() :
diff --git a/WebCore/platform/Scrollbar.h b/WebCore/platform/Scrollbar.h
index f8ef96d..276bf60 100644
--- a/WebCore/platform/Scrollbar.h
+++ b/WebCore/platform/Scrollbar.h
@@ -42,6 +42,11 @@ class PlatformMouseEvent;
class Scrollbar : public Widget {
public:
+ enum ScrollSource {
+ FromScrollAnimator,
+ NotFromScrollAnimator,
+ };
+
virtual ~Scrollbar();
// Must be implemented by platforms that can't simply use the Scrollbar base class. Right now the only platform that is not using the base class is GTK.
@@ -75,7 +80,7 @@ public:
virtual void setPressedPart(ScrollbarPart);
void setSteps(int lineStep, int pageStep, int pixelsPerStep = 1);
- bool setValue(int);
+ bool setValue(int, ScrollSource source);
void setProportion(int visibleSize, int totalSize);
void setPressedPos(int p) { m_pressedPos = p; }
@@ -167,7 +172,7 @@ protected:
private:
virtual bool isScrollbar() const { return true; }
- bool setCurrentPos(float pos);
+ bool setCurrentPos(float pos, ScrollSource source);
};
}
diff --git a/WebCore/platform/ScrollbarClient.cpp b/WebCore/platform/ScrollbarClient.cpp
new file mode 100644
index 0000000..2f81a93
--- /dev/null
+++ b/WebCore/platform/ScrollbarClient.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "ScrollbarClient.h"
+
+#include "ScrollAnimator.h"
+
+namespace WebCore {
+
+ScrollbarClient::ScrollbarClient()
+ : m_scrollAnimator(ScrollAnimator::create(this))
+{
+}
+
+ScrollbarClient::~ScrollbarClient()
+{
+}
+
+bool ScrollbarClient::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier)
+{
+ return m_scrollAnimator->scroll(orientation, granularity, step, multiplier);
+}
+
+void ScrollbarClient::setScrollPositionAndStopAnimation(ScrollbarOrientation orientation, float pos)
+{
+ m_scrollAnimator->setScrollPositionAndStopAnimation(orientation, pos);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/ScrollbarClient.h b/WebCore/platform/ScrollbarClient.h
index fa94ecc..ab3b10e 100644
--- a/WebCore/platform/ScrollbarClient.h
+++ b/WebCore/platform/ScrollbarClient.h
@@ -26,21 +26,28 @@
#ifndef ScrollbarClient_h
#define ScrollbarClient_h
+#include "IntPoint.h"
#include "IntRect.h"
#include "Scrollbar.h"
#include <wtf/Vector.h>
namespace WebCore {
+class ScrollAnimator;
+
class ScrollbarClient {
public:
- virtual ~ScrollbarClient() { }
- virtual void valueChanged(Scrollbar*) = 0;
+ ScrollbarClient();
+ virtual ~ScrollbarClient();
- virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&) = 0;
+ bool scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier);
+ void setScrollPositionAndStopAnimation(ScrollbarOrientation orientation, float pos);
+ virtual int scrollSize(ScrollbarOrientation orientation) const = 0;
+ virtual void setScrollOffsetFromAnimation(const IntPoint&) = 0;
+ virtual void valueChanged(Scrollbar*) = 0;
+ virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&) = 0;
virtual bool isActive() const = 0;
-
virtual bool scrollbarCornerPresent() const = 0;
virtual void getTickmarks(Vector<IntRect>&) const { }
@@ -52,21 +59,21 @@ public:
{
return scrollbar->Widget::convertToContainingView(scrollbarRect);
}
-
virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
{
return scrollbar->Widget::convertFromContainingView(parentRect);
}
-
virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
{
return scrollbar->Widget::convertToContainingView(scrollbarPoint);
}
-
virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
{
return scrollbar->Widget::convertFromContainingView(parentPoint);
}
+
+private:
+ OwnPtr<ScrollAnimator> m_scrollAnimator;
};
}
diff --git a/WebCore/platform/ScrollbarThemeComposite.cpp b/WebCore/platform/ScrollbarThemeComposite.cpp
index d28e1c3..fdac14d 100644
--- a/WebCore/platform/ScrollbarThemeComposite.cpp
+++ b/WebCore/platform/ScrollbarThemeComposite.cpp
@@ -296,10 +296,9 @@ void ScrollbarThemeComposite::paintScrollCorner(ScrollView* view, GraphicsContex
{
FrameView* frameView = static_cast<FrameView*>(view);
Page* page = frameView->frame() ? frameView->frame()->page() : 0;
- if (page && page->settings()->shouldPaintCustomScrollbars()) {
- if (!page->chrome()->client()->paintCustomScrollCorner(context, cornerRect))
- context->fillRect(cornerRect, Color::white, DeviceColorSpace);
- }
+ if (page && page->settings()->shouldPaintCustomScrollbars() && page->chrome()->client()->paintCustomScrollCorner(context, cornerRect))
+ return;
+ context->fillRect(cornerRect, Color::white, DeviceColorSpace);
}
}
diff --git a/WebCore/platform/UUID.cpp b/WebCore/platform/UUID.cpp
index 852e3ae..fdbf601 100644
--- a/WebCore/platform/UUID.cpp
+++ b/WebCore/platform/UUID.cpp
@@ -84,10 +84,11 @@ String createCanonicalUUIDString()
FILE* fptr = fopen("/proc/sys/kernel/random/uuid", "r");
if (!fptr)
return String();
- char uuidStr[37] = {0};
- if (!fgets(uuidStr, sizeof(uuidStr) - 1, fptr))
- return String();
+ char uuidStr[37];
+ char* result = fgets(uuidStr, sizeof(uuidStr), fptr);
fclose(fptr);
+ if (!result)
+ return String();
String canonicalUuidStr = String(uuidStr).lower(); // make it lower.
ASSERT(canonicalUuidStr[uuidVersionIdentifierIndex] == uuidVersionRequired);
return canonicalUuidStr;
diff --git a/WebCore/platform/android/TemporaryLinkStubs.cpp b/WebCore/platform/android/TemporaryLinkStubs.cpp
index bedb91b..3c5c8b4 100644
--- a/WebCore/platform/android/TemporaryLinkStubs.cpp
+++ b/WebCore/platform/android/TemporaryLinkStubs.cpp
@@ -104,7 +104,7 @@ namespace WebCore {
// This function tells the bridge that a resource was loaded from the cache and thus
// the app may update progress with the amount of data loaded.
-void CheckCacheObjectStatus(DocLoader*, CachedResource*)
+void CheckCacheObjectStatus(CachedResourceLoader*, CachedResource*)
{
ASSERT_NOT_REACHED();
notImplemented();
diff --git a/WebCore/platform/animation/Animation.cpp b/WebCore/platform/animation/Animation.cpp
index bc33a9e..112ee36 100644
--- a/WebCore/platform/animation/Animation.cpp
+++ b/WebCore/platform/animation/Animation.cpp
@@ -106,23 +106,23 @@ bool Animation::animationsMatch(const Animation* o, bool matchPlayStates) const
if (!o)
return false;
- bool result = m_name == o->m_name &&
- m_property == o->m_property &&
- m_iterationCount == o->m_iterationCount &&
- m_delay == o->m_delay &&
- m_duration == o->m_duration &&
- m_timingFunction == o->m_timingFunction &&
- m_direction == o->m_direction &&
- m_fillMode == o->m_fillMode &&
- m_delaySet == o->m_delaySet &&
- m_directionSet == o->m_directionSet &&
- m_durationSet == o->m_durationSet &&
- m_fillModeSet == o->m_fillModeSet &&
- m_iterationCountSet == o->m_iterationCountSet &&
- m_nameSet == o->m_nameSet &&
- m_propertySet == o->m_propertySet &&
- m_timingFunctionSet == o->m_timingFunctionSet &&
- m_isNone == o->m_isNone;
+ bool result = m_name == o->m_name
+ && m_property == o->m_property
+ && m_iterationCount == o->m_iterationCount
+ && m_delay == o->m_delay
+ && m_duration == o->m_duration
+ && *(m_timingFunction.get()) == *(o->m_timingFunction.get())
+ && m_direction == o->m_direction
+ && m_fillMode == o->m_fillMode
+ && m_delaySet == o->m_delaySet
+ && m_directionSet == o->m_directionSet
+ && m_durationSet == o->m_durationSet
+ && m_fillModeSet == o->m_fillModeSet
+ && m_iterationCountSet == o->m_iterationCountSet
+ && m_nameSet == o->m_nameSet
+ && m_propertySet == o->m_propertySet
+ && m_timingFunctionSet == o->m_timingFunctionSet
+ && m_isNone == o->m_isNone;
if (!result)
return false;
diff --git a/WebCore/platform/animation/Animation.h b/WebCore/platform/animation/Animation.h
index cabb0eb..9130415 100644
--- a/WebCore/platform/animation/Animation.h
+++ b/WebCore/platform/animation/Animation.h
@@ -26,6 +26,7 @@
#define Animation_h
#include "PlatformString.h"
+#include "RenderStyleConstants.h"
#include "TimingFunction.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -94,7 +95,7 @@ public:
const String& name() const { return m_name; }
unsigned playState() const { return m_playState; }
int property() const { return m_property; }
- const TimingFunction& timingFunction() const { return m_timingFunction; }
+ const PassRefPtr<TimingFunction> timingFunction() const { return m_timingFunction; }
void setDelay(double c) { m_delay = c; m_delaySet = true; }
void setDirection(AnimationDirection d) { m_direction = d; m_directionSet = true; }
@@ -104,7 +105,7 @@ public:
void setName(const String& n) { m_name = n; m_nameSet = true; }
void setPlayState(unsigned d) { m_playState = d; m_playStateSet = true; }
void setProperty(int t) { m_property = t; m_propertySet = true; }
- void setTimingFunction(const TimingFunction& f) { m_timingFunction = f; m_timingFunctionSet = true; }
+ void setTimingFunction(PassRefPtr<TimingFunction> f) { m_timingFunction = f; m_timingFunctionSet = true; }
void setIsNoneAnimation(bool n) { m_isNone = n; }
@@ -129,7 +130,7 @@ private:
int m_iterationCount;
double m_delay;
double m_duration;
- TimingFunction m_timingFunction;
+ RefPtr<TimingFunction> m_timingFunction;
AnimationDirection m_direction : 1;
unsigned m_fillMode : 2;
@@ -156,7 +157,7 @@ public:
static String initialAnimationName() { return String("none"); }
static unsigned initialAnimationPlayState() { return AnimPlayStatePlaying; }
static int initialAnimationProperty() { return cAnimateAll; }
- static TimingFunction initialAnimationTimingFunction() { return TimingFunction(); }
+ static PassRefPtr<TimingFunction> initialAnimationTimingFunction() { return CubicBezierTimingFunction::create(); }
};
} // namespace WebCore
diff --git a/WebCore/platform/animation/TimingFunction.h b/WebCore/platform/animation/TimingFunction.h
index d3f71ff..8ef2d8f 100644
--- a/WebCore/platform/animation/TimingFunction.h
+++ b/WebCore/platform/animation/TimingFunction.h
@@ -25,53 +25,87 @@
#ifndef TimingFunction_h
#define TimingFunction_h
-#include "RenderStyleConstants.h"
+#include <wtf/RefCounted.h>
namespace WebCore {
-struct TimingFunction : FastAllocBase {
- TimingFunction()
- : m_type(CubicBezierTimingFunction)
- , m_x1(0.25)
- , m_y1(0.1)
- , m_x2(0.25)
- , m_y2(1.0)
+class TimingFunction : public RefCounted<TimingFunction> {
+public:
+
+ enum TimingFunctionType {
+ LinearFunction, CubicBezierFunction, StepsFunction
+ };
+
+ virtual ~TimingFunction() { }
+
+ bool isLinearTimingFunction() const { return m_type == LinearFunction; }
+ bool isCubicBezierTimingFunction() const { return m_type == CubicBezierFunction; }
+ bool isStepsTimingFunction() const { return m_type == StepsFunction; }
+
+ virtual bool operator==(const TimingFunction& other) = 0;
+
+protected:
+ TimingFunction(TimingFunctionType type)
+ : m_type(type)
{
}
+
+ TimingFunctionType m_type;
+};
- // This explicit copy constructor works around an inlining bug in GCC 4.2 (only reproed on mac, but may exist on other platforms).
- TimingFunction(const TimingFunction& that)
- : m_type(that.m_type)
- , m_x1(that.m_x1)
- , m_y1(that.m_y1)
- , m_x2(that.m_x2)
- , m_y2(that.m_y2)
+class LinearTimingFunction : public TimingFunction {
+public:
+ static PassRefPtr<LinearTimingFunction> create()
{
+ return adoptRef(new LinearTimingFunction);
}
-
- TimingFunction(ETimingFunctionType timingFunction, double x1 = 0.0, double y1 = 0.0, double x2 = 1.0, double y2 = 1.0)
- : m_type(timingFunction)
- , m_x1(x1)
- , m_y1(y1)
- , m_x2(x2)
- , m_y2(y2)
+
+ ~LinearTimingFunction() { }
+
+ virtual bool operator==(const TimingFunction& other)
{
+ return other.isLinearTimingFunction();
+ }
+
+private:
+ LinearTimingFunction()
+ : TimingFunction(LinearFunction)
+ {
+ }
+};
+
+class CubicBezierTimingFunction : public TimingFunction {
+public:
+ static PassRefPtr<CubicBezierTimingFunction> create(double x1 = 0.25, double y1 = 0.1, double x2 = 0.25, double y2 = 1.0)
+ {
+ return adoptRef(new CubicBezierTimingFunction(x1, y1, x2, y2));
}
- bool operator==(const TimingFunction& o) const
+ ~CubicBezierTimingFunction() { }
+
+ virtual bool operator==(const TimingFunction& other)
{
- return m_type == o.m_type && m_x1 == o.m_x1 && m_y1 == o.m_y1 && m_x2 == o.m_x2 && m_y2 == o.m_y2;
+ if (other.isCubicBezierTimingFunction()) {
+ const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(&other);
+ return m_x1 == ctf->m_x1 && m_y1 == ctf->m_y1 && m_x2 == ctf->m_x2 && m_y2 == ctf->m_y2;
+ }
+ return false;
}
double x1() const { return m_x1; }
double y1() const { return m_y1; }
double x2() const { return m_x2; }
double y2() const { return m_y2; }
-
- ETimingFunctionType type() const { return m_type; }
-
+
private:
- ETimingFunctionType m_type;
+ CubicBezierTimingFunction(double x1, double y1, double x2, double y2)
+ : TimingFunction(CubicBezierFunction)
+ , m_x1(x1)
+ , m_y1(y1)
+ , m_x2(x2)
+ , m_y2(y2)
+ {
+ }
double m_x1;
double m_y1;
@@ -79,6 +113,39 @@ private:
double m_y2;
};
+class StepsTimingFunction : public TimingFunction {
+public:
+ static PassRefPtr<StepsTimingFunction> create(int steps, bool stepAtStart)
+ {
+ return adoptRef(new StepsTimingFunction(steps, stepAtStart));
+ }
+
+ ~StepsTimingFunction() { }
+
+ virtual bool operator==(const TimingFunction& other)
+ {
+ if (other.isStepsTimingFunction()) {
+ const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(&other);
+ return m_steps == stf->m_steps && m_stepAtStart == stf->m_stepAtStart;
+ }
+ return false;
+ }
+
+ int numberOfSteps() const { return m_steps; }
+ bool stepAtStart() const { return m_stepAtStart; }
+
+private:
+ StepsTimingFunction(int steps, bool stepAtStart)
+ : TimingFunction(StepsFunction)
+ , m_steps(steps)
+ , m_stepAtStart(stepAtStart)
+ {
+ }
+
+ int m_steps;
+ bool m_stepAtStart;
+};
+
} // namespace WebCore
#endif // TimingFunction_h
diff --git a/WebCore/platform/audio/AudioArray.h b/WebCore/platform/audio/AudioArray.h
new file mode 100644
index 0000000..9c25b0f
--- /dev/null
+++ b/WebCore/platform/audio/AudioArray.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AudioArray_h
+#define AudioArray_h
+
+#include <string.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+template<typename T>
+class AudioArray : public Vector<T> {
+public:
+ AudioArray() : Vector<T>(0) { }
+ explicit AudioArray(size_t n) : Vector<T>(n, 0) { }
+
+ void zero() { memset(this->data(), 0, sizeof(T) * this->size()); }
+
+ void zeroRange(unsigned start, unsigned end)
+ {
+ bool isSafe = (start <= end) && (end <= this->size());
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ memset(this->data() + start, 0, sizeof(T) * (end - start));
+ }
+
+ void copyToRange(T* sourceData, unsigned start, unsigned end)
+ {
+ bool isSafe = (start <= end) && (end <= this->size());
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ memcpy(this->data() + start, sourceData, sizeof(T) * (end - start));
+ }
+};
+
+typedef AudioArray<float> AudioFloatArray;
+typedef AudioArray<double> AudioDoubleArray;
+
+} // WebCore
+
+#endif // AudioArray_h
diff --git a/WebCore/platform/audio/AudioBus.cpp b/WebCore/platform/audio/AudioBus.cpp
new file mode 100644
index 0000000..6b7ec3f
--- /dev/null
+++ b/WebCore/platform/audio/AudioBus.cpp
@@ -0,0 +1,363 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioBus.h"
+
+#include "Accelerate.h"
+#include <algorithm>
+#include <assert.h>
+#include <math.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+AudioBus::AudioBus(unsigned numberOfChannels, size_t length, bool allocate)
+ : m_length(length)
+ , m_busGain(1.0)
+ , m_isFirstTime(true)
+ , m_sampleRate(0.0)
+{
+ m_channels.reserveInitialCapacity(numberOfChannels);
+
+ for (unsigned i = 0; i < numberOfChannels; ++i) {
+ PassOwnPtr<AudioChannel> channel = allocate ? adoptPtr(new AudioChannel(length)) : adoptPtr(new AudioChannel(0, length));
+ m_channels.append(channel);
+ }
+
+ m_layout = LayoutCanonical; // for now this is the only layout we define
+}
+
+void AudioBus::setChannelMemory(unsigned channelIndex, float* storage, size_t length)
+{
+ if (channelIndex < m_channels.size()) {
+ channel(channelIndex)->set(storage, length);
+ m_length = length; // FIXME: verify that this length matches all the other channel lengths
+ }
+}
+
+void AudioBus::zero()
+{
+ for (unsigned i = 0; i < m_channels.size(); ++i)
+ m_channels[i]->zero();
+}
+
+AudioChannel* AudioBus::channelByType(unsigned channelType)
+{
+ // For now we only support canonical channel layouts...
+ if (m_layout != LayoutCanonical)
+ return 0;
+
+ switch (numberOfChannels()) {
+ case 1: // mono
+ if (channelType == ChannelMono || channelType == ChannelLeft)
+ return channel(0);
+ return 0;
+
+ case 2: // stereo
+ switch (channelType) {
+ case ChannelLeft: return channel(0);
+ case ChannelRight: return channel(1);
+ default: return 0;
+ }
+
+ case 4: // quad
+ switch (channelType) {
+ case ChannelLeft: return channel(0);
+ case ChannelRight: return channel(1);
+ case ChannelSurroundLeft: return channel(2);
+ case ChannelSurroundRight: return channel(3);
+ default: return 0;
+ }
+
+ case 5: // 5.0
+ switch (channelType) {
+ case ChannelLeft: return channel(0);
+ case ChannelRight: return channel(1);
+ case ChannelCenter: return channel(2);
+ case ChannelSurroundLeft: return channel(3);
+ case ChannelSurroundRight: return channel(4);
+ default: return 0;
+ }
+
+ case 6: // 5.1
+ switch (channelType) {
+ case ChannelLeft: return channel(0);
+ case ChannelRight: return channel(1);
+ case ChannelCenter: return channel(2);
+ case ChannelLFE: return channel(3);
+ case ChannelSurroundLeft: return channel(4);
+ case ChannelSurroundRight: return channel(5);
+ default: return 0;
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+// Returns true if the channel count and frame-size match.
+bool AudioBus::topologyMatches(const AudioBus& bus) const
+{
+ if (numberOfChannels() != bus.numberOfChannels())
+ return false; // channel mismatch
+
+ // Make sure source bus has enough frames.
+ if (length() > bus.length())
+ return false; // frame-size mismatch
+
+ return true;
+}
+
+PassOwnPtr<AudioBus> AudioBus::createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame)
+{
+ size_t numberOfSourceFrames = sourceBuffer->length();
+ unsigned numberOfChannels = sourceBuffer->numberOfChannels();
+
+ // Sanity checking
+ bool isRangeSafe = startFrame < endFrame && endFrame <= numberOfSourceFrames;
+ ASSERT(isRangeSafe);
+ if (!isRangeSafe)
+ return 0;
+
+ size_t rangeLength = endFrame - startFrame;
+
+ OwnPtr<AudioBus> audioBus = adoptPtr(new AudioBus(numberOfChannels, rangeLength));
+ audioBus->setSampleRate(sourceBuffer->sampleRate());
+
+ for (unsigned i = 0; i < numberOfChannels; ++i)
+ audioBus->channel(i)->copyFromRange(sourceBuffer->channel(i), startFrame, endFrame);
+
+ return audioBus.release();
+}
+
+float AudioBus::maxAbsValue() const
+{
+ float max = 0.0f;
+ for (unsigned i = 0; i < numberOfChannels(); ++i) {
+ const AudioChannel* channel = this->channel(i);
+ max = std::max(max, channel->maxAbsValue());
+ }
+
+ return max;
+}
+
+void AudioBus::normalize()
+{
+ float max = maxAbsValue();
+ if (max)
+ scale(1.0f / max);
+}
+
+void AudioBus::scale(double scale)
+{
+ for (unsigned i = 0; i < numberOfChannels(); ++i)
+ channel(i)->scale(scale);
+}
+
+// Just copies the samples from the source bus to this one.
+// This is just a simple copy if the number of channels match, otherwise a mixup or mixdown is done.
+// For now, we just support a mixup from mono -> stereo.
+void AudioBus::copyFrom(const AudioBus& sourceBus)
+{
+ if (&sourceBus == this)
+ return;
+
+ if (numberOfChannels() == sourceBus.numberOfChannels()) {
+ for (unsigned i = 0; i < numberOfChannels(); ++i)
+ channel(i)->copyFrom(sourceBus.channel(i));
+ } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
+ // Handle mono -> stereo case (for now simply copy mono channel into both left and right)
+ // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
+ const AudioChannel* sourceChannel = sourceBus.channel(0);
+ channel(0)->copyFrom(sourceChannel);
+ channel(1)->copyFrom(sourceChannel);
+ } else {
+ // Case not handled
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void AudioBus::sumFrom(const AudioBus &sourceBus)
+{
+ if (numberOfChannels() == sourceBus.numberOfChannels()) {
+ for (unsigned i = 0; i < numberOfChannels(); ++i)
+ channel(i)->sumFrom(sourceBus.channel(i));
+ } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
+ // Handle mono -> stereo case (for now simply sum mono channel into both left and right)
+ // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
+ const AudioChannel* sourceChannel = sourceBus.channel(0);
+ channel(0)->sumFrom(sourceChannel);
+ channel(1)->sumFrom(sourceChannel);
+ } else {
+ // Case not handled
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void AudioBus::processWithGainFromMonoStereo(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus)
+{
+ // We don't want to suddenly change the gain from mixing one time slice to the next,
+ // so we "de-zipper" by slowly changing the gain each sample-frame until we've achieved the target gain.
+
+ // FIXME: optimize this method (SSE, etc.)
+ // FIXME: Need fast path here when gain has converged on targetGain. In this case, de-zippering is no longer needed.
+ // FIXME: Need fast path when this==sourceBus && lastMixGain==targetGain==1.0 && sumToBus==false (this is a NOP)
+
+ // Take master bus gain into account as well as the targetGain.
+ double totalDesiredGain = m_busGain * targetGain;
+
+ // First time, snap directly to totalDesiredGain.
+ double gain = m_isFirstTime ? totalDesiredGain : *lastMixGain;
+ m_isFirstTime = false;
+
+ int numberOfSourceChannels = sourceBus.numberOfChannels();
+ int numberOfDestinationChannels = numberOfChannels();
+
+ AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
+ const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
+ const float* sourceR = numberOfSourceChannels > 1 ? sourceBusSafe.channelByType(ChannelRight)->data() : 0;
+
+ float* destinationL = channelByType(ChannelLeft)->data();
+ float* destinationR = numberOfDestinationChannels > 1 ? channelByType(ChannelRight)->data() : 0;
+
+ const double DezipperRate = 0.005;
+ int framesToProcess = length();
+
+ if (sumToBus) {
+ // Sum to our bus
+ if (sourceR && destinationR) {
+ // Stereo
+ while (framesToProcess--) {
+ float sampleL = *sourceL++;
+ float sampleR = *sourceR++;
+ *destinationL++ += static_cast<float>(gain * sampleL);
+ *destinationR++ += static_cast<float>(gain * sampleR);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ } else if (destinationR) {
+ // Mono -> stereo (mix equally into L and R)
+ // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
+ while (framesToProcess--) {
+ float sample = *sourceL++;
+ *destinationL++ += static_cast<float>(gain * sample);
+ *destinationR++ += static_cast<float>(gain * sample);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ } else {
+ // Mono
+ while (framesToProcess--) {
+ float sampleL = *sourceL++;
+ *destinationL++ += static_cast<float>(gain * sampleL);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ }
+ } else {
+ // Process directly (without summing) to our bus
+ if (sourceR && destinationR) {
+ // Stereo
+ while (framesToProcess--) {
+ float sampleL = *sourceL++;
+ float sampleR = *sourceR++;
+ *destinationL++ = static_cast<float>(gain * sampleL);
+ *destinationR++ = static_cast<float>(gain * sampleR);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ } else if (destinationR) {
+ // Mono -> stereo (mix equally into L and R)
+ // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
+ while (framesToProcess--) {
+ float sample = *sourceL++;
+ *destinationL++ = static_cast<float>(gain * sample);
+ *destinationR++ = static_cast<float>(gain * sample);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ } else {
+ // Mono
+ while (framesToProcess--) {
+ float sampleL = *sourceL++;
+ *destinationL++ = static_cast<float>(gain * sampleL);
+
+ // Slowly change gain to desired gain.
+ gain += (totalDesiredGain - gain) * DezipperRate;
+ }
+ }
+ }
+
+ // Save the target gain as the starting point for next time around.
+ *lastMixGain = gain;
+}
+
+void AudioBus::processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus)
+{
+ // Make sure we're summing from same type of bus.
+ // We *are* able to sum from mono -> stereo
+ if (sourceBus.numberOfChannels() != 1 && !topologyMatches(sourceBus))
+ return;
+
+ // Dispatch for different channel layouts
+ switch (numberOfChannels()) {
+ case 1: // mono
+ case 2: // stereo
+ processWithGainFromMonoStereo(sourceBus, lastMixGain, targetGain, sumToBus);
+ break;
+ case 4: // FIXME: implement quad
+ case 5: // FIXME: implement 5.0
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
+{
+ processWithGainFrom(sourceBus, lastMixGain, targetGain, false);
+}
+
+void AudioBus::sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain)
+{
+ processWithGainFrom(sourceBus, lastMixGain, targetGain, true);
+}
+
+} // WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/AudioBus.h b/WebCore/platform/audio/AudioBus.h
new file mode 100644
index 0000000..72357e8
--- /dev/null
+++ b/WebCore/platform/audio/AudioBus.h
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AudioBus_h
+#define AudioBus_h
+
+#include "AudioChannel.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// An AudioBus represents a collection of one or more AudioChannels.
+// The data layout is "planar" as opposed to "interleaved".
+// An AudioBus with one channel is mono, an AudioBus with two channels is stereo, etc.
+class AudioBus : public Noncopyable {
+public:
+ enum {
+ ChannelLeft = 0,
+ ChannelRight = 1,
+ ChannelCenter = 2, // center and mono are the same
+ ChannelMono = 2,
+ ChannelLFE = 3,
+ ChannelSurroundLeft = 4,
+ ChannelSurroundRight = 5,
+ };
+
+ enum {
+ LayoutCanonical = 0
+ // Can define non-standard layouts here
+ };
+
+ // allocate indicates whether or not to initially have the AudioChannels created with managed storage.
+ // Normal usage is to pass true here, in which case the AudioChannels will memory-manage their own storage.
+ // If allocate is false then setChannelMemory() has to be called later on for each channel before the AudioBus is useable...
+ AudioBus(unsigned numberOfChannels, size_t length, bool allocate = true);
+
+ // Tells the given channel to use an externally allocated buffer.
+ void setChannelMemory(unsigned channelIndex, float* storage, size_t length);
+
+ // Channels
+ unsigned numberOfChannels() const { return m_channels.size(); }
+
+ AudioChannel* channel(unsigned channel) { return m_channels[channel].get(); }
+ const AudioChannel* channel(unsigned channel) const { return const_cast<AudioBus*>(this)->m_channels[channel].get(); }
+ AudioChannel* channelByType(unsigned type);
+
+ // Number of sample-frames
+ size_t length() const { return m_length; }
+
+ // Sample-rate : 0.0 if unknown or "don't care"
+ double sampleRate() const { return m_sampleRate; }
+ void setSampleRate(double sampleRate) { m_sampleRate = sampleRate; }
+
+ // Zeroes all channels.
+ void zero();
+
+ // Returns true if the channel count and frame-size match.
+ bool topologyMatches(const AudioBus &sourceBus) const;
+
+ // Creates a new buffer from a range in the source buffer.
+ // 0 may be returned if the range does not fit in the sourceBuffer
+ static PassOwnPtr<AudioBus> createBufferFromRange(AudioBus* sourceBuffer, unsigned startFrame, unsigned endFrame);
+
+ // Scales all samples by the same amount.
+ void scale(double scale);
+
+ // Master gain for this bus - used with sumWithGainFrom() below
+ void setGain(double gain) { m_busGain = gain; }
+ double gain() { return m_busGain; }
+
+ void reset() { m_isFirstTime = true; } // for de-zippering
+
+ // Assuming sourceBus has the same topology, copies sample data from each channel of sourceBus to our corresponding channel.
+ void copyFrom(const AudioBus &sourceBus);
+
+ // Sums the sourceBus into our bus with unity gain.
+ // Our own internal gain m_busGain is ignored.
+ void sumFrom(const AudioBus &sourceBus);
+
+ // Copy or sum each channel from sourceBus into our corresponding channel.
+ // We scale by targetGain (and our own internal gain m_busGain), performing "de-zippering" to smoothly change from *lastMixGain to (targetGain*m_busGain).
+ // The caller is responsible for setting up lastMixGain to point to storage which is unique for every "stream" which will be summed to this bus.
+ // This represents the dezippering memory.
+ void copyWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain);
+ void sumWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain);
+
+ // Returns maximum absolute value across all channels (useful for normalization).
+ float maxAbsValue() const;
+
+ // Makes maximum absolute value == 1.0 (if possible).
+ void normalize();
+
+protected:
+ AudioBus() { };
+
+ void processWithGainFrom(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus);
+ void processWithGainFromMonoStereo(const AudioBus &sourceBus, double* lastMixGain, double targetGain, bool sumToBus);
+
+ size_t m_length;
+
+ Vector<OwnPtr<AudioChannel> > m_channels;
+
+ int m_layout;
+
+ double m_busGain;
+ bool m_isFirstTime;
+ double m_sampleRate; // 0.0 if unknown or N/A
+};
+
+} // WebCore
+
+#endif // AudioBus_h
diff --git a/WebCore/platform/audio/AudioChannel.cpp b/WebCore/platform/audio/AudioChannel.cpp
new file mode 100644
index 0000000..ad38219
--- /dev/null
+++ b/WebCore/platform/audio/AudioChannel.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "AudioChannel.h"
+
+#include "Accelerate.h"
+#include <algorithm>
+#include <math.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+void AudioChannel::scale(double scale)
+{
+ float s = static_cast<float>(scale);
+ vsmul(data(), 1, &s, data(), 1, length());
+}
+
+void AudioChannel::copyFrom(const AudioChannel* sourceChannel)
+{
+ bool isSafe = (sourceChannel && sourceChannel->length() >= length());
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ memcpy(data(), sourceChannel->data(), sizeof(float) * length());
+}
+
+void AudioChannel::copyFromRange(const AudioChannel* sourceChannel, unsigned startFrame, unsigned endFrame)
+{
+ // Check that range is safe for reading from sourceChannel.
+ bool isRangeSafe = sourceChannel && startFrame < endFrame && endFrame <= sourceChannel->length();
+ ASSERT(isRangeSafe);
+ if (!isRangeSafe)
+ return;
+
+ // Check that this channel has enough space.
+ size_t rangeLength = endFrame - startFrame;
+ bool isRangeLengthSafe = rangeLength <= length();
+ ASSERT(isRangeLengthSafe);
+ if (!isRangeLengthSafe)
+ return;
+
+ const float* source = sourceChannel->data();
+ float* destination = data();
+ memcpy(destination, source + startFrame, sizeof(float) * rangeLength);
+}
+
+void AudioChannel::sumFrom(const AudioChannel* sourceChannel)
+{
+ bool isSafe = sourceChannel && sourceChannel->length() >= length();
+ ASSERT(isSafe);
+ if (!isSafe)
+ return;
+
+ vadd(data(), 1, sourceChannel->data(), 1, data(), 1, length());
+}
+
+float AudioChannel::maxAbsValue() const
+{
+ const float* p = data();
+ int n = length();
+
+ float max = 0.0f;
+ while (n--)
+ max = std::max(max, fabsf(*p++));
+
+ return max;
+}
+
+} // WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/AudioChannel.h b/WebCore/platform/audio/AudioChannel.h
new file mode 100644
index 0000000..511048c
--- /dev/null
+++ b/WebCore/platform/audio/AudioChannel.h
@@ -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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AudioChannel_h
+#define AudioChannel_h
+
+#include "AudioFloatArray.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+// An AudioChannel represents a buffer of non-interleaved floating-point audio samples.
+// The PCM samples are normally assumed to be in a nominal range -1.0 -> +1.0
+class AudioChannel : public Noncopyable {
+public:
+ // Memory can be externally referenced, or can be internally allocated with an AudioFloatArray.
+
+ // Reference an external buffer.
+ AudioChannel(float* storage, size_t length)
+ : m_length(length), m_rawPointer(storage) { }
+
+ // Manage storage for us.
+ explicit AudioChannel(size_t length)
+ : m_length(length)
+ , m_rawPointer(0)
+ {
+ m_memBuffer = adoptPtr(new AudioFloatArray(length));
+ }
+
+ // A "blank" audio channel -- must call set() before it's useful...
+ AudioChannel()
+ : m_length(0)
+ , m_rawPointer(0)
+ {
+ }
+
+ // Redefine the memory for this channel.
+ // storage represents external memory not managed by this object.
+ void set(float* storage, size_t length)
+ {
+ m_memBuffer.clear(); // cleanup managed storage
+ m_rawPointer = storage;
+ m_length = length;
+ }
+
+ // How many sample-frames do we contain?
+ size_t length() const { return m_length; }
+
+ // Direct access to PCM sample data
+ float* data() { return m_rawPointer ? m_rawPointer : m_memBuffer->data(); }
+ const float* data() const { return m_rawPointer ? m_rawPointer : m_memBuffer->data(); }
+
+ // Zeroes out all sample values in buffer.
+ void zero()
+ {
+ if (m_memBuffer.get())
+ m_memBuffer->zero();
+ else
+ memset(m_rawPointer, 0, sizeof(float) * m_length);
+ }
+
+ // Scales all samples by the same amount.
+ void scale(double scale);
+
+ // A simple memcpy() from the source channel
+ void copyFrom(const AudioChannel* sourceChannel);
+
+ // Copies the given range from the source channel.
+ void copyFromRange(const AudioChannel* sourceChannel, unsigned startFrame, unsigned endFrame);
+
+ // Sums (with unity gain) from the source channel.
+ void sumFrom(const AudioChannel* sourceChannel);
+
+ // Returns maximum absolute value (useful for normalization).
+ float maxAbsValue() const;
+
+private:
+ size_t m_length;
+
+ float* m_rawPointer;
+ OwnPtr<AudioFloatArray> m_memBuffer;
+};
+
+} // WebCore
+
+#endif // AudioChannel_h
diff --git a/WebCore/platform/audio/AudioDSPKernel.h b/WebCore/platform/audio/AudioDSPKernel.h
new file mode 100644
index 0000000..d9be6dc
--- /dev/null
+++ b/WebCore/platform/audio/AudioDSPKernel.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 AudioDSPKernel_h
+#define AudioDSPKernel_h
+
+#include "AudioDSPKernelProcessor.h"
+
+namespace WebCore {
+
+// AudioDSPKernel does the processing for one channel of an AudioDSPKernelProcessor.
+
+class AudioDSPKernel {
+public:
+ AudioDSPKernel(AudioDSPKernelProcessor* kernelProcessor)
+ : m_kernelProcessor(kernelProcessor)
+ {
+ }
+
+ virtual ~AudioDSPKernel() { };
+
+ // Subclasses must override process() to do the processing and reset() to reset DSP state.
+ virtual void process(const float* source, float* destination, size_t framesToProcess) = 0;
+ virtual void reset() = 0;
+
+ double sampleRate() const { return processor()->sampleRate(); }
+ double nyquist() const { return 0.5 * sampleRate(); }
+
+ AudioDSPKernelProcessor* processor() { return m_kernelProcessor; }
+ const AudioDSPKernelProcessor* processor() const { return m_kernelProcessor; }
+
+protected:
+ AudioDSPKernelProcessor* m_kernelProcessor;
+};
+
+} // namespace WebCore
+
+#endif // AudioDSPKernel_h
diff --git a/WebCore/platform/audio/AudioDSPKernelProcessor.cpp b/WebCore/platform/audio/AudioDSPKernelProcessor.cpp
new file mode 100644
index 0000000..d79afd5
--- /dev/null
+++ b/WebCore/platform/audio/AudioDSPKernelProcessor.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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 ENABLE(WEB_AUDIO)
+
+#include "AudioDSPKernelProcessor.h"
+
+#include "AudioDSPKernel.h"
+
+namespace WebCore {
+
+// setNumberOfChannels() may later be called if the object is not yet in an "initialized" state.
+AudioDSPKernelProcessor::AudioDSPKernelProcessor(double sampleRate, unsigned numberOfChannels)
+ : AudioProcessor(sampleRate)
+ , m_numberOfChannels(numberOfChannels)
+ , m_hasJustReset(true)
+{
+}
+
+void AudioDSPKernelProcessor::initialize()
+{
+ if (isInitialized())
+ return;
+
+ ASSERT(!m_kernels.size());
+
+ // Create processing kernels, one per channel.
+ for (unsigned i = 0; i < numberOfChannels(); ++i)
+ m_kernels.append(createKernel());
+
+ m_initialized = true;
+}
+
+void AudioDSPKernelProcessor::uninitialize()
+{
+ if (!isInitialized())
+ return;
+
+ m_kernels.clear();
+
+ m_initialized = false;
+}
+
+void AudioDSPKernelProcessor::process(AudioBus* source, AudioBus* destination, size_t framesToProcess)
+{
+ ASSERT(source && destination);
+ if (!source || !destination)
+ return;
+
+ if (!isInitialized()) {
+ destination->zero();
+ return;
+ }
+
+ bool channelCountMatches = source->numberOfChannels() == destination->numberOfChannels() && source->numberOfChannels() == m_kernels.size();
+ ASSERT(channelCountMatches);
+ if (!channelCountMatches)
+ return;
+
+ for (unsigned i = 0; i < m_kernels.size(); ++i)
+ m_kernels[i]->process(source->channel(i)->data(), destination->channel(i)->data(), framesToProcess);
+}
+
+// Resets filter state
+void AudioDSPKernelProcessor::reset()
+{
+ if (!isInitialized())
+ return;
+
+ // Forces snap to parameter values - first time.
+ // Any processing depending on this value must set it to false at the appropriate time.
+ m_hasJustReset = true;
+
+ for (unsigned i = 0; i < m_kernels.size(); ++i)
+ m_kernels[i]->reset();
+}
+
+void AudioDSPKernelProcessor::setNumberOfChannels(unsigned numberOfChannels)
+{
+ ASSERT(!isInitialized());
+ if (!isInitialized())
+ m_numberOfChannels = numberOfChannels;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/AudioDSPKernelProcessor.h b/WebCore/platform/audio/AudioDSPKernelProcessor.h
new file mode 100644
index 0000000..e87a810
--- /dev/null
+++ b/WebCore/platform/audio/AudioDSPKernelProcessor.h
@@ -0,0 +1,76 @@
+/*
+ * 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 AudioDSPKernelProcessor_h
+#define AudioDSPKernelProcessor_h
+
+#include "AudioBus.h"
+#include "AudioProcessor.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class AudioBus;
+class AudioDSPKernel;
+class AudioProcessor;
+
+// AudioDSPKernelProcessor processes one input -> one output (N channels each)
+// It uses one AudioDSPKernel object per channel to do the processing, thus there is no cross-channel processing.
+// Despite this limitation it turns out to be a very common and useful type of processor.
+
+class AudioDSPKernelProcessor : public AudioProcessor {
+public:
+ // numberOfChannels may be later changed if object is not yet in an "initialized" state
+ AudioDSPKernelProcessor(double sampleRate, unsigned numberOfChannels);
+
+ // Subclasses create the appropriate type of processing kernel here.
+ // We'll call this to create a kernel for each channel.
+ virtual PassOwnPtr<AudioDSPKernel> createKernel() = 0;
+
+ // AudioProcessor methods
+ virtual void initialize();
+ virtual void uninitialize();
+ virtual void process(AudioBus* source, AudioBus* destination, size_t framesToProcess);
+ virtual void reset();
+ virtual void setNumberOfChannels(unsigned numberOfChannels);
+
+ unsigned numberOfChannels() const { return m_numberOfChannels; }
+
+protected:
+ unsigned m_numberOfChannels;
+ Vector<OwnPtr<AudioDSPKernel> > m_kernels;
+ bool m_hasJustReset;
+};
+
+} // namespace WebCore
+
+#endif // AudioDSPKernelProcessor_h
diff --git a/WebCore/platform/audio/AudioProcessor.h b/WebCore/platform/audio/AudioProcessor.h
new file mode 100644
index 0000000..69ba40f
--- /dev/null
+++ b/WebCore/platform/audio/AudioProcessor.h
@@ -0,0 +1,75 @@
+/*
+ * 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 AudioProcessor_h
+#define AudioProcessor_h
+
+namespace WebCore {
+
+class AudioBus;
+
+// AudioProcessor is an abstract base class representing an audio signal processing object with a single input and a single output,
+// where the number of input channels equals the number of output channels. It can be used as one part of a complex DSP algorithm,
+// or as the processor for a basic (one input - one output) AudioNode.
+
+class AudioProcessor {
+public:
+ AudioProcessor(double sampleRate)
+ : m_initialized(false)
+ , m_sampleRate(sampleRate)
+ {
+ }
+
+ virtual ~AudioProcessor() { }
+
+ // Full initialization can be done here instead of in the constructor.
+ virtual void initialize() = 0;
+ virtual void uninitialize() = 0;
+
+ // Processes the source to destination bus. The number of channels must match in source and destination.
+ virtual void process(AudioBus* source, AudioBus* destination, size_t framesToProcess) = 0;
+
+ // Resets filter state
+ virtual void reset() = 0;
+
+ virtual void setNumberOfChannels(unsigned) = 0;
+
+ bool isInitialized() const { return m_initialized; }
+
+ double sampleRate() const { return m_sampleRate; }
+
+protected:
+ bool m_initialized;
+ double m_sampleRate;
+};
+
+} // namespace WebCore
+
+#endif // AudioProcessor_h
diff --git a/WebCore/platform/audio/AudioSourceProvider.h b/WebCore/platform/audio/AudioSourceProvider.h
new file mode 100644
index 0000000..773546a
--- /dev/null
+++ b/WebCore/platform/audio/AudioSourceProvider.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AudioSourceProvider_h
+#define AudioSourceProvider_h
+
+namespace WebCore {
+
+class AudioBus;
+
+// Abstract base-class for a pull-model client.
+// provideInput() gets called repeatedly to render time-slices of a continuous audio stream.
+class AudioSourceProvider {
+public:
+ virtual void provideInput(AudioBus* bus, size_t framesToProcess) = 0;
+ virtual ~AudioSourceProvider() { }
+};
+
+} // WebCore
+
+#endif // AudioSourceProvider_h
diff --git a/WebCore/platform/audio/Biquad.cpp b/WebCore/platform/audio/Biquad.cpp
new file mode 100644
index 0000000..6918dd6
--- /dev/null
+++ b/WebCore/platform/audio/Biquad.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "Biquad.h"
+
+#include "Accelerate.h"
+#include <algorithm>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+namespace WebCore {
+
+const int kBufferSize = 1024;
+
+Biquad::Biquad()
+{
+#if OS(DARWIN)
+ // Allocate two samples more for filter history
+ m_inputBuffer.resize(kBufferSize + 2);
+ m_outputBuffer.resize(kBufferSize + 2);
+#endif
+
+ // Initialize as pass-thru (straight-wire, no filter effect)
+ m_a0 = 1.0;
+ m_a1 = 0.0;
+ m_a2 = 0.0;
+ m_b1 = 0.0;
+ m_b2 = 0.0;
+
+ m_g = 1.0;
+
+ reset(); // clear filter memory
+}
+
+void Biquad::process(const float* sourceP, float* destP, size_t framesToProcess)
+{
+#if OS(DARWIN)
+ // Use vecLib if available
+ processFast(sourceP, destP, framesToProcess);
+#else
+ int n = framesToProcess;
+
+ // Create local copies of member variables
+ double x1 = m_x1;
+ double x2 = m_x2;
+ double y1 = m_y1;
+ double y2 = m_y2;
+
+ double a0 = m_a0;
+ double a1 = m_a1;
+ double a2 = m_a2;
+ double b1 = m_b1;
+ double b2 = m_b2;
+
+ while (n--) {
+ // FIXME: this can be optimized by pipelining the multiply adds...
+ float x = *sourceP++;
+ float y = a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2;
+
+ y *= m_g;
+
+ *destP++ = y;
+
+ // Update state variables
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+ }
+
+ // Local variables back to member
+ m_x1 = x1;
+ m_x2 = x2;
+ m_y1 = y1;
+ m_y2 = y2;
+
+ m_a0 = a0;
+ m_a1 = a1;
+ m_a2 = a2;
+ m_b1 = b1;
+ m_b2 = b2;
+#endif
+}
+
+#if OS(DARWIN)
+
+// Here we have optimized version using Accelerate.framework
+
+void Biquad::processFast(const float* sourceP, float* destP, size_t framesToProcess)
+{
+ // Filter coefficients
+ double B[5];
+ B[0] = m_a0;
+ B[1] = m_a1;
+ B[2] = m_a2;
+ B[3] = m_b1;
+ B[4] = m_b2;
+
+ double* inputP = m_inputBuffer.data();
+ double* outputP = m_outputBuffer.data();
+
+ double* input2P = inputP + 2;
+ double* output2P = outputP + 2;
+
+ // Break up processing into smaller slices (kBufferSize) if necessary.
+
+ int n = framesToProcess;
+
+ while (n > 0) {
+ int framesThisTime = n < kBufferSize ? n : kBufferSize;
+
+ // Copy input to input buffer
+ for (int i = 0; i < framesThisTime; ++i)
+ input2P[i] = *sourceP++;
+
+ processSliceFast(inputP, outputP, B, framesThisTime);
+
+ // Copy output buffer to output (converts float -> double).
+ for (int i = 0; i < framesThisTime; ++i)
+ *destP++ = static_cast<float>(output2P[i]);
+
+ n -= framesThisTime;
+ }
+}
+
+void Biquad::processSliceFast(double* sourceP, double* destP, double* coefficientsP, size_t framesToProcess)
+{
+ // Use double-precision for filter stability
+ vDSP_deq22D(sourceP, 1, coefficientsP, destP, 1, framesToProcess);
+
+ // Save history. Note that sourceP and destP reference m_inputBuffer and m_outputBuffer respectively.
+ // These buffers are allocated (in the constructor) with space for two extra samples so it's OK to access
+ // array values two beyond framesToProcess.
+ sourceP[0] = sourceP[framesToProcess - 2 + 2];
+ sourceP[1] = sourceP[framesToProcess - 1 + 2];
+ destP[0] = destP[framesToProcess - 2 + 2];
+ destP[1] = destP[framesToProcess - 1 + 2];
+}
+
+#endif // OS(DARWIN)
+
+
+void Biquad::reset()
+{
+ m_x1 = m_x2 = m_y1 = m_y2 = 0.0;
+
+#if OS(DARWIN)
+ // Two extra samples for filter history
+ double* inputP = m_inputBuffer.data();
+ inputP[0] = 0.0;
+ inputP[1] = 0.0;
+
+ double* outputP = m_outputBuffer.data();
+ outputP[0] = 0.0;
+ outputP[1] = 0.0;
+#endif
+}
+
+void Biquad::setLowpassParams(double cutoff, double resonance)
+{
+ resonance = std::max(0.0, resonance); // can't go negative
+
+ double g = pow(10.0, 0.05 * resonance);
+ double d = sqrt((4.0 - sqrt(16.0 - 16.0 / (g * g))) / 2.0);
+
+ // Compute biquad coefficients for lopass filter
+ double theta = M_PI * cutoff;
+ double sn = 0.5 * d * sin(theta);
+ double beta = 0.5 * (1.0 - sn) / (1.0 + sn);
+ double gamma = (0.5 + beta) * cos(theta);
+ double alpha = 0.25 * (0.5 + beta - gamma);
+
+ m_a0 = 2.0 * alpha;
+ m_a1 = 2.0 * 2.0*alpha;
+ m_a2 = 2.0 * alpha;
+ m_b1 = 2.0 * -gamma;
+ m_b2 = 2.0 * beta;
+}
+
+void Biquad::setHighpassParams(double cutoff, double resonance)
+{
+ resonance = std::max(0.0, resonance); // can't go negative
+
+ double g = pow(10.0, 0.05 * resonance);
+ double d = sqrt((4.0 - sqrt(16.0 - 16.0 / (g * g))) / 2.0);
+
+ // Compute biquad coefficients for highpass filter
+ double theta = M_PI * cutoff;
+ double sn = 0.5 * d * sin(theta);
+ double beta = 0.5 * (1.0 - sn) / (1.0 + sn);
+ double gamma = (0.5 + beta) * cos(theta);
+ double alpha = 0.25 * (0.5 + beta + gamma);
+
+ m_a0 = 2.0 * alpha;
+ m_a1 = 2.0 * -2.0*alpha;
+ m_a2 = 2.0 * alpha;
+ m_b1 = 2.0 * -gamma;
+ m_b2 = 2.0 * beta;
+}
+
+void Biquad::setLowShelfParams(double cutoff, double dbGain)
+{
+ double theta = M_PI * cutoff;
+
+ double A = pow(10.0, dbGain / 40.0);
+ double S = 1.0; // filter slope (1.0 is max value)
+ double alpha = 0.5 * sin(theta) * sqrt((A + 1.0 / A) * (1.0 / S - 1.0) + 2.0);
+
+ double k = cos(theta);
+ double k2 = 2.0 * sqrt(A) * alpha;
+
+ double b0 = A * ((A + 1.0) - (A - 1.0) * k + k2);
+ double b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * k);
+ double b2 = A * ((A + 1.0) - (A - 1.0) * k - k2);
+ double a0 = (A + 1.0) + (A - 1.0) * k + k2;
+ double a1 = -2.0 * ((A - 1.0) + (A + 1.0) * k);
+ double a2 = (A + 1.0) + (A - 1.0) * k - k2;
+
+ double a0Inverse = 1.0 / a0;
+
+ m_a0 = b0 * a0Inverse;
+ m_a1 = b1 * a0Inverse;
+ m_a2 = b2 * a0Inverse;
+ m_b1 = a1 * a0Inverse;
+ m_b2 = a2 * a0Inverse;
+}
+
+void Biquad::setZeroPolePairs(const Complex &zero, const Complex &pole)
+{
+ m_a0 = 1.0;
+ m_a1 = -2.0 * zero.real();
+
+ double zeroMag = abs(zero);
+ m_a2 = zeroMag * zeroMag;
+
+ m_b1 = -2.0 * pole.real();
+
+ double poleMag = abs(pole);
+ m_b2 = poleMag * poleMag;
+}
+
+void Biquad::setAllpassPole(const Complex &pole)
+{
+ Complex zero = Complex(1.0, 0.0) / pole;
+ setZeroPolePairs(zero, pole);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/Biquad.h b/WebCore/platform/audio/Biquad.h
new file mode 100644
index 0000000..d68bf4e
--- /dev/null
+++ b/WebCore/platform/audio/Biquad.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Biquad_h
+#define Biquad_h
+
+#include "AudioArray.h"
+#include <sys/types.h>
+#include <wtf/Complex.h>
+#include <wtf/Platform.h>
+
+namespace WebCore {
+
+// A basic biquad (two-zero / two-pole digital filter)
+//
+// It can be configured to a number of common and very useful filters:
+// lowpass, highpass, shelving, parameteric, notch, allpass, ...
+
+class Biquad {
+public:
+ Biquad();
+ virtual ~Biquad() { }
+
+ void process(const float* sourceP, float* destP, size_t framesToProcess);
+
+ // cutoff is 0-1 normalized, resonance is in dB >= 0.0
+ void setLowpassParams(double cutoff, double resonance);
+ void setHighpassParams(double cutoff, double resonance);
+
+ void setLowShelfParams(double cutoff, double dbGain);
+
+ // FIXME: need to implement a few more common filters
+ // void setHighShelfParams(double cutoff, double dbGain);
+ // void setParametricEQParams(double cutoff, double resonance);
+
+ // Set the biquad coefficients given a single zero (other zero will be conjugate)
+ // and a single pole (other pole will be conjugate)
+ void setZeroPolePairs(const Complex& zero, const Complex& pole);
+
+ // Set the biquad coefficients given a single pole (other pole will be conjugate)
+ // (The zeroes will be the inverse of the poles)
+ void setAllpassPole(const Complex& pole);
+
+ // Resets filter state
+ void reset();
+
+private:
+ // Filter coefficients
+ double m_a0;
+ double m_a1;
+ double m_a2;
+ double m_b1;
+ double m_b2;
+
+ double m_g;
+
+ // Filter memory
+ double m_x1; // input delayed by 1 sample
+ double m_x2; // input delayed by 2 samples
+ double m_y1; // output delayed by 1 sample
+ double m_y2; // output delayed by 2 samples
+
+#if OS(DARWIN)
+ void processFast(const float* sourceP, float* destP, size_t framesToProcess);
+ void processSliceFast(double* sourceP, double* destP, double* coefficientsP, size_t framesToProcess);
+
+ AudioDoubleArray m_inputBuffer;
+ AudioDoubleArray m_outputBuffer;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // Biquad_h
diff --git a/WebCore/platform/audio/Distance.cpp b/WebCore/platform/audio/Distance.cpp
new file mode 100644
index 0000000..0f1b005
--- /dev/null
+++ b/WebCore/platform/audio/Distance.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "Distance.h"
+
+#include <algorithm>
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+DistanceEffect::DistanceEffect()
+ : m_model(ModelInverse)
+ , m_isClamped(true)
+ , m_refDistance(1.0)
+ , m_maxDistance(10000.0)
+ , m_rolloffFactor(1.0)
+{
+}
+
+double DistanceEffect::gain(double distance)
+{
+ // don't go beyond maximum distance
+ distance = min(distance, m_maxDistance);
+
+ // if clamped, don't get closer than reference distance
+ if (m_isClamped)
+ distance = max(distance, m_refDistance);
+
+ switch (m_model) {
+ case ModelLinear:
+ return linearGain(distance);
+ break;
+ case ModelInverse:
+ return inverseGain(distance);
+ break;
+ case ModelExponential:
+ return exponentialGain(distance);
+ break;
+
+ default:
+ return 0.0;
+ }
+}
+
+double DistanceEffect::linearGain(double distance)
+{
+ return (1.0 - m_rolloffFactor * (distance - m_refDistance)) / (m_maxDistance - m_refDistance);
+}
+
+double DistanceEffect::inverseGain(double distance)
+{
+ return m_refDistance / (m_refDistance + m_rolloffFactor * (distance - m_refDistance));
+}
+
+double DistanceEffect::exponentialGain(double distance)
+{
+ return pow(distance / m_refDistance, -m_rolloffFactor);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/Distance.h b/WebCore/platform/audio/Distance.h
new file mode 100644
index 0000000..c7edded
--- /dev/null
+++ b/WebCore/platform/audio/Distance.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Distance_h
+#define Distance_h
+
+namespace WebCore {
+
+// Distance models are defined according to the OpenAL specification
+
+class DistanceEffect {
+public:
+ enum ModelType {
+ ModelLinear = 0,
+ ModelInverse = 1,
+ ModelExponential = 2
+ };
+
+ DistanceEffect();
+
+ // Returns scalar gain for the given distance the current distance model is used
+ double gain(double distance);
+
+ ModelType model() { return m_model; }
+
+ void setModel(ModelType model, bool clamped)
+ {
+ m_model = model;
+ m_isClamped = clamped;
+ }
+
+ // Distance params
+ void setRefDistance(double refDistance) { m_refDistance = refDistance; }
+ void setMaxDistance(double maxDistance) { m_maxDistance = maxDistance; }
+ void setRolloffFactor(double rolloffFactor) { m_rolloffFactor = rolloffFactor; }
+
+ double refDistance() const { return m_refDistance; }
+ double maxDistance() const { return m_maxDistance; }
+ double rolloffFactor() const { return m_rolloffFactor; }
+
+protected:
+ double linearGain(double distance);
+ double inverseGain(double distance);
+ double exponentialGain(double distance);
+
+ ModelType m_model;
+ bool m_isClamped;
+ double m_refDistance;
+ double m_maxDistance;
+ double m_rolloffFactor;
+};
+
+} // namespace WebCore
+
+#endif // Distance_h
diff --git a/WebCore/platform/audio/FFTFrame.cpp b/WebCore/platform/audio/FFTFrame.cpp
new file mode 100644
index 0000000..17292b6
--- /dev/null
+++ b/WebCore/platform/audio/FFTFrame.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "FFTFrame.h"
+
+#include <wtf/Complex.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+void FFTFrame::doPaddedFFT(float* data, size_t dataSize)
+{
+ // Zero-pad the impulse response
+ AudioFloatArray paddedResponse(fftSize()); // zero-initialized
+ paddedResponse.copyToRange(data, 0, dataSize);
+
+ // Get the frequency-domain version of padded response
+ doFFT(paddedResponse.data());
+}
+
+PassOwnPtr<FFTFrame> FFTFrame::createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x)
+{
+ OwnPtr<FFTFrame> newFrame = adoptPtr(new FFTFrame(frame1.fftSize()));
+
+ newFrame->interpolateFrequencyComponents(frame1, frame2, x);
+
+ // In the time-domain, the 2nd half of the response must be zero, to avoid circular convolution aliasing...
+ int fftSize = newFrame->fftSize();
+ AudioFloatArray buffer(fftSize);
+ newFrame->doInverseFFT(buffer.data());
+ buffer.zeroRange(fftSize / 2, fftSize);
+
+ // Put back into frequency domain.
+ newFrame->doFFT(buffer.data());
+
+ return newFrame.release();
+}
+
+void FFTFrame::interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double interp)
+{
+ // FIXME : with some work, this method could be optimized
+
+ float* realP = realData();
+ float* imagP = imagData();
+
+ const float* realP1 = frame1.realData();
+ const float* imagP1 = frame1.imagData();
+ const float* realP2 = frame2.realData();
+ const float* imagP2 = frame2.imagData();
+
+ m_FFTSize = frame1.fftSize();
+ m_log2FFTSize = frame1.log2FFTSize();
+
+ double s1base = (1.0 - interp);
+ double s2base = interp;
+
+ double phaseAccum = 0.0;
+ double lastPhase1 = 0.0;
+ double lastPhase2 = 0.0;
+
+ realP[0] = static_cast<float>(s1base * realP1[0] + s2base * realP2[0]);
+ imagP[0] = static_cast<float>(s1base * imagP1[0] + s2base * imagP2[0]);
+
+ int n = m_FFTSize / 2;
+
+ for (int i = 1; i < n; ++i) {
+ Complex c1(realP1[i], imagP1[i]);
+ Complex c2(realP2[i], imagP2[i]);
+
+ double mag1 = abs(c1);
+ double mag2 = abs(c2);
+
+ // Interpolate magnitudes in decibels
+ double mag1db = 20.0 * log10(mag1);
+ double mag2db = 20.0 * log10(mag2);
+
+ double s1 = s1base;
+ double s2 = s2base;
+
+ double magdbdiff = mag1db - mag2db;
+
+ // Empirical tweak to retain higher-frequency zeroes
+ double threshold = (i > 16) ? 5.0 : 2.0;
+
+ if (magdbdiff < -threshold && mag1db < 0.0) {
+ s1 = pow(s1, 0.75);
+ s2 = 1.0 - s1;
+ } else if (magdbdiff > threshold && mag2db < 0.0) {
+ s2 = pow(s2, 0.75);
+ s1 = 1.0 - s2;
+ }
+
+ // Average magnitude by decibels instead of linearly
+ double magdb = s1 * mag1db + s2 * mag2db;
+ double mag = pow(10.0, 0.05 * magdb);
+
+ // Now, deal with phase
+ double phase1 = arg(c1);
+ double phase2 = arg(c2);
+
+ double deltaPhase1 = phase1 - lastPhase1;
+ double deltaPhase2 = phase2 - lastPhase2;
+ lastPhase1 = phase1;
+ lastPhase2 = phase2;
+
+ // Unwrap phase deltas
+ if (deltaPhase1 > M_PI)
+ deltaPhase1 -= 2.0 * M_PI;
+ if (deltaPhase1 < -M_PI)
+ deltaPhase1 += 2.0 * M_PI;
+ if (deltaPhase2 > M_PI)
+ deltaPhase2 -= 2.0 * M_PI;
+ if (deltaPhase2 < -M_PI)
+ deltaPhase2 += 2.0 * M_PI;
+
+ // Blend group-delays
+ double deltaPhaseBlend;
+
+ if (deltaPhase1 - deltaPhase2 > M_PI)
+ deltaPhaseBlend = s1 * deltaPhase1 + s2 * (2.0 * M_PI + deltaPhase2);
+ else if (deltaPhase2 - deltaPhase1 > M_PI)
+ deltaPhaseBlend = s1 * (2.0 * M_PI + deltaPhase1) + s2 * deltaPhase2;
+ else
+ deltaPhaseBlend = s1 * deltaPhase1 + s2 * deltaPhase2;
+
+ phaseAccum += deltaPhaseBlend;
+
+ // Unwrap
+ if (phaseAccum > M_PI)
+ phaseAccum -= 2.0 * M_PI;
+ if (phaseAccum < -M_PI)
+ phaseAccum += 2.0 * M_PI;
+
+ Complex c = complexFromMagnitudePhase(mag, phaseAccum);
+
+ realP[i] = static_cast<float>(c.real());
+ imagP[i] = static_cast<float>(c.imag());
+ }
+}
+
+double FFTFrame::extractAverageGroupDelay()
+{
+ float* realP = realData();
+ float* imagP = imagData();
+
+ double aveSum = 0.0;
+ double weightSum = 0.0;
+ double lastPhase = 0.0;
+
+ int halfSize = fftSize() / 2;
+
+ const double kSamplePhaseDelay = (2.0 * M_PI) / double(fftSize());
+
+ // Calculate weighted average group delay
+ for (int i = 0; i < halfSize; i++) {
+ Complex c(realP[i], imagP[i]);
+ double mag = abs(c);
+ double phase = arg(c);
+
+ double deltaPhase = phase - lastPhase;
+ lastPhase = phase;
+
+ // Unwrap
+ if (deltaPhase < -M_PI)
+ deltaPhase += 2.0 * M_PI;
+ if (deltaPhase > M_PI)
+ deltaPhase -= 2.0 * M_PI;
+
+ aveSum += mag * deltaPhase;
+ weightSum += mag;
+ }
+
+ // Note how we invert the phase delta wrt frequency since this is how group delay is defined
+ double ave = aveSum / weightSum;
+ double aveSampleDelay = -ave / kSamplePhaseDelay;
+
+ // Leave 20 sample headroom (for leading edge of impulse)
+ if (aveSampleDelay > 20.0)
+ aveSampleDelay -= 20.0;
+
+ // Remove average group delay (minus 20 samples for headroom)
+ addConstantGroupDelay(-aveSampleDelay);
+
+ // Remove DC offset
+ realP[0] = 0.0f;
+
+ return aveSampleDelay;
+}
+
+void FFTFrame::addConstantGroupDelay(double sampleFrameDelay)
+{
+ int halfSize = fftSize() / 2;
+
+ float* realP = realData();
+ float* imagP = imagData();
+
+ const double kSamplePhaseDelay = (2.0 * M_PI) / double(fftSize());
+
+ double phaseAdj = -sampleFrameDelay * kSamplePhaseDelay;
+
+ // Add constant group delay
+ for (int i = 1; i < halfSize; i++) {
+ Complex c(realP[i], imagP[i]);
+ double mag = abs(c);
+ double phase = arg(c);
+
+ phase += i * phaseAdj;
+
+ Complex c2 = complexFromMagnitudePhase(mag, phase);
+
+ realP[i] = static_cast<float>(c2.real());
+ imagP[i] = static_cast<float>(c2.imag());
+ }
+}
+
+#ifndef NDEBUG
+void FFTFrame::print()
+{
+ FFTFrame& frame = *this;
+ float* realP = frame.realData();
+ float* imagP = frame.imagData();
+ printf("**** \n");
+ printf("DC = %f : nyquist = %f\n", realP[0], imagP[0]);
+
+ int n = m_FFTSize / 2;
+
+ for (int i = 1; i < n; i++) {
+ double mag = sqrt(realP[i] * realP[i] + imagP[i] * imagP[i]);
+ double phase = atan2(realP[i], imagP[i]);
+
+ printf("[%d] (%f %f)\n", i, mag, phase);
+ }
+ printf("****\n");
+}
+#endif // NDEBUG
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/FFTFrame.h b/WebCore/platform/audio/FFTFrame.h
new file mode 100644
index 0000000..6147fc1
--- /dev/null
+++ b/WebCore/platform/audio/FFTFrame.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FFTFrame_h
+#define FFTFrame_h
+
+#include "AudioArray.h"
+
+#if OS(DARWIN)
+#include <Accelerate/Accelerate.h>
+#endif
+
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Platform.h>
+
+namespace WebCore {
+
+// Defines the interface for an "FFT frame", an object which is able to perform a forward
+// and reverse FFT, internally storing the resultant frequency-domain data.
+
+class FFTFrame {
+public:
+ // The constructors, destructor, and methods up to the CROSS-PLATFORM section have platform-dependent implementations.
+
+ FFTFrame(unsigned fftSize);
+ FFTFrame(); // creates a blank/empty frame for later use with createInterpolatedFrame()
+ FFTFrame(const FFTFrame& frame);
+ ~FFTFrame();
+
+ static void cleanup();
+ void doFFT(float* data);
+ void doInverseFFT(float* data);
+ void multiply(const FFTFrame& frame); // multiplies ourself with frame : effectively operator*=()
+
+ float* realData() const;
+ float* imagData() const;
+
+ void print(); // for debugging
+
+ // CROSS-PLATFORM
+ // The remaining public methods have cross-platform implementations:
+
+ // Interpolates from frame1 -> frame2 as x goes from 0.0 -> 1.0
+ static PassOwnPtr<FFTFrame> createInterpolatedFrame(const FFTFrame& frame1, const FFTFrame& frame2, double x);
+
+ void doPaddedFFT(float* data, size_t dataSize); // zero-padding with dataSize <= fftSize
+ double extractAverageGroupDelay();
+ void addConstantGroupDelay(double sampleFrameDelay);
+
+ unsigned fftSize() const { return m_FFTSize; }
+ unsigned log2FFTSize() const { return m_log2FFTSize; }
+
+private:
+ unsigned m_FFTSize;
+ unsigned m_log2FFTSize;
+
+ void interpolateFrequencyComponents(const FFTFrame& frame1, const FFTFrame& frame2, double x);
+
+#if OS(DARWIN)
+ DSPSplitComplex& dspSplitComplex() { return m_frame; }
+ DSPSplitComplex dspSplitComplex() const { return m_frame; }
+
+ static FFTSetup fftSetupForSize(unsigned fftSize);
+
+ static FFTSetup* fftSetups;
+
+ FFTSetup m_FFTSetup;
+
+ DSPSplitComplex m_frame;
+ AudioFloatArray m_realData;
+ AudioFloatArray m_imagData;
+#endif // OS(DARWIN)
+};
+
+} // namespace WebCore
+
+#endif // FFTFrame_h
diff --git a/WebCore/platform/audio/Panner.cpp b/WebCore/platform/audio/Panner.cpp
new file mode 100644
index 0000000..29a1fbe
--- /dev/null
+++ b/WebCore/platform/audio/Panner.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "Panner.h"
+
+#include "EqualPowerPanner.h"
+#include "HRTFPanner.h"
+#include "PassThroughPanner.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+PassOwnPtr<Panner> Panner::create(PanningModel model, double sampleRate)
+{
+ OwnPtr<Panner> panner;
+
+ switch (model) {
+ case PanningModelEqualPower:
+ panner = adoptPtr(new EqualPowerPanner());
+ break;
+
+ case PanningModelHRTF:
+ panner = adoptPtr(new HRTFPanner(sampleRate));
+ break;
+
+ case PanningModelPassthrough:
+ panner = adoptPtr(new PassThroughPanner());
+ break;
+
+ // FIXME: sound field panning is not yet implemented...
+ case PanningModelSoundField:
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+
+ return panner.release();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/audio/Panner.h b/WebCore/platform/audio/Panner.h
new file mode 100644
index 0000000..c8e219b
--- /dev/null
+++ b/WebCore/platform/audio/Panner.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Panner_h
+#define Panner_h
+
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class AudioBus;
+
+// Abstract base class for panning a mono or stereo source.
+
+class Panner {
+public:
+ enum {
+ PanningModelPassthrough = 0,
+ PanningModelEqualPower = 1,
+ PanningModelHRTF = 2,
+ PanningModelSoundField = 3
+ };
+
+ typedef unsigned PanningModel;
+
+ static PassOwnPtr<Panner> create(PanningModel model, double sampleRate);
+
+ virtual ~Panner() { };
+
+ PanningModel panningModel() const { return m_panningModel; }
+
+ virtual void pan(double azimuth, double elevation, AudioBus* inputBus, AudioBus* outputBus, size_t framesToProcess) = 0;
+
+ virtual void reset() = 0;
+
+protected:
+ Panner(PanningModel model) : m_panningModel(model) { }
+
+ PanningModel m_panningModel;
+};
+
+} // namespace WebCore
+
+#endif // Panner_h
diff --git a/WebCore/platform/audio/mac/FFTFrameMac.cpp b/WebCore/platform/audio/mac/FFTFrameMac.cpp
new file mode 100644
index 0000000..0f7efb7
--- /dev/null
+++ b/WebCore/platform/audio/mac/FFTFrameMac.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Mac OS X - specific FFTFrame implementation
+
+#include "config.h"
+
+#if ENABLE(WEB_AUDIO)
+
+#include "FFTFrame.h"
+
+namespace WebCore {
+
+const int kMaxFFTPow2Size = 24;
+
+FFTSetup* FFTFrame::fftSetups = 0;
+
+// Normal constructor: allocates for a given fftSize
+FFTFrame::FFTFrame(unsigned fftSize)
+ : m_realData(fftSize)
+ , m_imagData(fftSize)
+{
+ m_FFTSize = fftSize;
+ m_log2FFTSize = static_cast<unsigned>(log2(fftSize));
+
+ // We only allow power of two
+ ASSERT(1UL << m_log2FFTSize == m_FFTSize);
+
+ // Lazily create and share fftSetup with other frames
+ m_FFTSetup = fftSetupForSize(fftSize);
+
+ // Setup frame data
+ m_frame.realp = m_realData.data();
+ m_frame.imagp = m_imagData.data();
+}
+
+// Creates a blank/empty frame (interpolate() must later be called)
+FFTFrame::FFTFrame()
+ : m_realData(0)
+ , m_imagData(0)
+{
+ // Later will be set to correct values when interpolate() is called
+ m_frame.realp = 0;
+ m_frame.imagp = 0;
+
+ m_FFTSize = 0;
+ m_log2FFTSize = 0;
+}
+
+// Copy constructor
+FFTFrame::FFTFrame(const FFTFrame& frame)
+ : m_FFTSize(frame.m_FFTSize)
+ , m_log2FFTSize(frame.m_log2FFTSize)
+ , m_FFTSetup(frame.m_FFTSetup)
+ , m_realData(frame.m_FFTSize)
+ , m_imagData(frame.m_FFTSize)
+{
+ // Setup frame data
+ m_frame.realp = m_realData.data();
+ m_frame.imagp = m_imagData.data();
+
+ // Copy/setup frame data
+ unsigned nbytes = sizeof(float) * m_FFTSize;
+ memcpy(realData(), frame.m_frame.realp, nbytes);
+ memcpy(imagData(), frame.m_frame.imagp, nbytes);
+}
+
+FFTFrame::~FFTFrame()
+{
+}
+
+void FFTFrame::multiply(const FFTFrame& frame)
+{
+ FFTFrame& frame1 = *this;
+ const FFTFrame& frame2 = frame;
+
+ float* realP1 = frame1.realData();
+ float* imagP1 = frame1.imagData();
+ const float* realP2 = frame2.realData();
+ const float* imagP2 = frame2.imagData();
+
+ // Scale accounts for vecLib's peculiar scaling
+ // This ensures the right scaling all the way back to inverse FFT
+ float scale = 0.5f;
+
+ // Multiply packed DC/nyquist component
+ realP1[0] *= scale * realP2[0];
+ imagP1[0] *= scale * imagP2[0];
+
+ // Multiply the rest, skipping packed DC/Nyquist components
+ DSPSplitComplex sc1 = frame1.dspSplitComplex();
+ sc1.realp++;
+ sc1.imagp++;
+
+ DSPSplitComplex sc2 = frame2.dspSplitComplex();
+ sc2.realp++;
+ sc2.imagp++;
+
+ unsigned halfSize = m_FFTSize / 2;
+
+ // Complex multiply
+ vDSP_zvmul(&sc1, 1, &sc2, 1, &sc1, 1, halfSize - 1, 1 /* normal multiplication */);
+
+ // We've previously scaled the packed part, now scale the rest.....
+ vDSP_vsmul(sc1.realp, 1, &scale, sc1.realp, 1, halfSize - 1);
+ vDSP_vsmul(sc1.imagp, 1, &scale, sc1.imagp, 1, halfSize - 1);
+}
+
+void FFTFrame::doFFT(float* data)
+{
+ vDSP_ctoz((DSPComplex*)data, 2, &m_frame, 1, m_FFTSize / 2);
+ vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_FORWARD);
+}
+
+void FFTFrame::doInverseFFT(float* data)
+{
+ vDSP_fft_zrip(m_FFTSetup, &m_frame, 1, m_log2FFTSize, FFT_INVERSE);
+ vDSP_ztoc(&m_frame, 1, (DSPComplex*)data, 2, m_FFTSize / 2);
+
+ // Do final scaling so that x == IFFT(FFT(x))
+ float scale = 0.5f / m_FFTSize;
+ vDSP_vsmul(data, 1, &scale, data, 1, m_FFTSize);
+}
+
+FFTSetup FFTFrame::fftSetupForSize(unsigned fftSize)
+{
+ if (!fftSetups) {
+ fftSetups = (FFTSetup*)malloc(sizeof(FFTSetup) * kMaxFFTPow2Size);
+ memset(fftSetups, 0, sizeof(FFTSetup) * kMaxFFTPow2Size);
+ }
+
+ int pow2size = static_cast<int>(log2(fftSize));
+ ASSERT(pow2size < kMaxFFTPow2Size);
+ if (!fftSetups[pow2size])
+ fftSetups[pow2size] = vDSP_create_fftsetup(pow2size, FFT_RADIX2);
+
+ return fftSetups[pow2size];
+}
+
+void FFTFrame::cleanup()
+{
+ if (!fftSetups)
+ return;
+
+ for (int i = 0; i < kMaxFFTPow2Size; ++i) {
+ if (fftSetups[i])
+ vDSP_destroy_fftsetup(fftSetups[i]);
+ }
+
+ free(fftSetups);
+ fftSetups = 0;
+}
+
+float* FFTFrame::realData() const
+{
+ return m_frame.realp;
+}
+
+float* FFTFrame::imagData() const
+{
+ return m_frame.imagp;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_AUDIO)
diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h
index bc86de2..894799c 100644
--- a/WebCore/platform/chromium/ChromiumBridge.h
+++ b/WebCore/platform/chromium/ChromiumBridge.h
@@ -190,6 +190,9 @@ namespace WebCore {
// That is committed size for Windows and virtual memory size for POSIX
static int memoryUsageMB();
+ // Same as above, but always returns actual value, without any caches.
+ static int actualMemoryUsageMB();
+
// MimeType -----------------------------------------------------------
static bool isSupportedImageMIMEType(const String& mimeType);
static bool isSupportedJavaScriptMIMEType(const String& mimeType);
diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp
index 23508a6..aff1466 100644
--- a/WebCore/platform/chromium/ClipboardChromium.cpp
+++ b/WebCore/platform/chromium/ClipboardChromium.cpp
@@ -533,7 +533,7 @@ void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame)
m_dataObject->textHtml = createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs);
m_dataObject->htmlBaseUrl = frame->document()->url();
- String str = frame->selectedText();
+ String str = frame->editor()->selectedText();
#if OS(WINDOWS)
replaceNewlinesWithWindowsStyleNewlines(str);
#endif
diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp
index 58373b1..ba69b00 100644
--- a/WebCore/platform/chromium/PasteboardChromium.cpp
+++ b/WebCore/platform/chromium/PasteboardChromium.cpp
@@ -84,7 +84,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete,
String html = createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs);
ExceptionCode ec = 0;
KURL url = selectedRange->startContainer(ec)->document()->url();
- String plainText = frame->selectedText();
+ String plainText = frame->editor()->selectedText();
#if OS(WINDOWS)
replaceNewlinesWithWindowsStyleNewlines(plainText);
#endif
diff --git a/WebCore/platform/efl/ScrollbarEfl.cpp b/WebCore/platform/efl/ScrollbarEfl.cpp
index e413260..6b00a37 100644
--- a/WebCore/platform/efl/ScrollbarEfl.cpp
+++ b/WebCore/platform/efl/ScrollbarEfl.cpp
@@ -84,7 +84,7 @@ static void scrollbarEflEdjeMessage(void* data, Evas_Object* o, Edje_Message_Typ
m = static_cast<Edje_Message_Float*>(msg);
v = m->val * (that->totalSize() - that->visibleSize());
- that->setValue(v);
+ that->setValue(v, Scrollbar::NotFromScrollAnimator);
}
void ScrollbarEfl::setParent(ScrollView* view)
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);
diff --git a/WebCore/platform/gtk/ClipboardGtk.cpp b/WebCore/platform/gtk/ClipboardGtk.cpp
index b2c32a4..3fe5ba1 100644
--- a/WebCore/platform/gtk/ClipboardGtk.cpp
+++ b/WebCore/platform/gtk/ClipboardGtk.cpp
@@ -348,7 +348,7 @@ void ClipboardGtk::writeRange(Range* range, Frame* frame)
{
ASSERT(range);
- m_dataObject->setText(frame->selectedText());
+ m_dataObject->setText(frame->editor()->selectedText());
m_dataObject->setMarkup(createMarkup(range, 0, AnnotateForInterchange, false, AbsoluteURLs));
if (m_clipboard)
diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.cpp b/WebCore/platform/gtk/GeolocationServiceGtk.cpp
index 69a0843..5b34c68 100644
--- a/WebCore/platform/gtk/GeolocationServiceGtk.cpp
+++ b/WebCore/platform/gtk/GeolocationServiceGtk.cpp
@@ -19,6 +19,7 @@
#include "config.h"
#include "GeolocationServiceGtk.h"
+#if ENABLE(GEOLOCATION)
#include "GOwnPtr.h"
#include "NotImplemented.h"
@@ -211,3 +212,4 @@ void GeolocationServiceGtk::setError(PositionError::ErrorCode errorCode, const c
}
}
+#endif // ENABLE(GEOLOCATION)
diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.h b/WebCore/platform/gtk/GeolocationServiceGtk.h
index c123017..46249ed 100644
--- a/WebCore/platform/gtk/GeolocationServiceGtk.h
+++ b/WebCore/platform/gtk/GeolocationServiceGtk.h
@@ -19,6 +19,7 @@
#ifndef GeolocationServiceGtk_h
#define GeolocationServiceGtk_h
+#if ENABLE(GEOLOCATION)
#include "GeolocationService.h"
#include "Geoposition.h"
@@ -70,4 +71,5 @@ namespace WebCore {
};
}
+#endif // ENABLE(GEOLOCATION)
#endif
diff --git a/WebCore/platform/gtk/MainFrameScrollbarGtk.cpp b/WebCore/platform/gtk/MainFrameScrollbarGtk.cpp
new file mode 100644
index 0000000..c2e24e0
--- /dev/null
+++ b/WebCore/platform/gtk/MainFrameScrollbarGtk.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2007, 2009 Holger Hans Peter Freyther zecke@selfish.org
+ * Copyright (C) 2010 Gustavo Noronha Silva <gns@gnome.org>
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "MainFrameScrollbarGtk.h"
+
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "IntRect.h"
+#include <gtk/gtk.h>
+
+using namespace WebCore;
+
+PassRefPtr<MainFrameScrollbarGtk> MainFrameScrollbarGtk::create(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment* adj)
+{
+ return adoptRef(new MainFrameScrollbarGtk(client, orientation, adj));
+}
+
+// Main frame scrollbars are slaves to a GtkAdjustment. If a main frame
+// scrollbar has an m_adjustment, it belongs to the container (a GtkWidget such
+// as GtkScrolledWindow). The adjustment may also be null, in which case there
+// is no containing view or the parent ScrollView is in some sort of transition
+// state. These scrollbars are never painted, as the container takes care of
+// that. They exist only to shuttle data from the GtkWidget container into
+// WebCore and vice-versa.
+MainFrameScrollbarGtk::MainFrameScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment* adjustment)
+ : Scrollbar(client, orientation, RegularScrollbar)
+ , m_adjustment(0)
+{
+ attachAdjustment(adjustment);
+
+ // We have nothing to show as we are solely operating on the GtkAdjustment.
+ resize(0, 0);
+}
+
+MainFrameScrollbarGtk::~MainFrameScrollbarGtk()
+{
+ if (m_adjustment)
+ detachAdjustment();
+}
+
+void MainFrameScrollbarGtk::attachAdjustment(GtkAdjustment* adjustment)
+{
+ if (m_adjustment)
+ detachAdjustment();
+
+ m_adjustment = adjustment;
+ if (!m_adjustment)
+ return;
+
+ g_signal_connect(m_adjustment.get(), "value-changed", G_CALLBACK(MainFrameScrollbarGtk::gtkValueChanged), this);
+ updateThumbProportion();
+ updateThumbPosition();
+}
+
+void MainFrameScrollbarGtk::detachAdjustment()
+{
+ if (!m_adjustment)
+ return;
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(m_adjustment.get()), (gpointer)MainFrameScrollbarGtk::gtkValueChanged, this);
+
+ // For the case where we only operate on the GtkAdjustment it is best to
+ // reset the values so that the surrounding scrollbar gets updated, or
+ // e.g. for a GtkScrolledWindow the scrollbar gets hidden.
+ gtk_adjustment_configure(m_adjustment.get(), 0, 0, 0, 0, 0, 0);
+
+ m_adjustment = 0;
+}
+
+void MainFrameScrollbarGtk::updateThumbPosition()
+{
+ if (!m_adjustment || gtk_adjustment_get_value(m_adjustment.get()) == m_currentPos)
+ return;
+ gtk_adjustment_set_value(m_adjustment.get(), m_currentPos);
+}
+
+void MainFrameScrollbarGtk::updateThumbProportion()
+{
+ if (!m_adjustment)
+ return;
+ gtk_adjustment_configure(m_adjustment.get(),
+ gtk_adjustment_get_value(m_adjustment.get()),
+ gtk_adjustment_get_lower(m_adjustment.get()),
+ m_totalSize,
+ m_lineStep,
+ m_pageStep,
+ m_visibleSize);
+}
+
+void MainFrameScrollbarGtk::gtkValueChanged(GtkAdjustment*, MainFrameScrollbarGtk* that)
+{
+ that->setValue(static_cast<int>(gtk_adjustment_get_value(that->m_adjustment.get())), NotFromScrollAnimator);
+}
+
+void MainFrameScrollbarGtk::paint(GraphicsContext* context, const IntRect& rect)
+{
+ // Main frame scrollbars are not painted by WebCore.
+ return;
+}
diff --git a/WebCore/platform/gtk/MainFrameScrollbarGtk.h b/WebCore/platform/gtk/MainFrameScrollbarGtk.h
new file mode 100644
index 0000000..8271ef5
--- /dev/null
+++ b/WebCore/platform/gtk/MainFrameScrollbarGtk.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef MainFrameScrollbarGtk_h
+#define MainFrameScrollbarGtk_h
+
+#include "GRefPtrGtk.h"
+#include "Scrollbar.h"
+#include <wtf/PassRefPtr.h>
+
+typedef struct _GtkAdjustment GtkAdjustment;
+
+namespace WebCore {
+
+class MainFrameScrollbarGtk : public Scrollbar {
+public:
+ ~MainFrameScrollbarGtk();
+ virtual void paint(GraphicsContext*, const IntRect&);
+ void detachAdjustment();
+ void attachAdjustment(GtkAdjustment*);
+ static PassRefPtr<MainFrameScrollbarGtk> create(ScrollbarClient*, ScrollbarOrientation, GtkAdjustment*);
+
+protected:
+ virtual void updateThumbPosition();
+ virtual void updateThumbProportion();
+
+private:
+ MainFrameScrollbarGtk(ScrollbarClient*, ScrollbarOrientation, GtkAdjustment*);
+ static void gtkValueChanged(GtkAdjustment*, MainFrameScrollbarGtk*);
+
+ PlatformRefPtr<GtkAdjustment> m_adjustment;
+};
+
+}
+
+#endif // ScrollbarGtk_h
diff --git a/WebCore/platform/gtk/PasteboardGtk.cpp b/WebCore/platform/gtk/PasteboardGtk.cpp
index ddb9768..76b7bb0 100644
--- a/WebCore/platform/gtk/PasteboardGtk.cpp
+++ b/WebCore/platform/gtk/PasteboardGtk.cpp
@@ -67,7 +67,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete,
{
GtkClipboard* clipboard = m_helper->getClipboard(frame);
DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
- dataObject->setText(frame->selectedText());
+ dataObject->setText(frame->editor()->selectedText());
dataObject->setMarkup(createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs));
m_helper->writeClipboardContents(clipboard);
}
diff --git a/WebCore/platform/gtk/ScrollViewGtk.cpp b/WebCore/platform/gtk/ScrollViewGtk.cpp
index 565123c..ebcdaa1 100644
--- a/WebCore/platform/gtk/ScrollViewGtk.cpp
+++ b/WebCore/platform/gtk/ScrollViewGtk.cpp
@@ -39,10 +39,10 @@
#include "GtkVersioning.h"
#include "HostWindow.h"
#include "IntRect.h"
+#include "MainFrameScrollbarGtk.h"
#include "Page.h"
#include "PlatformMouseEvent.h"
#include "PlatformWheelEvent.h"
-#include "ScrollbarGtk.h"
#include "ScrollbarTheme.h"
#include <gtk/gtk.h>
@@ -53,8 +53,6 @@ namespace WebCore {
void ScrollView::platformInit()
{
- m_horizontalAdjustment = 0;
- m_verticalAdjustment = 0;
}
void ScrollView::platformDestroy()
@@ -65,9 +63,8 @@ void ScrollView::platformDestroy()
PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
{
- // If this is an interior frame scrollbar, we want to create a scrollbar without
- // passing a GtkAdjustment. This will cause the Scrollbar to create a native GTK+
- // scrollbar.
+ // If this is an interior frame scrollbar, we want to create a totally fake
+ // scrollbar with no GtkAdjustment backing it.
if (parent())
return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
@@ -75,10 +72,10 @@ PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientati
// and defers to our GtkAdjustment for all of its state. Note that the GtkAdjustment
// may be null here.
if (orientation == HorizontalScrollbar)
- return ScrollbarGtk::createScrollbar(this, orientation, m_horizontalAdjustment);
+ return MainFrameScrollbarGtk::create(this, orientation, m_horizontalAdjustment.get());
// VerticalScrollbar
- return ScrollbarGtk::createScrollbar(this, orientation, m_verticalAdjustment);
+ return MainFrameScrollbarGtk::create(this, orientation, m_verticalAdjustment.get());
}
/*
@@ -89,15 +86,23 @@ void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj, boo
{
ASSERT(!hadj == !vadj);
+ // If this is a non-main frame ScrollView, we do not want to set the
+ // m_horizontalAdjustments & m_verticalAdjustments members. At the same
+ // time we want to to allow FrameLoaderClientGtk.cpp to call
+ // ScrollView::setGtkAdjustments(0, 0) unconditionally.
+ ASSERT(!parent() || !hadj);
+ if (parent())
+ return;
+
m_horizontalAdjustment = hadj;
m_verticalAdjustment = vadj;
if (!m_horizontalAdjustment) {
- ScrollbarGtk* hScrollbar = reinterpret_cast<ScrollbarGtk*>(horizontalScrollbar());
+ MainFrameScrollbarGtk* hScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(horizontalScrollbar());
if (hScrollbar)
hScrollbar->detachAdjustment();
- ScrollbarGtk* vScrollbar = reinterpret_cast<ScrollbarGtk*>(verticalScrollbar());
+ MainFrameScrollbarGtk* vScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(verticalScrollbar());
if (vScrollbar)
vScrollbar->detachAdjustment();
@@ -109,11 +114,11 @@ void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj, boo
setHasVerticalScrollbar(true);
setHasHorizontalScrollbar(true);
- ScrollbarGtk* hScrollbar = reinterpret_cast<ScrollbarGtk*>(horizontalScrollbar());
- hScrollbar->attachAdjustment(m_horizontalAdjustment);
+ MainFrameScrollbarGtk* hScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(horizontalScrollbar());
+ hScrollbar->attachAdjustment(m_horizontalAdjustment.get());
- ScrollbarGtk* vScrollbar = reinterpret_cast<ScrollbarGtk*>(verticalScrollbar());
- vScrollbar->attachAdjustment(m_verticalAdjustment);
+ MainFrameScrollbarGtk* vScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(verticalScrollbar());
+ vScrollbar->attachAdjustment(m_verticalAdjustment.get());
// We used to reset everything to 0 here, but when page cache
// is enabled we reuse FrameViews that are cached. Since their
@@ -124,7 +129,7 @@ void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj, boo
// able to report correct values.
int horizontalPageStep = max(max<int>(frameRect().width() * Scrollbar::minFractionToStepWhenPaging(), frameRect().width() - Scrollbar::maxOverlapBetweenPages()), 1);
- gtk_adjustment_configure(m_horizontalAdjustment,
+ gtk_adjustment_configure(m_horizontalAdjustment.get(),
resetValues ? 0 : scrollOffset().width(), 0,
resetValues ? 0 : contentsSize().width(),
resetValues ? 0 : Scrollbar::pixelsPerLineStep(),
@@ -132,7 +137,7 @@ void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj, boo
resetValues ? 0 : frameRect().width());
int verticalPageStep = max(max<int>(frameRect().height() * Scrollbar::minFractionToStepWhenPaging(), frameRect().height() - Scrollbar::maxOverlapBetweenPages()), 1);
- gtk_adjustment_configure(m_verticalAdjustment,
+ gtk_adjustment_configure(m_verticalAdjustment.get(),
resetValues ? 0 : scrollOffset().height(), 0,
resetValues ? 0 : contentsSize().height(),
resetValues ? 0 : Scrollbar::pixelsPerLineStep(),
@@ -142,72 +147,73 @@ void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj, boo
void ScrollView::platformAddChild(Widget* child)
{
- if (!GTK_IS_SOCKET(child->platformWidget()))
- gtk_container_add(GTK_CONTAINER(hostWindow()->platformPageClient()), child->platformWidget());
}
void ScrollView::platformRemoveChild(Widget* child)
{
- GtkWidget* parent;
-
- // HostWindow can be NULL here. If that's the case
- // let's grab the child's parent instead.
- if (hostWindow())
- parent = GTK_WIDGET(hostWindow()->platformPageClient());
- else
- parent = GTK_WIDGET(gtk_widget_get_parent(child->platformWidget()));
-
- if (GTK_IS_CONTAINER(parent) && parent == gtk_widget_get_parent(child->platformWidget()))
- gtk_container_remove(GTK_CONTAINER(parent), child->platformWidget());
}
IntRect ScrollView::visibleContentRect(bool includeScrollbars) const
{
- if (!m_horizontalAdjustment)
+ // If we are an interior frame scrollbar or are in some sort of transition
+ // state, just calculate our size based on what the GTK+ theme says the
+ // scrollbar width should be.
+ if (parent() || !hostWindow() || !hostWindow()->platformPageClient()) {
return IntRect(IntPoint(m_scrollOffset.width(), m_scrollOffset.height()),
IntSize(max(0, width() - (verticalScrollbar() && !includeScrollbars ? verticalScrollbar()->width() : 0)),
max(0, height() - (horizontalScrollbar() && !includeScrollbars ? horizontalScrollbar()->height() : 0))));
+ }
- // Main frame.
+ // We don't have a parent, so we are the main frame and thus have
+ // a parent widget which we can use to measure the visible region.
GtkWidget* measuredWidget = hostWindow()->platformPageClient();
- GtkWidget* parent = gtk_widget_get_parent(measuredWidget);
+ GtkWidget* parentWidget = gtk_widget_get_parent(measuredWidget);
// We may not be in a widget that displays scrollbars, but we may
// have other kinds of decoration that make us smaller.
- if (parent && includeScrollbars)
- measuredWidget = parent;
+ if (parentWidget && includeScrollbars)
+ measuredWidget = parentWidget;
GtkAllocation allocation;
-#if GTK_CHECK_VERSION(2, 18, 0)
gtk_widget_get_allocation(measuredWidget, &allocation);
-#else
- allocation = measuredWidget->allocation;
-#endif
return IntRect(IntPoint(m_scrollOffset.width(), m_scrollOffset.height()),
IntSize(allocation.width, allocation.height));
}
-void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode, bool, bool)
+void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode, bool horizontalLock, bool verticalLock)
{
- if (horizontalMode == m_horizontalScrollbarMode && verticalMode == m_verticalScrollbarMode)
- return;
+ // FIXME: Restructure the ScrollView abstraction so that we do not have to
+ // copy this verbatim from ScrollView.cpp. Until then, we should make sure this
+ // is kept in sync.
+ bool needsUpdate = false;
+
+ if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
+ m_horizontalScrollbarMode = horizontalMode;
+ needsUpdate = true;
+ }
- m_horizontalScrollbarMode = horizontalMode;
- m_verticalScrollbarMode = verticalMode;
+ if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
+ m_verticalScrollbarMode = verticalMode;
+ needsUpdate = true;
+ }
- // We don't really care about reporting policy changes on frames
- // that have no adjustments attached to them.
- if (!m_horizontalAdjustment) {
+ if (horizontalLock)
+ setHorizontalScrollbarLock();
+
+ if (verticalLock)
+ setVerticalScrollbarLock();
+
+ if (needsUpdate)
updateScrollbars(scrollOffset());
- return;
- }
- if (!isFrameView())
+ // We don't need to report policy changes on ScrollView's unless this
+ // one has an adjustment attached and it is a main frame.
+ if (!m_horizontalAdjustment || parent() || !isFrameView())
return;
// For frames that do have adjustments attached, we want to report
// policy changes, so that they may be applied to the widget to
- // which the WebView has been added, for instance.
+ // which the WebView's container (e.g. GtkScrolledWindow).
if (hostWindow())
hostWindow()->scrollbarsModeDidChange();
}
diff --git a/WebCore/platform/gtk/ScrollbarGtk.cpp b/WebCore/platform/gtk/ScrollbarGtk.cpp
deleted file mode 100644
index 8a1c4fa..0000000
--- a/WebCore/platform/gtk/ScrollbarGtk.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2007, 2009 Holger Hans Peter Freyther zecke@selfish.org
- * Copyright (C) 2010 Gustavo Noronha Silva <gns@gnome.org>
- * Copyright (C) 2010 Collabora Ltd.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-#include "ScrollbarGtk.h"
-
-#include "FrameView.h"
-#include "GraphicsContext.h"
-#include "GtkVersioning.h"
-#include "IntRect.h"
-#include "ScrollbarTheme.h"
-
-#include <gtk/gtk.h>
-
-using namespace WebCore;
-
-PassRefPtr<Scrollbar> Scrollbar::createNativeScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
-{
- return adoptRef(new ScrollbarGtk(client, orientation, size));
-}
-
-PassRefPtr<ScrollbarGtk> ScrollbarGtk::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment* adj)
-{
- return adoptRef(new ScrollbarGtk(client, orientation, adj));
-}
-
-static gboolean gtkScrollEventCallback(GtkWidget* widget, GdkEventScroll* event, ScrollbarGtk*)
-{
- /* Scroll only if our parent rejects the scroll event. The rationale for
- * this is that we want the main frame to scroll when we move the mouse
- * wheel over a child scrollbar in most cases. */
- return gtk_widget_event(gtk_widget_get_parent(widget), reinterpret_cast<GdkEvent*>(event));
-}
-
-ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orientation,
- ScrollbarControlSize controlSize)
- : Scrollbar(client, orientation, controlSize)
- , m_adjustment(GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)))
-{
- GtkWidget* scrollBar = orientation == HorizontalScrollbar ?
- gtk_hscrollbar_new(m_adjustment):
- gtk_vscrollbar_new(m_adjustment);
- gtk_widget_show(scrollBar);
- g_object_ref(m_adjustment);
- g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this);
- g_signal_connect(scrollBar, "scroll-event", G_CALLBACK(gtkScrollEventCallback), this);
-
- setPlatformWidget(scrollBar);
-
- /*
- * assign a sane default width and height to the Scrollbar, otherwise
- * we will end up with a 0 width scrollbar.
- */
- resize(ScrollbarTheme::nativeTheme()->scrollbarThickness(),
- ScrollbarTheme::nativeTheme()->scrollbarThickness());
-}
-
-// Create a ScrollbarGtk on top of an existing GtkAdjustment but do not create a
-// GtkScrollbar on top of this adjustment. The goal is to have a WebCore::Scrollbar
-// that will manipulate the GtkAdjustment properties, will react to the changed
-// value but will not consume any space on the screen and will not be painted
-// at all. It is achieved by not calling setPlatformWidget.
-ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment* adjustment)
- : Scrollbar(client, orientation, RegularScrollbar)
- , m_adjustment(adjustment)
-{
- if (m_adjustment) {
- g_object_ref(m_adjustment);
- g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this);
- }
-
- // We have nothing to show as we are solely operating on the GtkAdjustment
- resize(0, 0);
-}
-
-ScrollbarGtk::~ScrollbarGtk()
-{
- if (m_adjustment)
- detachAdjustment();
-}
-
-void ScrollbarGtk::attachAdjustment(GtkAdjustment* adjustment)
-{
- if (platformWidget())
- return;
-
- if (m_adjustment)
- detachAdjustment();
-
- m_adjustment = adjustment;
-
- if (m_adjustment) {
- g_object_ref(m_adjustment);
- g_signal_connect(m_adjustment, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this);
- }
-
- updateThumbProportion();
- updateThumbPosition();
-}
-
-void ScrollbarGtk::detachAdjustment()
-{
- if (!m_adjustment)
- return;
-
- g_signal_handlers_disconnect_by_func(G_OBJECT(m_adjustment), (gpointer)ScrollbarGtk::gtkValueChanged, this);
-
- // For the case where we only operate on the GtkAdjustment it is best to
- // reset the values so that the surrounding scrollbar gets updated, or
- // e.g. for a GtkScrolledWindow the scrollbar gets hidden.
- gtk_adjustment_configure(m_adjustment, 0, 0, 0, 0, 0, 0);
-
- g_object_unref(m_adjustment);
- m_adjustment = 0;
-}
-
-IntPoint ScrollbarGtk::getLocationInParentWindow(const IntRect& rect)
-{
- IntPoint loc;
-
- if (parent()->isScrollViewScrollbar(this))
- loc = parent()->convertToContainingWindow(rect.location());
- else
- loc = parent()->contentsToWindow(rect.location());
-
- return loc;
-}
-
-void ScrollbarGtk::frameRectsChanged()
-{
- if (!parent() || !platformWidget())
- return;
-
- IntPoint loc = getLocationInParentWindow(frameRect());
-
- // Don't allow the allocation size to be negative
- IntSize sz = frameRect().size();
- sz.clampNegativeToZero();
-
- GtkAllocation allocation = { loc.x(), loc.y(), sz.width(), sz.height() };
- gtk_widget_size_allocate(platformWidget(), &allocation);
-}
-
-void ScrollbarGtk::updateThumbPosition()
-{
- if (!m_adjustment)
- return;
-
- if (gtk_adjustment_get_value(m_adjustment) != m_currentPos)
- gtk_adjustment_set_value(m_adjustment, m_currentPos);
-}
-
-void ScrollbarGtk::updateThumbProportion()
-{
- if (!m_adjustment)
- return;
-
- gtk_adjustment_configure(m_adjustment,
- gtk_adjustment_get_value(m_adjustment),
- gtk_adjustment_get_lower(m_adjustment),
- m_totalSize,
- m_lineStep,
- m_pageStep,
- m_visibleSize);
-}
-
-void ScrollbarGtk::setFrameRect(const IntRect& rect)
-{
- Widget::setFrameRect(rect);
- frameRectsChanged();
-}
-
-void ScrollbarGtk::gtkValueChanged(GtkAdjustment*, ScrollbarGtk* that)
-{
- that->setValue(static_cast<int>(gtk_adjustment_get_value(that->m_adjustment)));
-}
-
-void ScrollbarGtk::setEnabled(bool shouldEnable)
-{
- if (enabled() == shouldEnable)
- return;
-
- Scrollbar::setEnabled(shouldEnable);
- if (platformWidget())
- gtk_widget_set_sensitive(platformWidget(), shouldEnable);
-}
-
-/*
- * Strategy to painting a Widget:
- * 1.) do not paint if there is no GtkWidget set
- * 2.) We assume that the widget has no window and that frameRectsChanged positioned
- * the widget correctly. ATM we do not honor the GraphicsContext translation.
- */
-void ScrollbarGtk::paint(GraphicsContext* context, const IntRect& rect)
-{
- if (!platformWidget())
- return;
-
- if (!context->gdkExposeEvent())
- return;
-
- GtkWidget* widget = platformWidget();
- ASSERT(!gtk_widget_get_has_window(widget));
-
- GdkEvent* event = gdk_event_new(GDK_EXPOSE);
- event->expose = *context->gdkExposeEvent();
- event->expose.area = static_cast<GdkRectangle>(rect);
-
- IntPoint loc = getLocationInParentWindow(rect);
-
- event->expose.area.x = loc.x();
- event->expose.area.y = loc.y();
-
-#ifdef GTK_API_VERSION_2
- event->expose.region = gdk_region_rectangle(&event->expose.area);
-#else
- event->expose.region = cairo_region_create_rectangle(&event->expose.area);
-#endif
-
- /*
- * This will be unref'ed by gdk_event_free.
- */
- g_object_ref(event->expose.window);
-
- /*
- * If we are going to paint do the translation and GtkAllocation manipulation.
- */
-#ifdef GTK_API_VERSION_2
- if (!gdk_region_empty(event->expose.region))
-#else
- if (!cairo_region_is_empty(event->expose.region))
-#endif
- gtk_widget_send_expose(widget, event);
-
- gdk_event_free(event);
-}
diff --git a/WebCore/platform/gtk/ScrollbarGtk.h b/WebCore/platform/gtk/ScrollbarGtk.h
deleted file mode 100644
index 1a078c9..0000000
--- a/WebCore/platform/gtk/ScrollbarGtk.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE 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 ScrollbarGtk_h
-#define ScrollbarGtk_h
-
-#include "Scrollbar.h"
-#include <wtf/PassRefPtr.h>
-
-namespace WebCore {
-
-class ScrollbarGtk : public Scrollbar {
-public:
- friend class Scrollbar;
- friend class ScrollView;
- ~ScrollbarGtk();
-
- virtual void setFrameRect(const IntRect&);
- virtual void paint(GraphicsContext*, const IntRect&);
-
- virtual bool handleMouseMoveEvent(const PlatformMouseEvent&) { return false; }
- virtual bool handleMouseOutEvent(const PlatformMouseEvent&) { return false; }
- virtual bool handleMousePressEvent(const PlatformMouseEvent&) { return false; }
- virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&) { return false; }
-
- virtual void setEnabled(bool);
-
- virtual void frameRectsChanged();
-
-protected:
- static PassRefPtr<ScrollbarGtk> createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment*);
-
- ScrollbarGtk(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize);
- ScrollbarGtk(ScrollbarClient*, ScrollbarOrientation, GtkAdjustment*);
-
- virtual void updateThumbPosition();
- virtual void updateThumbProportion();
-
- void detachAdjustment();
- void attachAdjustment(GtkAdjustment*);
-private:
- static void gtkValueChanged(GtkAdjustment*, ScrollbarGtk*);
- IntPoint getLocationInParentWindow(const IntRect&);
- GtkAdjustment* m_adjustment;
-};
-
-}
-
-#endif // ScrollbarGtk_h
diff --git a/WebCore/platform/gtk/ScrollbarThemeGtk.cpp b/WebCore/platform/gtk/ScrollbarThemeGtk.cpp
index b6efe54..2e942fe 100644
--- a/WebCore/platform/gtk/ScrollbarThemeGtk.cpp
+++ b/WebCore/platform/gtk/ScrollbarThemeGtk.cpp
@@ -82,6 +82,8 @@ void ScrollbarThemeGtk::updateThemeProperties()
m_stepperSpacing = metrics.stepper_spacing;
m_minThumbLength = metrics.min_slider_size;
m_troughUnderSteppers = metrics.trough_under_steppers;
+ m_hasForwardButtonStartPart = metrics.has_secondary_forward_stepper;
+ m_hasBackButtonEndPart = metrics.has_secondary_backward_stepper;
if (!gScrollbars)
return;
@@ -120,30 +122,45 @@ bool ScrollbarThemeGtk::hasThumb(Scrollbar* scrollbar)
IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
{
- // We do not support multiple steppers per end yet.
- if (part == BackButtonEndPart)
+ if (part == BackButtonEndPart && !m_hasBackButtonEndPart)
return IntRect();
+ int x = scrollbar->x() + m_troughBorderWidth;
+ int y = scrollbar->y() + m_troughBorderWidth;
IntSize size = buttonSize(scrollbar);
- return IntRect(scrollbar->x() + m_troughBorderWidth, scrollbar->y() + m_troughBorderWidth, size.width(), size.height());
+ if (part == BackButtonStartPart)
+ return IntRect(x, y, size.width(), size.height());
+
+ // BackButtonEndPart (alternate button)
+ if (scrollbar->orientation() == HorizontalScrollbar)
+ return IntRect(scrollbar->x() + scrollbar->width() - m_troughBorderWidth - (2 * size.width()), y, size.width(), size.height());
+
+ // VerticalScrollbar alternate button
+ return IntRect(x, scrollbar->y() + scrollbar->height() - m_troughBorderWidth - (2 * size.height()), size.width(), size.height());
}
IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
{
- // We do not support multiple steppers per end yet.
- if (part == ForwardButtonStartPart)
+ if (part == ForwardButtonStartPart && !m_hasForwardButtonStartPart)
return IntRect();
IntSize size = buttonSize(scrollbar);
- int x, y;
if (scrollbar->orientation() == HorizontalScrollbar) {
- x = scrollbar->x() + scrollbar->width() - size.width() - m_troughBorderWidth;
- y = scrollbar->y() + m_troughBorderWidth;
- } else {
- x = scrollbar->x() + m_troughBorderWidth;
- y = scrollbar->y() + scrollbar->height() - size.height() - m_troughBorderWidth;
+ int y = scrollbar->y() + m_troughBorderWidth;
+ if (part == ForwardButtonEndPart)
+ return IntRect(scrollbar->x() + scrollbar->width() - size.width() - m_troughBorderWidth, y, size.width(), size.height());
+
+ // ForwardButtonStartPart (alternate button)
+ return IntRect(scrollbar->x() + m_troughBorderWidth + size.width(), y, size.width(), size.height());
}
- return IntRect(x, y, size.width(), size.height());
+
+ // VerticalScrollbar
+ int x = scrollbar->x() + m_troughBorderWidth;
+ if (part == ForwardButtonEndPart)
+ return IntRect(x, scrollbar->y() + scrollbar->height() - size.height() - m_troughBorderWidth, size.width(), size.height());
+
+ // ForwardButtonStartPart (alternate button)
+ return IntRect(x, scrollbar->y() + m_troughBorderWidth + size.height(), size.width(), size.height());
}
IntRect ScrollbarThemeGtk::trackRect(Scrollbar* scrollbar, bool)
@@ -157,17 +174,28 @@ IntRect ScrollbarThemeGtk::trackRect(Scrollbar* scrollbar, bool)
// The fatness of the scrollbar on the non-movement axis.
int thickness = scrollbarThickness(scrollbar->controlSize());
+ int alternateButtonOffset = 0;
+ int alternateButtonWidth = 0;
+ if (m_hasForwardButtonStartPart) {
+ alternateButtonOffset += m_stepperSize;
+ alternateButtonWidth += m_stepperSize;
+ }
+ if (m_hasBackButtonEndPart)
+ alternateButtonWidth += m_stepperSize;
+
if (scrollbar->orientation() == HorizontalScrollbar) {
// Once the scrollbar becomes smaller than the natural size of the
// two buttons, the track disappears.
if (scrollbar->width() < 2 * thickness)
return IntRect();
- return IntRect(scrollbar->x() + movementAxisPadding, scrollbar->y(), scrollbar->width() - (2 * movementAxisPadding), thickness);
+ return IntRect(scrollbar->x() + movementAxisPadding + alternateButtonOffset, scrollbar->y(),
+ scrollbar->width() - (2 * movementAxisPadding) - alternateButtonWidth, thickness);
}
if (scrollbar->height() < 2 * thickness)
return IntRect();
- return IntRect(scrollbar->x(), scrollbar->y() + movementAxisPadding, thickness, scrollbar->height() - (2 * movementAxisPadding));
+ return IntRect(scrollbar->x(), scrollbar->y() + movementAxisPadding + alternateButtonOffset,
+ thickness, scrollbar->height() - (2 * movementAxisPadding) - alternateButtonWidth);
}
void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
@@ -304,10 +332,10 @@ void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollb
if (scrollbar->orientation() == VerticalScrollbar)
flags |= MOZ_GTK_STEPPER_VERTICAL;
- if (part == ForwardButtonEndPart) {
+ if (part == ForwardButtonEndPart)
+ flags |= (MOZ_GTK_STEPPER_DOWN | MOZ_GTK_STEPPER_BOTTOM);
+ if (part == ForwardButtonStartPart)
flags |= MOZ_GTK_STEPPER_DOWN;
- flags |= MOZ_GTK_STEPPER_BOTTOM;
- }
GtkWidgetState state;
state.focused = TRUE;
@@ -315,7 +343,9 @@ void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollb
state.canDefault = TRUE;
if ((BackButtonStartPart == part && scrollbar->currentPos())
- || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum())) {
+ || (BackButtonEndPart == part && scrollbar->currentPos())
+ || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum())
+ || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) {
state.disabled = FALSE;
state.active = part == scrollbar->pressedPart();
state.inHover = part == scrollbar->hoveredPart();
diff --git a/WebCore/platform/gtk/ScrollbarThemeGtk.h b/WebCore/platform/gtk/ScrollbarThemeGtk.h
index eff2fee..8f990d5 100644
--- a/WebCore/platform/gtk/ScrollbarThemeGtk.h
+++ b/WebCore/platform/gtk/ScrollbarThemeGtk.h
@@ -68,6 +68,8 @@ protected:
int m_stepperSpacing;
int m_minThumbLength;
bool m_troughUnderSteppers;
+ bool m_hasForwardButtonStartPart;
+ bool m_hasBackButtonEndPart;
};
}
diff --git a/WebCore/platform/gtk/gtk2drawing.c b/WebCore/platform/gtk/gtk2drawing.c
index b33fb1f..ba69cdc 100644
--- a/WebCore/platform/gtk/gtk2drawing.c
+++ b/WebCore/platform/gtk/gtk2drawing.c
@@ -3079,6 +3079,8 @@ moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
"stepper_size", &metrics->stepper_size,
"stepper_spacing", &metrics->stepper_spacing,
"trough_under_steppers", &metrics->trough_under_steppers,
+ "has_secondary_forward_stepper", &metrics->has_secondary_forward_stepper,
+ "has_secondary_backward_stepper", &metrics->has_secondary_backward_stepper,
NULL);
metrics->min_slider_size = gtk_range_get_min_slider_size(GTK_RANGE(gParts->horizScrollbarWidget));
diff --git a/WebCore/platform/gtk/gtkdrawing.h b/WebCore/platform/gtk/gtkdrawing.h
index 9d06d5d..c00da97 100644
--- a/WebCore/platform/gtk/gtkdrawing.h
+++ b/WebCore/platform/gtk/gtkdrawing.h
@@ -76,6 +76,8 @@ typedef struct {
gint stepper_spacing;
gint min_slider_size;
gboolean trough_under_steppers;
+ gboolean has_secondary_forward_stepper;
+ gboolean has_secondary_backward_stepper;
} MozGtkScrollbarMetrics;
typedef struct _GtkThemeParts {
diff --git a/WebCore/platform/network/FormData.cpp b/WebCore/platform/network/FormData.cpp
index 786f1b6..406a375 100644
--- a/WebCore/platform/network/FormData.cpp
+++ b/WebCore/platform/network/FormData.cpp
@@ -226,7 +226,7 @@ void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncod
FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
// Add the content type if it is available.
- if (value.blob()->type().isEmpty())
+ if (!value.blob()->type().isEmpty())
FormDataBuilder::addContentTypeToMultiPartHeader(header, value.blob()->type().latin1());
}
diff --git a/WebCore/platform/network/android/ResourceHandleAndroid.cpp b/WebCore/platform/network/android/ResourceHandleAndroid.cpp
index 2cd1ba9..2a2ea74 100644
--- a/WebCore/platform/network/android/ResourceHandleAndroid.cpp
+++ b/WebCore/platform/network/android/ResourceHandleAndroid.cpp
@@ -27,7 +27,7 @@
#include "ResourceHandle.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "DocumentLoader.h"
#include "Frame.h"
#include "FrameLoader.h"
@@ -51,6 +51,7 @@ ResourceHandle::~ResourceHandle()
bool ResourceHandle::start(Frame* frame)
{
+<<<<<<< HEAD
DocumentLoader* docLoader = frame->loader()->activeDocumentLoader();
MainResourceLoader* mainLoader = docLoader->mainResourceLoader();
bool isMainResource =
@@ -58,6 +59,11 @@ bool ResourceHandle::start(Frame* frame)
bool isPrivateBrowsing = false;
if (frame->settings())
isPrivateBrowsing = frame->settings()->privateBrowsingEnabled();
+=======
+ DocumentLoader* documentLoader = frame->loader()->activeDocumentLoader();
+ MainResourceLoader* mainLoader = documentLoader->mainResourceLoader();
+ bool isMainResource = mainLoader && (mainLoader->handle() == this);
+>>>>>>> webkit.org at r67178
PassRefPtr<ResourceLoaderAndroid> loader = ResourceLoaderAndroid::start(this, d->m_firstRequest, frame->loader()->client(), isMainResource, false, isPrivateBrowsing);
diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
index 419e397..209906e 100644
--- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
+++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp
@@ -34,7 +34,7 @@
#include "Base64.h"
#include "CookieStorageWin.h"
#include "CredentialStorage.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "FormDataStreamCFNet.h"
#include "Frame.h"
#include "FrameLoader.h"
diff --git a/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/WebCore/platform/network/curl/ResourceHandleCurl.cpp
index a4c1f8e..096905d 100644
--- a/WebCore/platform/network/curl/ResourceHandleCurl.cpp
+++ b/WebCore/platform/network/curl/ResourceHandleCurl.cpp
@@ -28,7 +28,7 @@
#include "config.h"
#include "ResourceHandle.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "NotImplemented.h"
#include "ResourceHandleInternal.h"
#include "ResourceHandleManager.h"
diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp
index ba68351..8d2a1bf 100644
--- a/WebCore/platform/network/curl/ResourceHandleManager.cpp
+++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp
@@ -612,7 +612,8 @@ static void parseDataUrl(ResourceHandle* handle)
// WebCore's decoder fails on Acid3 test 97 (whitespace).
Vector<char> out;
- if (base64Decode(data.latin1().data(), data.latin1().length(), out) && out.size() > 0)
+ CString latin1 = data.latin1();
+ if (base64Decode(latin1.data(), latin1.length(), out) && out.size() > 0)
client->didReceiveData(handle, out.data(), out.size(), 0);
} else {
// We have to convert to UTF-16 early due to limitations in KURL
diff --git a/WebCore/platform/network/curl/ResourceRequest.h b/WebCore/platform/network/curl/ResourceRequest.h
index 40e1e8f..12dc214 100644
--- a/WebCore/platform/network/curl/ResourceRequest.h
+++ b/WebCore/platform/network/curl/ResourceRequest.h
@@ -56,6 +56,11 @@ namespace WebCore {
{
}
+ ResourceRequest(CFURLRequestRef)
+ : ResourceRequestBase()
+ {
+ }
+
// Needed for compatibility.
CFURLRequestRef cfURLRequest() const { return 0; }
diff --git a/WebCore/platform/network/curl/ResourceResponse.h b/WebCore/platform/network/curl/ResourceResponse.h
index 6195f61..860e902 100644
--- a/WebCore/platform/network/curl/ResourceResponse.h
+++ b/WebCore/platform/network/curl/ResourceResponse.h
@@ -28,6 +28,8 @@
#include "ResourceResponseBase.h"
+typedef const struct _CFURLResponse* CFURLResponseRef;
+
namespace WebCore {
class ResourceResponse : public ResourceResponseBase {
@@ -46,6 +48,9 @@ public:
void setResponseFired(bool fired) { m_responseFired = fired; }
bool responseFired() { return m_responseFired; }
+ // Needed for compatibility.
+ CFURLResponseRef cfURLResponse() const { return 0; }
+
private:
bool m_responseFired;
};
diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm
index d014bb3..0af86d0 100644
--- a/WebCore/platform/network/mac/ResourceHandleMac.mm
+++ b/WebCore/platform/network/mac/ResourceHandleMac.mm
@@ -32,7 +32,7 @@
#import "BlobRegistry.h"
#import "BlockExceptions.h"
#import "CredentialStorage.h"
-#import "DocLoader.h"
+#import "CachedResourceLoader.h"
#import "EmptyProtocolDefinitions.h"
#import "FormDataStreamMac.h"
#import "Frame.h"
diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp
index f91eecb..3548467 100644
--- a/WebCore/platform/network/qt/ResourceHandleQt.cpp
+++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp
@@ -31,7 +31,7 @@
#include "ResourceHandle.h"
#include "ChromeClientQt.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Frame.h"
#include "FrameLoaderClientQt.h"
#include "NotImplemented.h"
diff --git a/WebCore/platform/network/qt/ResourceRequestQt.cpp b/WebCore/platform/network/qt/ResourceRequestQt.cpp
index 637c71f..4d576c7 100644
--- a/WebCore/platform/network/qt/ResourceRequestQt.cpp
+++ b/WebCore/platform/network/qt/ResourceRequestQt.cpp
@@ -64,6 +64,11 @@ QNetworkRequest ResourceRequest::toNetworkRequest(QObject* originatingFrame) con
request.setRawHeader(name, "");
}
+ // Make sure we always have an Accept header; some sites require this to
+ // serve subresources
+ if (!request.hasRawHeader("Accept"))
+ request.setRawHeader("Accept", "*/*");
+
switch (cachePolicy()) {
case ReloadIgnoringCacheData:
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
index 96a2f25..dadbd22 100644
--- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp
+++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp
@@ -31,7 +31,7 @@
#include "CString.h"
#include "ChromeClient.h"
#include "CookieJarSoup.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "FileSystem.h"
#include "Frame.h"
#include "GOwnPtrSoup.h"
diff --git a/WebCore/platform/network/soup/SocketStreamHandle.h b/WebCore/platform/network/soup/SocketStreamHandle.h
index 64139e5..2ba4504 100644
--- a/WebCore/platform/network/soup/SocketStreamHandle.h
+++ b/WebCore/platform/network/soup/SocketStreamHandle.h
@@ -32,8 +32,8 @@
#ifndef SocketStreamHandle_h
#define SocketStreamHandle_h
+#include "GRefPtr.h"
#include "SocketStreamHandleBase.h"
-
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -48,12 +48,21 @@ namespace WebCore {
static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); }
virtual ~SocketStreamHandle();
+ void connected(GSocketConnection*, GError*);
+ void readBytes(signed long, GError*);
+ void writeReady();
protected:
virtual int platformSend(const char* data, int length);
virtual void platformClose();
private:
+ PlatformRefPtr<GSocketConnection> m_socketConnection;
+ PlatformRefPtr<GInputStream> m_inputStream;
+ PlatformRefPtr<GOutputStream> m_outputStream;
+ PlatformRefPtr<GSource> m_writeReadySource;
+ char* m_readBuffer;
+
SocketStreamHandle(const KURL&, SocketStreamHandleClient*);
// No authentication for streams per se, but proxy may ask for credentials.
@@ -61,6 +70,8 @@ namespace WebCore {
void receivedCredential(const AuthenticationChallenge&, const Credential&);
void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&);
void receivedCancellation(const AuthenticationChallenge&);
+ void beginWaitingForSocketWritability();
+ void stopWaitingForSocketWritability();
};
} // namespace WebCore
diff --git a/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp b/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp
index 6aa33fc..d73b499 100644
--- a/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp
+++ b/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp
@@ -31,38 +31,161 @@
#include "config.h"
#include "SocketStreamHandle.h"
+#include "CString.h"
+#include "GOwnPtr.h"
#include "KURL.h"
#include "Logging.h"
+#include "NotFound.h"
#include "NotImplemented.h"
+#include "SocketStreamError.h"
#include "SocketStreamHandleClient.h"
+#include "Vector.h"
+#include <gio/gio.h>
+#include <glib.h>
+
+#define READ_BUFFER_SIZE 1024
namespace WebCore {
+// These functions immediately call the similarly named SocketStreamHandle methods.
+static void connectedCallback(GSocketClient*, GAsyncResult*, SocketStreamHandle*);
+static void readReadyCallback(GInputStream*, GAsyncResult*, SocketStreamHandle*);
+static gboolean writeReadyCallback(GSocket*, GIOCondition, SocketStreamHandle*);
+
+// Having a list of active handles means that we do not have to worry about WebCore
+// reference counting in GLib callbacks. Once the handle is off the active handles list
+// we just ignore it in the callback. We avoid a lot of extra checks and tricky
+// situations this way.
+static Vector<SocketStreamHandle*> gActiveHandles;
+bool isActiveHandle(SocketStreamHandle* handle)
+{
+ return gActiveHandles.find(handle) != notFound;
+}
+
+void deactivateHandle(SocketStreamHandle* handle)
+{
+ size_t handleIndex = gActiveHandles.find(handle);
+ if (handleIndex != notFound)
+ gActiveHandles.remove(handleIndex);
+}
+
SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
: SocketStreamHandleBase(url, client)
+ , m_readBuffer(0)
{
- LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
- notImplemented();
+ // No support for SSL sockets yet.
+ if (url.protocolIs("wss"))
+ return;
+ unsigned int port = url.hasPort() ? url.port() : 80;
+
+ gActiveHandles.append(this);
+ PlatformRefPtr<GSocketClient> socketClient = adoptPlatformRef(g_socket_client_new());
+ g_socket_client_connect_to_host_async(socketClient.get(), url.host().utf8().data(), port, 0,
+ reinterpret_cast<GAsyncReadyCallback>(connectedCallback), this);
}
SocketStreamHandle::~SocketStreamHandle()
{
- LOG(Network, "SocketStreamHandle %p delete", this);
+ // If for some reason we were destroyed without closing, ensure that we are deactivated.
+ deactivateHandle(this);
setClient(0);
- notImplemented();
}
-int SocketStreamHandle::platformSend(const char*, int)
+void SocketStreamHandle::connected(GSocketConnection* socketConnection, GError* error)
{
- LOG(Network, "SocketStreamHandle %p platformSend", this);
- notImplemented();
- return 0;
+ if (error) {
+ m_client->didFail(this, SocketStreamError(error->code));
+ return;
+ }
+
+ m_socketConnection = adoptPlatformRef(socketConnection);
+ m_outputStream = g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get()));
+ m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
+
+ m_readBuffer = new char[READ_BUFFER_SIZE];
+ g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
+ reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), this);
+
+ // The client can close the handle, potentially removing the last reference.
+ RefPtr<SocketStreamHandle> protect(this);
+ m_state = Open;
+ m_client->didOpen(this);
+ if (!m_socketConnection) // Client closed the connection.
+ return;
+}
+
+void SocketStreamHandle::readBytes(signed long bytesRead, GError* error)
+{
+ if (error) {
+ m_client->didFail(this, SocketStreamError(error->code));
+ return;
+ }
+
+ if (!bytesRead) {
+ close();
+ return;
+ }
+
+ // The client can close the handle, potentially removing the last reference.
+ RefPtr<SocketStreamHandle> protect(this);
+ m_client->didReceiveData(this, m_readBuffer, bytesRead);
+ if (m_inputStream) // The client may have closed the connection.
+ g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
+ reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), this);
+}
+
+void SocketStreamHandle::writeReady()
+{
+ // We no longer have buffered data, so stop waiting for the socket to be writable.
+ if (!bufferedAmount()) {
+ stopWaitingForSocketWritability();
+ return;
+ }
+
+ sendPendingData();
+}
+
+int SocketStreamHandle::platformSend(const char* data, int length)
+{
+ if (!g_socket_condition_check(g_socket_connection_get_socket(m_socketConnection.get()), G_IO_OUT)) {
+ beginWaitingForSocketWritability();
+ return 0;
+ }
+
+ GOwnPtr<GError> error;
+ gssize written = g_output_stream_write(m_outputStream.get(), data, length, 0, &error.outPtr());
+ if (error) {
+ m_client->didFail(this, SocketStreamError(error->code)); // FIXME: Provide a sensible error.
+ return 0;
+ }
+
+ // If we did not send all the bytes we were given, we know that
+ // SocketStreamHandleBase will need to send more in the future.
+ if (written < length)
+ beginWaitingForSocketWritability();
+
+ return written;
}
void SocketStreamHandle::platformClose()
{
- LOG(Network, "SocketStreamHandle %p platformClose", this);
- notImplemented();
+ // We remove this handle from the active handles list first, to disable all callbacks.
+ deactivateHandle(this);
+ stopWaitingForSocketWritability();
+
+ if (m_socketConnection) {
+ GOwnPtr<GError> error;
+ g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), 0, &error.outPtr());
+ if (error)
+ m_client->didFail(this, SocketStreamError(error->code)); // FIXME: Provide a sensible error.
+ m_socketConnection = 0;
+ }
+
+ m_outputStream = 0;
+ m_inputStream = 0;
+ delete m_readBuffer;
+
+ m_client->didClose(this);
}
void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
@@ -85,4 +208,70 @@ void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
notImplemented();
}
+void SocketStreamHandle::beginWaitingForSocketWritability()
+{
+ if (m_writeReadySource) // Already waiting.
+ return;
+
+ m_writeReadySource = adoptPlatformRef(g_socket_create_source(
+ g_socket_connection_get_socket(m_socketConnection.get()), static_cast<GIOCondition>(G_IO_OUT), 0));
+ g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), this, 0);
+ g_source_attach(m_writeReadySource.get(), 0);
+}
+
+void SocketStreamHandle::stopWaitingForSocketWritability()
+{
+ if (!m_writeReadySource) // Not waiting.
+ return;
+
+ g_source_remove(g_source_get_id(m_writeReadySource.get()));
+ m_writeReadySource = 0;
+}
+
+static void connectedCallback(GSocketClient* client, GAsyncResult* result, SocketStreamHandle* handle)
+{
+ // Always finish the connection, even if this SocketStreamHandle was deactivated earlier.
+ GOwnPtr<GError> error;
+ GSocketConnection* socketConnection = g_socket_client_connect_to_host_finish(client, result, &error.outPtr());
+
+ // The SocketStreamHandle has been deactivated, so just close the connection, ignoring errors.
+ if (!isActiveHandle(handle)) {
+ g_io_stream_close(G_IO_STREAM(socketConnection), 0, &error.outPtr());
+ return;
+ }
+
+ handle->connected(socketConnection, error.get());
+}
+
+static void readReadyCallback(GInputStream* stream, GAsyncResult* result, SocketStreamHandle* handle)
+{
+ // Always finish the read, even if this SocketStreamHandle was deactivated earlier.
+ GOwnPtr<GError> error;
+ gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
+
+ if (!isActiveHandle(handle))
+ return;
+ handle->readBytes(bytesRead, error.get());
+}
+
+static gboolean writeReadyCallback(GSocket*, GIOCondition condition, SocketStreamHandle* handle)
+{
+ if (!isActiveHandle(handle))
+ return FALSE;
+
+ // G_IO_HUP and G_IO_ERR are are always active. See:
+ // http://library.gnome.org/devel/gio/stable/GSocket.html#g-socket-create-source
+ if (condition & G_IO_HUP) {
+ handle->close();
+ return FALSE;
+ }
+ if (condition & G_IO_ERR) {
+ handle->client()->didFail(handle, SocketStreamError(0)); // FIXME: Provide a sensible error.
+ return FALSE;
+ }
+ if (condition & G_IO_OUT)
+ handle->writeReady();
+ return TRUE;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/network/win/ResourceHandleWin.cpp b/WebCore/platform/network/win/ResourceHandleWin.cpp
index 3dabd91..2af03c0 100644
--- a/WebCore/platform/network/win/ResourceHandleWin.cpp
+++ b/WebCore/platform/network/win/ResourceHandleWin.cpp
@@ -27,7 +27,7 @@
#include "config.h"
#include "ResourceHandle.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
diff --git a/WebCore/platform/qt/ClipboardQt.cpp b/WebCore/platform/qt/ClipboardQt.cpp
index f677d28..6cbde0c 100644
--- a/WebCore/platform/qt/ClipboardQt.cpp
+++ b/WebCore/platform/qt/ClipboardQt.cpp
@@ -315,7 +315,7 @@ void ClipboardQt::writeRange(Range* range, Frame* frame)
if (!m_writableData)
m_writableData = new QMimeData;
- QString text = frame->selectedText();
+ QString text = frame->editor()->selectedText();
text.replace(QChar(0xa0), QLatin1Char(' '));
m_writableData->setText(text);
m_writableData->setHtml(createMarkup(range, 0, AnnotateForInterchange, false, AbsoluteURLs));
diff --git a/WebCore/platform/qt/PasteboardQt.cpp b/WebCore/platform/qt/PasteboardQt.cpp
index fc53124..ac54fdb 100644
--- a/WebCore/platform/qt/PasteboardQt.cpp
+++ b/WebCore/platform/qt/PasteboardQt.cpp
@@ -61,7 +61,7 @@ Pasteboard* Pasteboard::generalPasteboard()
void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
{
QMimeData* md = new QMimeData;
- QString text = frame->selectedText();
+ QString text = frame->editor()->selectedText();
text.replace(QChar(0xa0), QLatin1Char(' '));
md->setText(text);
diff --git a/WebCore/platform/qt/ScrollbarQt.cpp b/WebCore/platform/qt/ScrollbarQt.cpp
index 85dc107..a517064 100644
--- a/WebCore/platform/qt/ScrollbarQt.cpp
+++ b/WebCore/platform/qt/ScrollbarQt.cpp
@@ -76,11 +76,11 @@ bool Scrollbar::contextMenu(const PlatformMouseEvent& event)
const QPoint pos = convertFromContainingWindow(event.pos());
moveThumb(horizontal ? pos.x() : pos.y());
} else if (actionSelected == actScrollTop)
- setValue(0);
+ scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByDocument);
else if (actionSelected == actScrollBottom)
- setValue(maximum());
+ scroll(horizontal ? ScrollRight : ScrollDown, ScrollByDocument);
else if (actionSelected == actPageUp)
- scroll(horizontal ? ScrollLeft: ScrollUp, ScrollByPage);
+ scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByPage);
else if (actionSelected == actPageDown)
scroll(horizontal ? ScrollRight : ScrollDown, ScrollByPage);
else if (actionSelected == actScrollUp)
diff --git a/WebCore/platform/text/CharacterNames.h b/WebCore/platform/text/CharacterNames.h
index f06246c..9f8f807 100644
--- a/WebCore/platform/text/CharacterNames.h
+++ b/WebCore/platform/text/CharacterNames.h
@@ -52,6 +52,7 @@ const UChar leftSingleQuotationMark = 0x2018;
const UChar leftToRightEmbed = 0x202A;
const UChar leftToRightMark = 0x200E;
const UChar leftToRightOverride = 0x202D;
+const UChar minusSign = 0x2212;
const UChar newlineCharacter = 0x000A;
const UChar noBreakSpace = 0x00A0;
const UChar objectReplacementCharacter = 0xFFFC;
diff --git a/WebCore/platform/text/wince/TextCodecWinCE.cpp b/WebCore/platform/text/wince/TextCodecWinCE.cpp
index 578f789..2789148 100644
--- a/WebCore/platform/text/wince/TextCodecWinCE.cpp
+++ b/WebCore/platform/text/wince/TextCodecWinCE.cpp
@@ -24,7 +24,6 @@
#include "config.h"
#include "TextCodecWinCE.h"
-#include "ce_textcodecs.h"
#include "FontCache.h"
#include "PlatformString.h"
#include <mlang.h>
@@ -43,7 +42,6 @@ struct CharsetInfo {
String m_friendlyName;
UINT m_codePage;
Vector<CString> m_aliases;
- bool m_usesNativeCodec;
};
class LanguageManager {
@@ -82,45 +80,8 @@ static LanguageManager& languageManager()
return lm;
}
-static void addCharset(UINT codePage, const char* charsetName, const wchar_t* friendlyName, const char* charsetAliases, bool nativeSupport = false)
-{
- CharsetInfo info;
- info.m_codePage = codePage;
- info.m_name = charsetName;
- info.m_friendlyName = friendlyName;
- info.m_usesNativeCodec = nativeSupport;
- const char* begin = charsetAliases;
- for (;;) {
- const char* end = strchr(begin, '|');
- CString alias = end ? CString(begin, end - begin) : begin;
- if (alias.length())
- info.m_aliases.append(alias);
- if (!end)
- break;
- begin = end + 1;
- }
- knownCharsets().set(info.m_name.data(), info);
- if (codePage != CP_ACP)
- codePageCharsets().set(codePage, info.m_name);
-}
-
LanguageManager::LanguageManager()
{
- // 437, 708, 709, 710, 720, 737, 775, 850, 852
- addCharset(932, "SHIFT_JIS", L"Japanese (SHIFT_JIS)", "shift_jis");
- addCharset(936, "GBK", L"Chinese Simplified (GBK)", "gbk|gb2312");
- addCharset(949, "KSC5601", L"Korean (KSC5601)", "ks_c_5601-1987|ksc5601|euc-kr|euckr|x-euc-kr");
- addCharset(950, "BIG5", L"Chinese Traditional (BIG5)", "big5");
- addCharset(1361, "JOHAB", L"Korean (Johab)", "johab|korean.johab");
- addCharset(51932, "EUC-JP", L"Japanese (EUC)", "euc-jp|eucjp|x-euc-jp", true);
- addCharset(874, "CP874", L"Thai (Windows)", "cp874|windows-874", true);
- addCharset(CP_ACP, "TIS620", L"Thai (TIS 620)", "tis620|ISO-8859-11|ISO-IR-166|TIS-620|TIS620-0TIS620.2529-1|TIS620.2533-0|TIS620.2533-1|thai8", true);
- addCharset(CP_ACP, "MACTHAI", L"Thai (Mac OS)", "macthai|x-mac-thai|mac-thai", true);
- supportedCharsets().add("EUC-JP");
- supportedCharsets().add("CP874");
- supportedCharsets().add("TIS620");
- supportedCharsets().add("MACTHAI");
-
IEnumCodePage* enumInterface;
IMultiLanguage* mli = FontCache::getMultiLanguageInterface();
if (mli && S_OK == mli->EnumCodePages(MIMECONTF_BROWSER, &enumInterface)) {
@@ -148,7 +109,6 @@ LanguageManager::LanguageManager()
info.m_aliases.append(name);
info.m_aliases.append(String(cpInfo.wszHeaderCharset).latin1());
info.m_aliases.append(String(cpInfo.wszBodyCharset).latin1());
- info.m_usesNativeCodec = false;
String cpName = String::format("cp%d", cpInfo.uiCodePage);
info.m_aliases.append(cpName.latin1());
supportedCharsets().add(i->second.data());
@@ -265,52 +225,6 @@ static void decode(Vector<UChar, 8192>& result, const char* encodingName, const
codePage = CP_UTF8;
else
codePage = CP_ACP;
- } else {
- codePage = i->second.m_codePage;
- if (i->second.m_usesNativeCodec) {
- typedef int (*FuncEucMbToWc)(wchar_t *pwc, const unsigned char *s, int n);
- FuncEucMbToWc encMbToWc = 0;
- if (!strcmp(encodingName, "EUC-JP"))
- encMbToWc = TextCodecsCE::euc_jp_mbtowc;
- else if (!strcmp(encodingName, "CP874"))
- encMbToWc = TextCodecsCE::cp874_mbtowc;
- else if (!strcmp(encodingName, "TIS620"))
- encMbToWc = TextCodecsCE::tis620_mbtowc;
- else if (!strcmp(encodingName, "MACTHAI"))
- encMbToWc = TextCodecsCE::mac_thai_mbtowc;
-
- if (encMbToWc) {
- const char* const srcStart = bytes;
- const char* const srcEnd = bytes + length;
- int lastSize = result.size();
- result.resize(lastSize + length);
- for (;;) {
- UChar* dst = result.data() + lastSize;
- const UChar* const dstEnd = result.data() + result.size();
- for (; dst < dstEnd && bytes < srcEnd; ++dst) {
- int numberEncoded = encMbToWc(dst, (const unsigned char*)bytes, srcEnd - bytes);
- if (numberEncoded >= 0)
- bytes += numberEncoded;
- else {
- if (numberEncoded == RET_ILSEQ)
- sawInvalidChar = true;
- break;
- }
- }
- if (bytes == srcEnd || dst != dstEnd) {
- *left = srcEnd - bytes;
- result.resize(dst - result.data());
- return;
- }
- lastSize = result.size();
- result.resize(result.size() + 256);
- }
- } else {
- *left = 0;
- result.append(bytes, length);
- return;
- }
- }
}
DWORD flags = getCodePageFlags(codePage);
diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp
index 2915f9d..6d9930c 100644
--- a/WebCore/platform/win/ClipboardWin.cpp
+++ b/WebCore/platform/win/ClipboardWin.cpp
@@ -776,7 +776,7 @@ void ClipboardWin::writeRange(Range* selectedRange, Frame* frame)
if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE)))
::GlobalFree(medium.hGlobal);
- String str = frame->selectedText();
+ String str = frame->editor()->selectedText();
replaceNewlinesWithWindowsStyleNewlines(str);
replaceNBSPWithSpace(str);
medium.hGlobal = createGlobalData(str);
diff --git a/WebCore/platform/win/PasteboardWin.cpp b/WebCore/platform/win/PasteboardWin.cpp
index c065f04..4b20adb 100644
--- a/WebCore/platform/win/PasteboardWin.cpp
+++ b/WebCore/platform/win/PasteboardWin.cpp
@@ -131,7 +131,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete,
}
// Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well
- String str = frame->selectedText();
+ String str = frame->editor()->selectedText();
replaceNewlinesWithWindowsStyleNewlines(str);
replaceNBSPWithSpace(str);
if (::OpenClipboard(m_owner)) {
diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp
index 6e22024..a782b03 100644
--- a/WebCore/platform/win/PopupMenuWin.cpp
+++ b/WebCore/platform/win/PopupMenuWin.cpp
@@ -531,12 +531,12 @@ bool PopupMenuWin::scrollToRevealSelection()
int index = focusedIndex();
if (index < m_scrollOffset) {
- m_scrollbar->setValue(index);
+ m_scrollbar->setValue(index, Scrollbar::NotFromScrollAnimator);
return true;
}
if (index >= m_scrollOffset + visibleItems()) {
- m_scrollbar->setValue(index - visibleItems() + 1);
+ m_scrollbar->setValue(index - visibleItems() + 1, Scrollbar::NotFromScrollAnimator);
return true;
}
@@ -664,6 +664,17 @@ void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc)
::ReleaseDC(m_popup, localDC);
}
+int PopupMenuWin::scrollSize(ScrollbarOrientation orientation) const
+{
+ return ((orientation == VerticalScrollbar) && m_scrollbar) ? (m_scrollbar->totalSize() - m_scrollbar->visibleSize()) : 0;
+}
+
+void PopupMenuWin::setScrollOffsetFromAnimation(const IntPoint& offset)
+{
+ if (m_scrollbar)
+ m_scrollbar->setValue(offset.y(), Scrollbar::FromScrollAnimator);
+}
+
void PopupMenuWin::valueChanged(Scrollbar* scrollBar)
{
ASSERT(m_scrollbar);
diff --git a/WebCore/platform/win/PopupMenuWin.h b/WebCore/platform/win/PopupMenuWin.h
index d4a4255..bfec7aa 100644
--- a/WebCore/platform/win/PopupMenuWin.h
+++ b/WebCore/platform/win/PopupMenuWin.h
@@ -91,6 +91,8 @@ private:
void setScrollbarCapturingMouse(bool b) { m_scrollbarCapturingMouse = b; }
// ScrollBarClient
+ virtual int scrollSize(ScrollbarOrientation orientation) const;
+ virtual void setScrollOffsetFromAnimation(const IntPoint&);
virtual void valueChanged(Scrollbar*);
virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
virtual bool isActive() const { return true; }
diff --git a/WebCore/platform/win/ScrollbarThemeWin.cpp b/WebCore/platform/win/ScrollbarThemeWin.cpp
index a8d374a..ff3aaa4 100644
--- a/WebCore/platform/win/ScrollbarThemeWin.cpp
+++ b/WebCore/platform/win/ScrollbarThemeWin.cpp
@@ -27,6 +27,7 @@
#include "ScrollbarThemeWin.h"
#include "GraphicsContext.h"
+#include "LocalWindowsContext.h"
#include "PlatformMouseEvent.h"
#include "Scrollbar.h"
#include "SoftLinking.h"
@@ -240,14 +241,17 @@ void ScrollbarThemeWin::paintTrackPiece(GraphicsContext* context, Scrollbar* scr
bool alphaBlend = false;
if (scrollbarTheme)
alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, part, state);
- HDC hdc = context->getWindowsContext(rect, alphaBlend);
+
+ LocalWindowsContext windowsContext(context, rect, alphaBlend);
RECT themeRect(rect);
+
if (scrollbarTheme)
- DrawThemeBackground(scrollbarTheme, hdc, part, state, &themeRect, 0);
+ DrawThemeBackground(scrollbarTheme, windowsContext.hdc(), part, state, &themeRect, 0);
else {
DWORD color3DFace = ::GetSysColor(COLOR_3DFACE);
DWORD colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR);
DWORD colorWindow = ::GetSysColor(COLOR_WINDOW);
+ HDC hdc = windowsContext.hdc();
if ((color3DFace != colorScrollbar) && (colorWindow != colorScrollbar))
::FillRect(hdc, &themeRect, HBRUSH(COLOR_SCROLLBAR+1));
else {
@@ -265,7 +269,6 @@ void ScrollbarThemeWin::paintTrackPiece(GraphicsContext* context, Scrollbar* scr
::DeleteObject(patternBitmap);
}
}
- context->releaseWindowsContext(hdc, rect, alphaBlend);
}
void ScrollbarThemeWin::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
@@ -308,14 +311,13 @@ void ScrollbarThemeWin::paintButton(GraphicsContext* context, Scrollbar* scrollb
bool alphaBlend = false;
if (scrollbarTheme)
alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, SP_BUTTON, xpState);
- HDC hdc = context->getWindowsContext(rect, alphaBlend);
+ LocalWindowsContext windowsContext(context, rect, alphaBlend);
RECT themeRect(rect);
if (scrollbarTheme)
- DrawThemeBackground(scrollbarTheme, hdc, SP_BUTTON, xpState, &themeRect, 0);
+ DrawThemeBackground(scrollbarTheme, windowsContext.hdc(), SP_BUTTON, xpState, &themeRect, 0);
else
- ::DrawFrameControl(hdc, &themeRect, DFC_SCROLL, classicState);
- context->releaseWindowsContext(hdc, rect, alphaBlend);
+ ::DrawFrameControl(windowsContext.hdc(), &themeRect, DFC_SCROLL, classicState);
}
static IntRect gripperRect(int thickness, const IntRect& thumbRect)