| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions | |
| 6 * are met: | |
| 7 * | |
| 8 * 1. Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 * notice, this list of conditions and the following disclaimer in the | |
| 12 * documentation and/or other materials provided with the distribution. | |
| 13 * | |
| 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
| 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 24 */ | |
| 25 | |
| 26 #include "sky/engine/config.h" | |
| 27 | |
| 28 #include "sky/engine/web/LinkHighlight.h" | |
| 29 | |
| 30 #include "sky/engine/core/dom/Node.h" | |
| 31 #include "sky/engine/core/frame/FrameView.h" | |
| 32 #include "sky/engine/core/frame/LocalFrame.h" | |
| 33 #include "sky/engine/core/rendering/RenderLayer.h" | |
| 34 #include "sky/engine/core/rendering/RenderLayerModelObject.h" | |
| 35 #include "sky/engine/core/rendering/RenderObject.h" | |
| 36 #include "sky/engine/core/rendering/RenderView.h" | |
| 37 #include "sky/engine/core/rendering/style/ShadowData.h" | |
| 38 #include "sky/engine/platform/graphics/Color.h" | |
| 39 #include "sky/engine/public/platform/Platform.h" | |
| 40 #include "sky/engine/public/platform/WebCompositorAnimationCurve.h" | |
| 41 #include "sky/engine/public/platform/WebCompositorSupport.h" | |
| 42 #include "sky/engine/public/platform/WebFloatAnimationCurve.h" | |
| 43 #include "sky/engine/public/platform/WebFloatPoint.h" | |
| 44 #include "sky/engine/public/platform/WebRect.h" | |
| 45 #include "sky/engine/public/platform/WebSize.h" | |
| 46 #include "sky/engine/public/web/Sky.h" | |
| 47 #include "sky/engine/web/WebLocalFrameImpl.h" | |
| 48 #include "sky/engine/web/WebSettingsImpl.h" | |
| 49 #include "sky/engine/web/WebViewImpl.h" | |
| 50 #include "sky/engine/wtf/CurrentTime.h" | |
| 51 #include "third_party/skia/include/utils/SkMatrix44.h" | |
| 52 | |
| 53 namespace blink { | |
| 54 | |
| 55 class WebViewImpl; | |
| 56 | |
| 57 PassOwnPtr<LinkHighlight> LinkHighlight::create(Node* node, WebViewImpl* owningW
ebViewImpl) | |
| 58 { | |
| 59 return adoptPtr(new LinkHighlight(node, owningWebViewImpl)); | |
| 60 } | |
| 61 | |
| 62 LinkHighlight::LinkHighlight(Node* node, WebViewImpl* owningWebViewImpl) | |
| 63 : m_node(node) | |
| 64 , m_owningWebViewImpl(owningWebViewImpl) | |
| 65 , m_currentGraphicsLayer(0) | |
| 66 , m_geometryNeedsUpdate(false) | |
| 67 , m_isAnimating(false) | |
| 68 , m_startTime(monotonicallyIncreasingTime()) | |
| 69 { | |
| 70 ASSERT(m_node); | |
| 71 ASSERT(owningWebViewImpl); | |
| 72 WebCompositorSupport* compositorSupport = Platform::current()->compositorSup
port(); | |
| 73 m_contentLayer = adoptPtr(compositorSupport->createContentLayer(this)); | |
| 74 m_clipLayer = adoptPtr(compositorSupport->createLayer()); | |
| 75 m_clipLayer->setTransformOrigin(WebFloatPoint3D()); | |
| 76 m_clipLayer->addChild(m_contentLayer->layer()); | |
| 77 m_contentLayer->layer()->setAnimationDelegate(this); | |
| 78 m_contentLayer->layer()->setDrawsContent(true); | |
| 79 m_contentLayer->layer()->setOpacity(1); | |
| 80 m_geometryNeedsUpdate = true; | |
| 81 updateGeometry(); | |
| 82 } | |
| 83 | |
| 84 LinkHighlight::~LinkHighlight() | |
| 85 { | |
| 86 clearGraphicsLayerLinkHighlightPointer(); | |
| 87 releaseResources(); | |
| 88 } | |
| 89 | |
| 90 WebContentLayer* LinkHighlight::contentLayer() | |
| 91 { | |
| 92 return m_contentLayer.get(); | |
| 93 } | |
| 94 | |
| 95 WebLayer* LinkHighlight::clipLayer() | |
| 96 { | |
| 97 return m_clipLayer.get(); | |
| 98 } | |
| 99 | |
| 100 void LinkHighlight::releaseResources() | |
| 101 { | |
| 102 m_node.clear(); | |
| 103 } | |
| 104 | |
| 105 RenderLayer* LinkHighlight::computeEnclosingCompositingLayer() | |
| 106 { | |
| 107 return 0; | |
| 108 } | |
| 109 | |
| 110 static void convertTargetSpaceQuadToCompositedLayer(const FloatQuad& targetSpace
Quad, RenderObject* targetRenderer, RenderObject* compositedRenderer, FloatQuad&
compositedSpaceQuad) | |
| 111 { | |
| 112 ASSERT(targetRenderer); | |
| 113 ASSERT(compositedRenderer); | |
| 114 | |
| 115 for (unsigned i = 0; i < 4; ++i) { | |
| 116 IntPoint point; | |
| 117 switch (i) { | |
| 118 case 0: point = roundedIntPoint(targetSpaceQuad.p1()); break; | |
| 119 case 1: point = roundedIntPoint(targetSpaceQuad.p2()); break; | |
| 120 case 2: point = roundedIntPoint(targetSpaceQuad.p3()); break; | |
| 121 case 3: point = roundedIntPoint(targetSpaceQuad.p4()); break; | |
| 122 } | |
| 123 | |
| 124 point = targetRenderer->frame()->view()->contentsToWindow(point); | |
| 125 point = compositedRenderer->frame()->view()->windowToContents(point); | |
| 126 FloatPoint floatPoint = compositedRenderer->absoluteToLocal(point, UseTr
ansforms); | |
| 127 | |
| 128 switch (i) { | |
| 129 case 0: compositedSpaceQuad.setP1(floatPoint); break; | |
| 130 case 1: compositedSpaceQuad.setP2(floatPoint); break; | |
| 131 case 2: compositedSpaceQuad.setP3(floatPoint); break; | |
| 132 case 3: compositedSpaceQuad.setP4(floatPoint); break; | |
| 133 } | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 static void addQuadToPath(const FloatQuad& quad, Path& path) | |
| 138 { | |
| 139 // FIXME: Make this create rounded quad-paths, just like the axis-aligned ca
se. | |
| 140 path.moveTo(quad.p1()); | |
| 141 path.addLineTo(quad.p2()); | |
| 142 path.addLineTo(quad.p3()); | |
| 143 path.addLineTo(quad.p4()); | |
| 144 path.closeSubpath(); | |
| 145 } | |
| 146 | |
| 147 void LinkHighlight::computeQuads(RenderObject& renderer, Vector<FloatQuad>& outQ
uads) const | |
| 148 { | |
| 149 // For inline elements, absoluteQuads will return a line box based on the li
ne-height | |
| 150 // and font metrics, which is technically incorrect as replaced elements lik
e images | |
| 151 // should use their intristic height and expand the linebox as needed. To g
et an | |
| 152 // appropriately sized highlight we descend into the children and have them
add their | |
| 153 // boxes. | |
| 154 if (renderer.isRenderInline()) { | |
| 155 for (RenderObject* child = renderer.slowFirstChild(); child; child = chi
ld->nextSibling()) | |
| 156 computeQuads(*child, outQuads); | |
| 157 } else { | |
| 158 renderer.absoluteQuads(outQuads); | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 bool LinkHighlight::computeHighlightLayerPathAndPosition(RenderLayer* compositin
gLayer) | |
| 163 { | |
| 164 if (!m_node || !m_node->renderer() || !m_currentGraphicsLayer) | |
| 165 return false; | |
| 166 | |
| 167 ASSERT(compositingLayer); | |
| 168 | |
| 169 // Get quads for node in absolute coordinates. | |
| 170 Vector<FloatQuad> quads; | |
| 171 computeQuads(*m_node->renderer(), quads); | |
| 172 ASSERT(quads.size()); | |
| 173 | |
| 174 // Adjust for offset between target graphics layer and the node's renderer. | |
| 175 FloatPoint positionAdjust = IntPoint(m_currentGraphicsLayer->offsetFromRende
rer()); | |
| 176 | |
| 177 Path newPath; | |
| 178 for (size_t quadIndex = 0; quadIndex < quads.size(); ++quadIndex) { | |
| 179 FloatQuad absoluteQuad = quads[quadIndex]; | |
| 180 absoluteQuad.move(-positionAdjust.x(), -positionAdjust.y()); | |
| 181 | |
| 182 // Transform node quads in target absolute coords to local coordinates i
n the compositor layer. | |
| 183 FloatQuad transformedQuad; | |
| 184 convertTargetSpaceQuadToCompositedLayer(absoluteQuad, m_node->renderer()
, compositingLayer->renderer(), transformedQuad); | |
| 185 | |
| 186 // FIXME: for now, we'll only use rounded paths if we have a single node
quad. The reason for this is that | |
| 187 // we may sometimes get a chain of adjacent boxes (e.g. for text nodes)
which end up looking like sausage | |
| 188 // links: these should ideally be merged into a single rect before creat
ing the path, but that's | |
| 189 // another CL. | |
| 190 if (quads.size() == 1 && transformedQuad.isRectilinear() | |
| 191 && !m_owningWebViewImpl->settingsImpl()->mockGestureTapHighlightsEna
bled()) { | |
| 192 FloatSize rectRoundingRadii(3, 3); | |
| 193 newPath.addRoundedRect(transformedQuad.boundingBox(), rectRoundingRa
dii); | |
| 194 } else | |
| 195 addQuadToPath(transformedQuad, newPath); | |
| 196 } | |
| 197 | |
| 198 FloatRect boundingRect = newPath.boundingRect(); | |
| 199 newPath.translate(-toFloatSize(boundingRect.location())); | |
| 200 | |
| 201 bool pathHasChanged = !(newPath == m_path); | |
| 202 if (pathHasChanged) { | |
| 203 m_path = newPath; | |
| 204 m_contentLayer->layer()->setBounds(enclosingIntRect(boundingRect).size()
); | |
| 205 } | |
| 206 | |
| 207 m_contentLayer->layer()->setPosition(boundingRect.location()); | |
| 208 | |
| 209 return pathHasChanged; | |
| 210 } | |
| 211 | |
| 212 void LinkHighlight::paintContents(WebCanvas* canvas, const WebRect& webClipRect,
bool, WebFloatRect&, | |
| 213 WebContentLayerClient::GraphicsContextStatus contextStatus) | |
| 214 { | |
| 215 if (!m_node || !m_node->renderer()) | |
| 216 return; | |
| 217 | |
| 218 GraphicsContext gc(canvas, | |
| 219 contextStatus == WebContentLayerClient::GraphicsContextEnabled ? Graphic
sContext::NothingDisabled : GraphicsContext::FullyDisabled); | |
| 220 IntRect clipRect(IntPoint(webClipRect.x, webClipRect.y), IntSize(webClipRect
.width, webClipRect.height)); | |
| 221 gc.clip(clipRect); | |
| 222 gc.setFillColor(m_node->renderer()->style()->tapHighlightColor()); | |
| 223 gc.fillPath(m_path); | |
| 224 } | |
| 225 | |
| 226 void LinkHighlight::startHighlightAnimationIfNeeded() | |
| 227 { | |
| 228 if (m_isAnimating) | |
| 229 return; | |
| 230 | |
| 231 m_isAnimating = true; | |
| 232 const float startOpacity = 1; | |
| 233 // FIXME: Should duration be configurable? | |
| 234 const float fadeDuration = 0.1f; | |
| 235 const float minPreFadeDuration = 0.1f; | |
| 236 | |
| 237 m_contentLayer->layer()->setOpacity(startOpacity); | |
| 238 | |
| 239 WebCompositorSupport* compositorSupport = Platform::current()->compositorSup
port(); | |
| 240 | |
| 241 OwnPtr<WebFloatAnimationCurve> curve = adoptPtr(compositorSupport->createFlo
atAnimationCurve()); | |
| 242 | |
| 243 curve->add(WebFloatKeyframe(0, startOpacity)); | |
| 244 // Make sure we have displayed for at least minPreFadeDuration before starti
ng to fade out. | |
| 245 float extraDurationRequired = std::max(0.f, minPreFadeDuration - static_cast
<float>(monotonicallyIncreasingTime() - m_startTime)); | |
| 246 if (extraDurationRequired) | |
| 247 curve->add(WebFloatKeyframe(extraDurationRequired, startOpacity)); | |
| 248 // For layout tests we don't fade out. | |
| 249 curve->add(WebFloatKeyframe(fadeDuration + extraDurationRequired, layoutTest
Mode() ? startOpacity : 0)); | |
| 250 | |
| 251 OwnPtr<WebCompositorAnimation> animation = adoptPtr(compositorSupport->creat
eAnimation(*curve, WebCompositorAnimation::TargetPropertyOpacity)); | |
| 252 | |
| 253 m_contentLayer->layer()->setDrawsContent(true); | |
| 254 m_contentLayer->layer()->addAnimation(animation.leakPtr()); | |
| 255 | |
| 256 invalidate(); | |
| 257 m_owningWebViewImpl->scheduleAnimation(); | |
| 258 } | |
| 259 | |
| 260 void LinkHighlight::clearGraphicsLayerLinkHighlightPointer() | |
| 261 { | |
| 262 if (m_currentGraphicsLayer) { | |
| 263 m_currentGraphicsLayer->removeLinkHighlight(this); | |
| 264 m_currentGraphicsLayer = 0; | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 void LinkHighlight::notifyAnimationStarted(double, WebCompositorAnimation::Targe
tProperty) | |
| 269 { | |
| 270 } | |
| 271 | |
| 272 void LinkHighlight::notifyAnimationFinished(double, WebCompositorAnimation::Targ
etProperty) | |
| 273 { | |
| 274 // Since WebViewImpl may hang on to us for a while, make sure we | |
| 275 // release resources as soon as possible. | |
| 276 clearGraphicsLayerLinkHighlightPointer(); | |
| 277 releaseResources(); | |
| 278 } | |
| 279 | |
| 280 void LinkHighlight::updateGeometry() | |
| 281 { | |
| 282 // To avoid unnecessary updates (e.g. other entities have requested animatio
ns from our WebViewImpl), | |
| 283 // only proceed if we actually requested an update. | |
| 284 if (!m_geometryNeedsUpdate) | |
| 285 return; | |
| 286 | |
| 287 m_geometryNeedsUpdate = false; | |
| 288 | |
| 289 RenderLayer* compositingLayer = computeEnclosingCompositingLayer(); | |
| 290 if (compositingLayer && computeHighlightLayerPathAndPosition(compositingLaye
r)) { | |
| 291 // We only need to invalidate the layer if the highlight size has change
d, otherwise | |
| 292 // we can just re-position the layer without needing to repaint. | |
| 293 m_contentLayer->layer()->invalidate(); | |
| 294 | |
| 295 if (m_currentGraphicsLayer) | |
| 296 m_currentGraphicsLayer->addRepaintRect(FloatRect(layer()->position()
.x, layer()->position().y, layer()->bounds().width, layer()->bounds().height)); | |
| 297 } else if (!m_node || !m_node->renderer()) { | |
| 298 clearGraphicsLayerLinkHighlightPointer(); | |
| 299 releaseResources(); | |
| 300 } | |
| 301 } | |
| 302 | |
| 303 void LinkHighlight::clearCurrentGraphicsLayer() | |
| 304 { | |
| 305 m_currentGraphicsLayer = 0; | |
| 306 m_geometryNeedsUpdate = true; | |
| 307 } | |
| 308 | |
| 309 void LinkHighlight::invalidate() | |
| 310 { | |
| 311 // Make sure we update geometry on the next callback from WebViewImpl::layou
t(). | |
| 312 m_geometryNeedsUpdate = true; | |
| 313 } | |
| 314 | |
| 315 WebLayer* LinkHighlight::layer() | |
| 316 { | |
| 317 return clipLayer(); | |
| 318 } | |
| 319 | |
| 320 } // namespace blink | |
| OLD | NEW |