• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
BaseLayerAndroid(LayerContent * content)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 
getLocalTransform(SkMatrix * matrix) const61 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 
updatePosition(SkRect viewport,IFrameLayerAndroid * parentIframeLayer)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 
updatePositionsRecursive(const SkRect & visibleContentRect)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 
ForegroundBaseLayerAndroid(LayerContent * content)113 ForegroundBaseLayerAndroid::ForegroundBaseLayerAndroid(LayerContent* content)
114     : LayerAndroid((RenderLayer*)0)
115 {
116     setIntrinsicallyComposited(true);
117 }
118 
FixedBackgroundImageLayerAndroid(PassRefPtr<RenderStyle> aStyle,int w,int h)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 
FixedBackgroundImageLayerAndroid(const FixedBackgroundImageLayerAndroid & layer)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 
~FixedBackgroundImageLayerAndroid()161 FixedBackgroundImageLayerAndroid::~FixedBackgroundImageLayerAndroid()
162 {
163 #ifdef DEBUG_COUNT
164     ClassTracker::instance()->decrement("FixedBackgroundImageLayerAndroid");
165 #endif
166 }
167 
needToDisplayImage(bool repeatX,bool repeatY,float dx,float dy)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.
drawSimpleQuad(ImageTexture * imageTexture,BackgroundImagePositioning * position,const IntPoint & repeatTimes,const FloatPoint & startPoint,const FloatPoint & origin,const Color & backgroundColor)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 
drawRepeatedGrid(ImageTexture * imageTexture,BackgroundImagePositioning * position,const IntPoint & repeatTimes,const FloatPoint & startPoint,const FloatPoint & origin,const Color & backgroundColor)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 
drawGL(bool layerTilesDisabled)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 
GetCachedImage(PassRefPtr<RenderStyle> aStyle)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