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