1 package org
.mozilla
.gecko
.gfx
;
3 import android
.content
.ComponentCallbacks2
;
4 import android
.content
.Context
;
5 import android
.content
.res
.Configuration
;
6 import android
.graphics
.RectF
;
7 import android
.graphics
.Region
;
8 import android
.util
.Log
;
10 import org
.libreoffice
.LOKitShell
;
11 import org
.libreoffice
.TileIdentifier
;
12 import org
.mozilla
.gecko
.util
.FloatUtils
;
14 import java
.util
.ArrayList
;
15 import java
.util
.Iterator
;
16 import java
.util
.List
;
17 import java
.util
.concurrent
.locks
.Lock
;
18 import java
.util
.concurrent
.locks
.ReadWriteLock
;
19 import java
.util
.concurrent
.locks
.ReentrantReadWriteLock
;
21 public abstract class ComposedTileLayer
extends Layer
implements ComponentCallbacks2
{
22 private static final String LOGTAG
= ComposedTileLayer
.class.getSimpleName();
24 protected final List
<SubTile
> tiles
= new ArrayList
<SubTile
>();
26 protected final IntSize tileSize
;
27 private final ReadWriteLock tilesReadWriteLock
= new ReentrantReadWriteLock();
28 private final Lock tilesReadLock
= tilesReadWriteLock
.readLock();
29 private final Lock tilesWriteLock
= tilesReadWriteLock
.writeLock();
31 protected RectF currentViewport
= new RectF();
32 protected float currentZoom
= 1.0f
;
33 protected RectF currentPageRect
= new RectF();
35 private long reevaluationNanoTime
= 0;
37 public ComposedTileLayer(Context context
) {
38 context
.registerComponentCallbacks(this);
39 this.tileSize
= new IntSize(256, 256);
42 protected static RectF
roundToTileSize(RectF input
, IntSize tileSize
) {
43 float minX
= ((int) (input
.left
/ tileSize
.width
)) * tileSize
.width
;
44 float minY
= ((int) (input
.top
/ tileSize
.height
)) * tileSize
.height
;
45 float maxX
= ((int) (input
.right
/ tileSize
.width
) + 1) * tileSize
.width
;
46 float maxY
= ((int) (input
.bottom
/ tileSize
.height
) + 1) * tileSize
.height
;
47 return new RectF(minX
, minY
, maxX
, maxY
);
50 protected static RectF
inflate(RectF rect
, IntSize inflateSize
) {
51 RectF newRect
= new RectF(rect
);
52 newRect
.left
-= inflateSize
.width
;
53 newRect
.left
= newRect
.left
< 0.0f ?
0.0f
: newRect
.left
;
55 newRect
.top
-= inflateSize
.height
;
56 newRect
.top
= newRect
.top
< 0.0f ?
0.0f
: newRect
.top
;
58 newRect
.right
+= inflateSize
.width
;
59 newRect
.bottom
+= inflateSize
.height
;
64 protected static RectF
normalizeRect(RectF rect
, float sourceFactor
, float targetFactor
) {
66 (rect
.left
/ sourceFactor
) * targetFactor
,
67 (rect
.top
/ sourceFactor
) * targetFactor
,
68 (rect
.right
/ sourceFactor
) * targetFactor
,
69 (rect
.bottom
/ sourceFactor
) * targetFactor
);
72 public void invalidate() {
74 for (SubTile tile
: tiles
) {
77 tilesReadLock
.unlock();
81 public void beginTransaction() {
82 super.beginTransaction();
84 for (SubTile tile
: tiles
) {
85 tile
.beginTransaction();
87 tilesReadLock
.unlock();
91 public void endTransaction() {
93 for (SubTile tile
: tiles
) {
94 tile
.endTransaction();
96 tilesReadLock
.unlock();
97 super.endTransaction();
101 public void draw(RenderContext context
) {
102 tilesReadLock
.lock();
103 for (SubTile tile
: tiles
) {
104 if (RectF
.intersects(tile
.getBounds(context
), context
.viewport
)) {
108 tilesReadLock
.unlock();
112 protected void performUpdates(RenderContext context
) {
113 super.performUpdates(context
);
115 tilesReadLock
.lock();
116 for (SubTile tile
: tiles
) {
117 tile
.beginTransaction();
118 tile
.refreshTileMetrics();
119 tile
.endTransaction();
120 tile
.performUpdates(context
);
122 tilesReadLock
.unlock();
126 public Region
getValidRegion(RenderContext context
) {
127 Region validRegion
= new Region();
128 tilesReadLock
.lock();
129 for (SubTile tile
: tiles
) {
130 validRegion
.op(tile
.getValidRegion(context
), Region
.Op
.UNION
);
132 tilesReadLock
.unlock();
137 public void setResolution(float newResolution
) {
138 super.setResolution(newResolution
);
139 tilesReadLock
.lock();
140 for (SubTile tile
: tiles
) {
141 tile
.setResolution(newResolution
);
143 tilesReadLock
.unlock();
146 public void reevaluateTiles(ImmutableViewportMetrics viewportMetrics
, DisplayPortMetrics mDisplayPort
) {
147 RectF newViewPort
= getViewPort(viewportMetrics
);
148 float newZoom
= getZoom(viewportMetrics
);
151 if (newZoom
<= 0.0 || Float
.isNaN(newZoom
)) {
155 if (currentViewport
.equals(newViewPort
) && FloatUtils
.fuzzyEquals(currentZoom
, newZoom
)) {
159 long currentReevaluationNanoTime
= System
.nanoTime();
160 if ((currentReevaluationNanoTime
- reevaluationNanoTime
) < 25 * 1000000) {
164 reevaluationNanoTime
= currentReevaluationNanoTime
;
166 currentViewport
= newViewPort
;
167 currentZoom
= newZoom
;
168 currentPageRect
= viewportMetrics
.getPageRect();
170 LOKitShell
.sendTileReevaluationRequest(this);
173 protected abstract RectF
getViewPort(ImmutableViewportMetrics viewportMetrics
);
175 protected abstract float getZoom(ImmutableViewportMetrics viewportMetrics
);
177 protected abstract int getTilePriority();
179 private boolean containsTilesMatching(float x
, float y
, float currentZoom
) {
180 tilesReadLock
.lock();
182 for (SubTile tile
: tiles
) {
183 if (tile
.id
.x
== x
&& tile
.id
.y
== y
&& tile
.id
.zoom
== currentZoom
) {
189 tilesReadLock
.unlock();
193 public void addNewTiles(List
<SubTile
> newTiles
) {
194 for (float y
= currentViewport
.top
; y
< currentViewport
.bottom
; y
+= tileSize
.height
) {
195 if (y
> currentPageRect
.height()) {
198 for (float x
= currentViewport
.left
; x
< currentViewport
.right
; x
+= tileSize
.width
) {
199 if (x
> currentPageRect
.width()) {
202 if (!containsTilesMatching(x
, y
, currentZoom
)) {
203 TileIdentifier tileId
= new TileIdentifier((int) x
, (int) y
, currentZoom
, tileSize
);
204 SubTile tile
= createNewTile(tileId
);
211 public void clearMarkedTiles() {
212 tilesWriteLock
.lock();
213 Iterator
<SubTile
> iterator
= tiles
.iterator();
214 while (iterator
.hasNext()) {
215 SubTile tile
= iterator
.next();
216 if (tile
.markedForRemoval
) {
221 tilesWriteLock
.unlock();
224 public void markTiles() {
225 tilesReadLock
.lock();
226 for (SubTile tile
: tiles
) {
227 if (FloatUtils
.fuzzyEquals(tile
.id
.zoom
, currentZoom
)) {
228 RectF tileRect
= tile
.id
.getRectF();
229 if (!RectF
.intersects(currentViewport
, tileRect
)) {
230 tile
.markForRemoval();
233 tile
.markForRemoval();
236 tilesReadLock
.unlock();
239 public void clearAndReset() {
240 tilesWriteLock
.lock();
242 tilesWriteLock
.unlock();
243 currentViewport
= new RectF();
246 private SubTile
createNewTile(TileIdentifier tileId
) {
247 SubTile tile
= new SubTile(tileId
);
248 tile
.beginTransaction();
249 tilesWriteLock
.lock();
251 tilesWriteLock
.unlock();
255 public boolean isStillValid(TileIdentifier tileId
) {
256 return RectF
.intersects(currentViewport
, tileId
.getRectF()) || currentViewport
.contains(tileId
.getRectF());
260 * Invalidate tiles which intersect the input rect
262 public void invalidateTiles(List
<SubTile
> tilesToInvalidate
, RectF cssRect
) {
263 RectF zoomedRect
= RectUtils
.scale(cssRect
, currentZoom
);
264 tilesReadLock
.lock();
265 for (SubTile tile
: tiles
) {
266 if (!tile
.markedForRemoval
&& RectF
.intersects(zoomedRect
, tile
.id
.getRectF())) {
267 tilesToInvalidate
.add(tile
);
270 tilesReadLock
.unlock();
274 public void onConfigurationChanged(Configuration newConfig
) {
278 public void onLowMemory() {
279 Log
.i(LOGTAG
, "onLowMemory");
283 public void onTrimMemory(int level
) {
284 if (level
>= 15 /*TRIM_MEMORY_RUNNING_CRITICAL*/) {
285 Log
.i(LOGTAG
, "Trimming memory - TRIM_MEMORY_RUNNING_CRITICAL");
286 } else if (level
>= 10 /*TRIM_MEMORY_RUNNING_LOW*/) {
287 Log
.i(LOGTAG
, "Trimming memory - TRIM_MEMORY_RUNNING_LOW");