1 /* 2 * Copyright 2012, The Android Open Source Project 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 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #define LOG_TAG "BaseLayerAndroid" 27 #define LOG_NDEBUG 1 28 29 #include "config.h" 30 #include "BaseLayerAndroid.h" 31 32 #include "AndroidLog.h" 33 #include "CachedImage.h" 34 #include "ClassTracker.h" 35 #include "DrawQuadData.h" 36 #include "FixedPositioning.h" 37 #include "GLWebViewState.h" 38 #include "ImagesManager.h" 39 #include "LayerContent.h" 40 #include "RenderStyle.h" 41 #include "StyleCachedImage.h" 42 #include "TilesManager.h" 43 44 namespace WebCore { 45 46 // Note: this must match the use of ID 0 specifying the base layer in DrawExtra 47 #define BASE_UNIQUE_ID 0 48 49 BaseLayerAndroid::BaseLayerAndroid(LayerContent* content) 50 : LayerAndroid((RenderLayer*)0) 51 , m_color(Color::white) 52 , m_positionsCalculated(false) 53 { 54 if (content) { 55 setContent(content); 56 setSize(content->width(), content->height()); 57 } 58 m_uniqueId = BASE_UNIQUE_ID; 59 } 60 61 void BaseLayerAndroid::getLocalTransform(SkMatrix* matrix) const 62 { 63 matrix->reset(); 64 // base layer doesn't use size in transform calculation 65 matrix->preConcat(getMatrix()); 66 } 67 68 IFrameLayerAndroid* BaseLayerAndroid::updatePosition(SkRect viewport, 69 IFrameLayerAndroid* parentIframeLayer) 70 { 71 if (viewport.fRight > getWidth() || viewport.fBottom > getHeight()) { 72 // To handle the viewport expanding past the layer's size with HW accel, 73 // expand the size of the layer, so that tiles will cover the viewport. 74 setSize(std::max(viewport.fRight, getWidth()), 75 std::max(viewport.fBottom, getHeight())); 76 } 77 78 return LayerAndroid::updatePosition(viewport, parentIframeLayer); 79 } 80 81 void BaseLayerAndroid::updatePositionsRecursive(const SkRect& visibleContentRect) 82 { 83 TRACE_METHOD(); 84 85 updateLayerPositions(visibleContentRect); 86 TransformationMatrix ident; 87 88 // Start with an unnecessarily large clip, since the base layer can 89 // dynamically increase in size to cover the viewport, and we cache its draw 90 // clip. This way the base layer will never have it's visible area clipped 91 // by its m_clippingRect, only the viewport. 92 // Note: values larger than this suffer from floating point rounding issues 93 FloatRect clip(0, 0, 1e7, 1e7); 94 95 bool forcePositionCalculation = !m_positionsCalculated; 96 float scale = 1.0f; 97 // To minimize tearing in single surface mode, don't update the fixed element 98 // when scrolling. The fixed element will move incorrectly when scrolling, 99 // but its position will be corrected after scrolling. 100 bool disableFixedElemUpdate = false; 101 GLWebViewState* webViewState = state(); 102 if (webViewState) { 103 scale = webViewState->scale(); 104 disableFixedElemUpdate = webViewState->isScrolling() 105 && webViewState->isSingleSurfaceRenderingMode(); 106 } 107 updateGLPositionsAndScale(ident, clip, 1, scale, forcePositionCalculation, 108 disableFixedElemUpdate); 109 110 m_positionsCalculated = true; 111 } 112 113 ForegroundBaseLayerAndroid::ForegroundBaseLayerAndroid(LayerContent* content) 114 : LayerAndroid((RenderLayer*)0) 115 { 116 setIntrinsicallyComposited(true); 117 } 118 119 FixedBackgroundImageLayerAndroid::FixedBackgroundImageLayerAndroid(PassRefPtr<RenderStyle> aStyle, 120 int w, int h) 121 : LayerAndroid((RenderLayer*)0) 122 , m_width(w) 123 , m_height(h) 124 { 125 RefPtr<RenderStyle> style = aStyle; 126 FillLayer* layers = style->accessBackgroundLayers(); 127 StyleImage* styleImage = layers->image(); 128 CachedImage* cachedImage = static_cast<StyleCachedImage*>(styleImage)->cachedImage(); 129 WebCore::Image* image = cachedImage->image(); 130 setContentsImage(image->nativeImageForCurrentFrame()); 131 setSize(image->width(), image->height()); 132 133 setIntrinsicallyComposited(true); 134 135 SkLength left, top; 136 left = SkLength::convertLength(style->backgroundXPosition()); 137 top = SkLength::convertLength(style->backgroundYPosition()); 138 139 BackgroundImagePositioning* position = new BackgroundImagePositioning(this); 140 position->setRepeatX(style->backgroundRepeatX() != WebCore::NoRepeatFill); 141 position->setRepeatY(style->backgroundRepeatY() != WebCore::NoRepeatFill); 142 143 setFixedPosition(position); 144 position->setPosition(left, top); 145 146 #ifdef DEBUG_COUNT 147 ClassTracker::instance()->increment("FixedBackgroundImageLayerAndroid"); 148 #endif 149 } 150 151 FixedBackgroundImageLayerAndroid::FixedBackgroundImageLayerAndroid(const FixedBackgroundImageLayerAndroid& layer) 152 : LayerAndroid(layer) 153 , m_width(layer.m_width) 154 , m_height(layer.m_height) 155 { 156 #ifdef DEBUG_COUNT 157 ClassTracker::instance()->increment("FixedBackgroundImageLayerAndroid"); 158 #endif 159 } 160 161 FixedBackgroundImageLayerAndroid::~FixedBackgroundImageLayerAndroid() 162 { 163 #ifdef DEBUG_COUNT 164 ClassTracker::instance()->decrement("FixedBackgroundImageLayerAndroid"); 165 #endif 166 } 167 168 static bool needToDisplayImage(bool repeatX, bool repeatY, float dx, float dy) 169 { 170 // handles the repeat attribute for the background image 171 if (repeatX && repeatY) 172 return true; 173 if (repeatX && !repeatY && dy == 0) 174 return true; 175 if (!repeatX && repeatY && dx == 0) 176 return true; 177 if (dx == 0 && dy == 0) 178 return true; 179 180 return false; 181 } 182 183 // Return true when fast draw succeeds. 184 // For the repeated image content, we just need to draw a single quad and use 185 // the GL shader to repeat. 186 bool FixedBackgroundImageLayerAndroid::drawSimpleQuad(ImageTexture* imageTexture, 187 BackgroundImagePositioning* position, 188 const IntPoint& repeatTimes, 189 const FloatPoint& startPoint, 190 const FloatPoint& origin, 191 const Color& backgroundColor) 192 { 193 // The limitation for current implementation is that we can only speed up 194 // single tile size image. 195 // TODO: add the fast path to imageTexture which contains >1 tiles. 196 GLuint imageTextureId = imageTexture->getImageTextureId(); 197 if (!imageTextureId) 198 return false; 199 200 int nbX = repeatTimes.x(); 201 int nbY = repeatTimes.y(); 202 float startX = startPoint.x(); 203 float startY = startPoint.y(); 204 bool repeatX = position->repeatX(); 205 bool repeatY = position->repeatY(); 206 207 // Draw the entire background when repeat only in one direction or no repeat. 208 if (!repeatX || !repeatY) { 209 SkRect backgroundRect; 210 backgroundRect.fLeft = origin.x() - startX; 211 backgroundRect.fTop = origin.y() - startY; 212 backgroundRect.fRight = backgroundRect.fLeft + getWidth() * nbX; 213 backgroundRect.fBottom = backgroundRect.fTop + getHeight() * nbY; 214 PureColorQuadData backgroundData(backgroundColor, BaseQuad, 215 0, &backgroundRect, 1.0, true); 216 TilesManager::instance()->shader()->drawQuad(&backgroundData); 217 } 218 219 // Now draw the repeated images. 220 // We set the quad size as the image size, then imageRepeatRanges will 221 // control how many times the image will be repeated by expanding the 222 // quad and texture coordinates. 223 // The image size can be smaller than a tile, so repeatScale will passed 224 // into the shader to scale the texture coordinates. 225 SkRect imageRect = SkRect::MakeXYWH(0, 0, getWidth(), getHeight()); 226 FloatRect imageRepeatRanges(0, 0, repeatX ? nbX : 1, repeatY ? nbY : 1); 227 228 FloatSize repeatScale(float(getWidth()) / TilesManager::tileWidth(), 229 float(getHeight()) / TilesManager::tileHeight()); 230 231 ALOGV("repeatedQuadData: startX %f, startY %f , getWidth() %f, getHeight() %f," 232 " nbX %d, nbY %d, repeatImageTimesX, repeatImageTimesY %d %d" 233 " repeatScale width %f, height %f, origin x %f y %f", 234 startX , startY , getWidth(), getHeight(), nbX , nbY, 235 imageRepeatRanges.width(), imageRepeatRanges.height(), 236 repeatScale.width(), repeatScale.height(), origin.x(), origin.y()); 237 238 // Adding startX and startY into the transform can handle the fixed right / 239 // fixed bottom case. 240 TransformationMatrix matrix = *drawTransform(); 241 matrix.translate(repeatX ? -startX : 0, repeatY ? -startY : 0); 242 243 TextureQuadData repeatedQuadData(imageTextureId, GL_TEXTURE_2D, GL_LINEAR, 244 LayerQuad, &matrix, &imageRect, getOpacity(), 245 true, imageRepeatRanges, repeatScale); 246 TilesManager::instance()->shader()->drawQuad(&repeatedQuadData); 247 return true; 248 } 249 250 void FixedBackgroundImageLayerAndroid::drawRepeatedGrid(ImageTexture* imageTexture, 251 BackgroundImagePositioning* position, 252 const IntPoint& repeatTimes, 253 const FloatPoint& startPoint, 254 const FloatPoint& origin, 255 const Color& backgroundColor) 256 { 257 // Cover the entire background 258 int nbX = repeatTimes.x(); 259 int nbY = repeatTimes.y(); 260 float startX = startPoint.x(); 261 float startY = startPoint.y(); 262 for (int i = 0; i < nbY; i++) { 263 float dy = (i * getHeight()) - startY; 264 for (int j = 0; j < nbX; j++) { 265 float dx = (j * getWidth()) - startX; 266 if (needToDisplayImage(position->repeatX(), 267 position->repeatY(), 268 dx, dy)) { 269 FloatPoint p(dx, dy); 270 imageTexture->drawGL(this, getOpacity(), &p); 271 } else { 272 // If the image is not displayed, we still need to fill 273 // with the background color 274 SkRect rect; 275 rect.fLeft = origin.x() + dx; 276 rect.fTop = origin.y() + dy; 277 rect.fRight = rect.fLeft + getWidth(); 278 rect.fBottom = rect.fTop + getHeight(); 279 PureColorQuadData backgroundData(backgroundColor, BaseQuad, 280 0, &rect, 1.0); 281 TilesManager::instance()->shader()->drawQuad(&backgroundData); 282 } 283 } 284 } 285 } 286 287 bool FixedBackgroundImageLayerAndroid::drawGL(bool layerTilesDisabled) 288 { 289 if (layerTilesDisabled) 290 return false; 291 if (!m_imageCRC) 292 return false; 293 294 ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC); 295 if (!imageTexture) { 296 ImagesManager::instance()->releaseImage(m_imageCRC); 297 return false; 298 } 299 300 // We have a fixed background image, let's draw it 301 if (m_fixedPosition && m_fixedPosition->isBackgroundImagePositioning()) { 302 BackgroundImagePositioning* position = 303 static_cast<BackgroundImagePositioning*>(m_fixedPosition); 304 305 IntPoint repeatTimes(position->nbRepeatX(), position->nbRepeatY()); 306 FloatPoint startPoint(position->offsetX() * getWidth(), 307 position->offsetY() * getHeight()); 308 309 FloatPoint origin; 310 origin = drawTransform()->mapPoint(origin); 311 312 Color backgroundColor = Color((int)SkColorGetR(m_backgroundColor), 313 (int)SkColorGetG(m_backgroundColor), 314 (int)SkColorGetB(m_backgroundColor), 315 (int)SkColorGetA(m_backgroundColor)); 316 317 bool drawSimpleQuadSuccess = drawSimpleQuad(imageTexture, position, 318 repeatTimes, startPoint, 319 origin, backgroundColor); 320 321 if (!drawSimpleQuadSuccess) { 322 drawRepeatedGrid(imageTexture, position, repeatTimes, startPoint, 323 origin, backgroundColor); 324 } 325 } else 326 imageTexture->drawGL(this, getOpacity()); 327 328 ImagesManager::instance()->releaseImage(m_imageCRC); 329 330 return false; 331 } 332 333 Image* FixedBackgroundImageLayerAndroid::GetCachedImage(PassRefPtr<RenderStyle> aStyle) 334 { 335 RefPtr<RenderStyle> style = aStyle; 336 if (!style) 337 return 0; 338 339 if (!style->hasFixedBackgroundImage()) 340 return 0; 341 342 FillLayer* layers = style->accessBackgroundLayers(); 343 StyleImage* styleImage = layers->image(); 344 345 if (!styleImage) 346 return 0; 347 348 if (!styleImage->isLoaded()) 349 return 0; 350 351 if (!styleImage->isCachedImage()) 352 return 0; 353 354 CachedImage* cachedImage = static_cast<StyleCachedImage*>(styleImage)->cachedImage(); 355 356 Image* image = cachedImage->image(); 357 358 if (image && !image->nativeImageForCurrentFrame()) 359 return 0; 360 361 if (image == Image::nullImage()) 362 return 0; 363 364 return image; 365 } 366 367 } // namespace WebCore 368