1 /* 2 * Copyright (C) 2007, 2008 Rob Buis <buis (at) kde.org> 3 * Copyright (C) 2007 Nikolas Zimmermann <zimmermann (at) kde.org> 4 * Copyright (C) 2007 Eric Seidel <eric (at) webkit.org> 5 * Copyright (C) 2009 Google, Inc. All rights reserved. 6 * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org> 7 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Library General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Library General Public License for more details. 18 * 19 * You should have received a copy of the GNU Library General Public License 20 * along with this library; see the file COPYING.LIB. If not, write to 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301, USA. 23 */ 24 25 #include "config.h" 26 27 #include "core/rendering/svg/SVGRenderingContext.h" 28 29 #include "core/frame/FrameHost.h" 30 #include "core/frame/FrameView.h" 31 #include "core/frame/LocalFrame.h" 32 #include "core/frame/Settings.h" 33 #include "core/paint/SVGImagePainter.h" 34 #include "core/rendering/RenderLayer.h" 35 #include "core/rendering/svg/RenderSVGImage.h" 36 #include "core/rendering/svg/RenderSVGResource.h" 37 #include "core/rendering/svg/RenderSVGResourceFilter.h" 38 #include "core/rendering/svg/RenderSVGResourceMasker.h" 39 #include "core/rendering/svg/SVGResources.h" 40 #include "core/rendering/svg/SVGResourcesCache.h" 41 #include "platform/FloatConversion.h" 42 43 static int kMaxImageBufferSize = 4096; 44 45 namespace blink { 46 47 static inline bool isRenderingMaskImage(RenderObject* object) 48 { 49 if (object->frame() && object->frame()->view()) 50 return object->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask; 51 return false; 52 } 53 54 SVGRenderingContext::~SVGRenderingContext() 55 { 56 // Fast path if we don't need to restore anything. 57 if (!(m_renderingFlags & ActionsNeeded)) 58 return; 59 60 ASSERT(m_object && m_paintInfo); 61 62 if (m_renderingFlags & PostApplyResources) { 63 ASSERT(m_masker || m_clipper || m_filter); 64 ASSERT(SVGResourcesCache::cachedResourcesForRenderObject(m_object)); 65 66 if (m_filter) { 67 ASSERT(SVGResourcesCache::cachedResourcesForRenderObject(m_object)->filter() == m_filter); 68 m_filter->postApplyResource(m_object, m_paintInfo->context); 69 m_paintInfo->context = m_savedContext; 70 m_paintInfo->rect = m_savedPaintRect; 71 } 72 73 if (m_clipper) { 74 ASSERT(SVGResourcesCache::cachedResourcesForRenderObject(m_object)->clipper() == m_clipper); 75 m_clipper->postApplyStatefulResource(m_object, m_paintInfo->context, m_clipperState); 76 } 77 78 if (m_masker) { 79 ASSERT(SVGResourcesCache::cachedResourcesForRenderObject(m_object)->masker() == m_masker); 80 m_masker->postApplyResource(m_object, m_paintInfo->context); 81 } 82 } 83 84 if (m_renderingFlags & EndOpacityLayer) 85 m_paintInfo->context->endLayer(); 86 87 if (m_renderingFlags & RestoreGraphicsContext) 88 m_paintInfo->context->restore(); 89 } 90 91 void SVGRenderingContext::prepareToRenderSVGContent(RenderObject* object, PaintInfo& paintInfo) 92 { 93 ASSERT(object); 94 95 #if ENABLE(ASSERT) 96 // This function must not be called twice! 97 ASSERT(!(m_renderingFlags & PrepareToRenderSVGContentWasCalled)); 98 m_renderingFlags |= PrepareToRenderSVGContentWasCalled; 99 #endif 100 101 m_object = object; 102 m_paintInfo = &paintInfo; 103 m_filter = 0; 104 105 RenderStyle* style = m_object->style(); 106 ASSERT(style); 107 108 const SVGRenderStyle& svgStyle = style->svgStyle(); 109 110 // Setup transparency layers before setting up SVG resources! 111 bool isRenderingMask = isRenderingMaskImage(m_object); 112 // RenderLayer takes care of root opacity. 113 float opacity = (object->isSVGRoot() || isRenderingMask) ? 1 : style->opacity(); 114 bool hasBlendMode = style->hasBlendMode() && !isRenderingMask; 115 116 if (opacity < 1 || hasBlendMode || style->hasIsolation()) { 117 FloatRect paintInvalidationRect = m_object->paintInvalidationRectInLocalCoordinates(); 118 m_paintInfo->context->clip(paintInvalidationRect); 119 120 if (hasBlendMode) { 121 if (!(m_renderingFlags & RestoreGraphicsContext)) { 122 m_paintInfo->context->save(); 123 m_renderingFlags |= RestoreGraphicsContext; 124 } 125 m_paintInfo->context->setCompositeOperation(CompositeSourceOver, style->blendMode()); 126 } 127 128 m_paintInfo->context->beginTransparencyLayer(opacity); 129 130 if (hasBlendMode) 131 m_paintInfo->context->setCompositeOperation(CompositeSourceOver, WebBlendModeNormal); 132 133 m_renderingFlags |= EndOpacityLayer; 134 } 135 136 ClipPathOperation* clipPathOperation = style->clipPath(); 137 if (clipPathOperation && clipPathOperation->type() == ClipPathOperation::SHAPE) { 138 ShapeClipPathOperation* clipPath = toShapeClipPathOperation(clipPathOperation); 139 m_paintInfo->context->clipPath(clipPath->path(object->objectBoundingBox()), clipPath->windRule()); 140 } 141 142 SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(m_object); 143 if (!resources) { 144 if (svgStyle.hasFilter()) 145 return; 146 147 m_renderingFlags |= RenderingPrepared; 148 return; 149 } 150 151 if (!isRenderingMask) { 152 if (RenderSVGResourceMasker* masker = resources->masker()) { 153 if (!masker->applyResource(m_object, style, m_paintInfo->context, ApplyToDefaultMode)) 154 return; 155 m_masker = masker; 156 m_renderingFlags |= PostApplyResources; 157 } 158 } 159 160 RenderSVGResourceClipper* clipper = resources->clipper(); 161 if (!clipPathOperation && clipper) { 162 if (!clipper->applyStatefulResource(m_object, m_paintInfo->context, m_clipperState)) 163 return; 164 m_clipper = clipper; 165 m_renderingFlags |= PostApplyResources; 166 } 167 168 if (!isRenderingMask) { 169 m_filter = resources->filter(); 170 if (m_filter) { 171 m_savedContext = m_paintInfo->context; 172 m_savedPaintRect = m_paintInfo->rect; 173 // Return with false here may mean that we don't need to draw the content 174 // (because it was either drawn before or empty) but we still need to apply the filter. 175 m_renderingFlags |= PostApplyResources; 176 if (!m_filter->applyResource(m_object, style, m_paintInfo->context, ApplyToDefaultMode)) 177 return; 178 179 // Since we're caching the resulting bitmap and do not invalidate it on paint invalidation rect 180 // changes, we need to paint the whole filter region. Otherwise, elements not visible 181 // at the time of the initial paint (due to scrolling, window size, etc.) will never 182 // be drawn. 183 m_paintInfo->rect = IntRect(m_filter->drawingRegion(m_object)); 184 } 185 } 186 187 m_renderingFlags |= RenderingPrepared; 188 } 189 190 static AffineTransform& currentContentTransformation() 191 { 192 DEFINE_STATIC_LOCAL(AffineTransform, s_currentContentTransformation, ()); 193 return s_currentContentTransformation; 194 } 195 196 float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObject* renderer) 197 { 198 ASSERT(renderer); 199 200 AffineTransform ctm; 201 // FIXME: calculateDeviceSpaceTransformation() queries layer compositing state - which is not 202 // supported during layout. Hence, the result may not include all CSS transforms. 203 calculateDeviceSpaceTransformation(renderer, ctm); 204 return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2)); 205 } 206 207 void SVGRenderingContext::calculateDeviceSpaceTransformation(const RenderObject* renderer, AffineTransform& absoluteTransform) 208 { 209 // FIXME: trying to compute a device space transform at record time is wrong. All clients 210 // should be updated to avoid relying on this information, and the method should be removed. 211 212 ASSERT(renderer); 213 // We're about to possibly clear renderer, so save the deviceScaleFactor now. 214 float deviceScaleFactor = renderer->document().frameHost()->deviceScaleFactor(); 215 216 // Walk up the render tree, accumulating SVG transforms. 217 absoluteTransform = currentContentTransformation(); 218 while (renderer) { 219 absoluteTransform = renderer->localToParentTransform() * absoluteTransform; 220 if (renderer->isSVGRoot()) 221 break; 222 renderer = renderer->parent(); 223 } 224 225 // Continue walking up the layer tree, accumulating CSS transforms. 226 RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0; 227 while (layer && layer->isAllowedToQueryCompositingState()) { 228 // We can stop at compositing layers, to match the backing resolution. 229 // FIXME: should we be computing the transform to the nearest composited layer, 230 // or the nearest composited layer that does not paint into its ancestor? 231 // I think this is the nearest composited ancestor since we will inherit its 232 // transforms in the composited layer tree. 233 if (layer->compositingState() != NotComposited) 234 break; 235 236 if (TransformationMatrix* layerTransform = layer->transform()) 237 absoluteTransform = layerTransform->toAffineTransform() * absoluteTransform; 238 239 layer = layer->parent(); 240 } 241 242 absoluteTransform.scale(deviceScaleFactor); 243 } 244 245 void SVGRenderingContext::renderSubtree(GraphicsContext* context, RenderObject* item, const AffineTransform& subtreeContentTransformation) 246 { 247 ASSERT(item); 248 ASSERT(context); 249 250 PaintInfo info(context, PaintInfo::infiniteRect(), PaintPhaseForeground, PaintBehaviorNormal); 251 252 AffineTransform& contentTransformation = currentContentTransformation(); 253 AffineTransform savedContentTransformation = contentTransformation; 254 contentTransformation = subtreeContentTransformation * contentTransformation; 255 256 ASSERT(!item->needsLayout()); 257 item->paint(info, IntPoint()); 258 259 contentTransformation = savedContentTransformation; 260 } 261 262 FloatRect SVGRenderingContext::clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect) 263 { 264 const FloatSize maxImageBufferSize(kMaxImageBufferSize, kMaxImageBufferSize); 265 return FloatRect(absoluteTargetRect.location(), absoluteTargetRect.size().shrunkTo(maxImageBufferSize)); 266 } 267 268 void SVGRenderingContext::clear2DRotation(AffineTransform& transform) 269 { 270 AffineTransform::DecomposedType decomposition; 271 transform.decompose(decomposition); 272 decomposition.angle = 0; 273 transform.recompose(decomposition); 274 } 275 276 bool SVGRenderingContext::bufferForeground(OwnPtr<ImageBuffer>& imageBuffer) 277 { 278 ASSERT(m_paintInfo); 279 ASSERT(m_object->isSVGImage()); 280 FloatRect boundingBox = m_object->objectBoundingBox(); 281 282 // Invalidate an existing buffer if the scale is not correct. 283 if (imageBuffer) { 284 AffineTransform transform = m_paintInfo->context->getCTM(); 285 IntSize expandedBoundingBox = expandedIntSize(boundingBox.size()); 286 IntSize bufferSize(static_cast<int>(ceil(expandedBoundingBox.width() * transform.xScale())), static_cast<int>(ceil(expandedBoundingBox.height() * transform.yScale()))); 287 if (bufferSize != imageBuffer->size()) 288 imageBuffer.clear(); 289 } 290 291 // Create a new buffer and paint the foreground into it. 292 if (!imageBuffer) { 293 if ((imageBuffer = m_paintInfo->context->createRasterBuffer(expandedIntSize(boundingBox.size())))) { 294 GraphicsContext* bufferedRenderingContext = imageBuffer->context(); 295 bufferedRenderingContext->translate(-boundingBox.x(), -boundingBox.y()); 296 PaintInfo bufferedInfo(*m_paintInfo); 297 bufferedInfo.context = bufferedRenderingContext; 298 SVGImagePainter::paintForeground(toRenderSVGImage(*m_object), bufferedInfo); 299 } else 300 return false; 301 } 302 303 m_paintInfo->context->drawImageBuffer(imageBuffer.get(), boundingBox); 304 return true; 305 } 306 307 } // namespace blink 308