Avoid potential negative array index access to cached text.
[LibreOffice.git] / android / source / src / java / org / mozilla / gecko / gfx / ComposedTileLayer.java
blobbdef7022186aad89acde362e91dd81677717d94a
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;
61 return newRect;
64 protected static RectF normalizeRect(RectF rect, float sourceFactor, float targetFactor) {
65 return new RectF(
66 (rect.left / sourceFactor) * targetFactor,
67 (rect.top / sourceFactor) * targetFactor,
68 (rect.right / sourceFactor) * targetFactor,
69 (rect.bottom / sourceFactor) * targetFactor);
72 public void invalidate() {
73 tilesReadLock.lock();
74 for (SubTile tile : tiles) {
75 tile.invalidate();
77 tilesReadLock.unlock();
80 @Override
81 public void beginTransaction() {
82 super.beginTransaction();
83 tilesReadLock.lock();
84 for (SubTile tile : tiles) {
85 tile.beginTransaction();
87 tilesReadLock.unlock();
90 @Override
91 public void endTransaction() {
92 tilesReadLock.lock();
93 for (SubTile tile : tiles) {
94 tile.endTransaction();
96 tilesReadLock.unlock();
97 super.endTransaction();
100 @Override
101 public void draw(RenderContext context) {
102 tilesReadLock.lock();
103 for (SubTile tile : tiles) {
104 if (RectF.intersects(tile.getBounds(context), context.viewport)) {
105 tile.draw(context);
108 tilesReadLock.unlock();
111 @Override
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();
125 @Override
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();
133 return validRegion;
136 @Override
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);
150 // When
151 if (newZoom <= 0.0 || Float.isNaN(newZoom)) {
152 return;
155 if (currentViewport.equals(newViewPort) && FloatUtils.fuzzyEquals(currentZoom, newZoom)) {
156 return;
159 long currentReevaluationNanoTime = System.nanoTime();
160 if ((currentReevaluationNanoTime - reevaluationNanoTime) < 25 * 1000000) {
161 return;
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();
181 try {
182 for (SubTile tile : tiles) {
183 if (tile.id.x == x && tile.id.y == y && tile.id.zoom == currentZoom) {
184 return true;
187 return false;
188 } finally {
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()) {
196 continue;
198 for (float x = currentViewport.left; x < currentViewport.right; x += tileSize.width) {
199 if (x > currentPageRect.width()) {
200 continue;
202 if (!containsTilesMatching(x, y, currentZoom)) {
203 TileIdentifier tileId = new TileIdentifier((int) x, (int) y, currentZoom, tileSize);
204 SubTile tile = createNewTile(tileId);
205 newTiles.add(tile);
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) {
217 tile.destroy();
218 iterator.remove();
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();
232 } else {
233 tile.markForRemoval();
236 tilesReadLock.unlock();
239 public void clearAndReset() {
240 tilesWriteLock.lock();
241 tiles.clear();
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();
250 tiles.add(tile);
251 tilesWriteLock.unlock();
252 return tile;
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();
273 @Override
274 public void onConfigurationChanged(Configuration newConfig) {
277 @Override
278 public void onLowMemory() {
279 Log.i(LOGTAG, "onLowMemory");
282 @Override
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");