blob: 2886961922d646c7bee2b5b6f8b87d111ad28e04 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.consoleproxy.util;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
public class TileTracker {
// 2 dimension tile status snapshot, a true value means the corresponding tile has been invalidated
private boolean[][] snapshot;
private int tileWidth = 0;
private int tileHeight = 0;
private int trackWidth = 0;
private int trackHeight = 0;
public TileTracker() {
}
public int getTileWidth() {
return tileWidth;
}
public void setTileWidth(int tileWidth) {
this.tileWidth = tileWidth;
}
public int getTileHeight() {
return tileHeight;
}
public void setTileHeight(int tileHeight) {
this.tileHeight = tileHeight;
}
public int getTrackWidth() {
return trackWidth;
}
public void setTrackWidth(int trackWidth) {
this.trackWidth = trackWidth;
}
public int getTrackHeight() {
return trackHeight;
}
public void setTrackHeight(int trackHeight) {
this.trackHeight = trackHeight;
}
public void initTracking(int tileWidth, int tileHeight, int trackWidth, int trackHeight) {
assert (tileWidth > 0);
assert (tileHeight > 0);
assert (trackWidth > 0);
assert (trackHeight > 0);
assert (tileWidth <= trackWidth);
assert (tileHeight <= trackHeight);
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.trackWidth = trackWidth;
this.trackHeight = trackHeight;
int cols = getTileCols();
int rows = getTileRows();
snapshot = new boolean[rows][cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
snapshot[i][j] = false;
}
public synchronized void resize(int trackWidth, int trackHeight) {
assert (tileWidth > 0);
assert (tileHeight > 0);
assert (trackWidth > 0);
assert (trackHeight > 0);
this.trackWidth = trackWidth;
this.trackHeight = trackHeight;
int cols = getTileCols();
int rows = getTileRows();
snapshot = new boolean[rows][cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
snapshot[i][j] = true;
}
public void invalidate(Rectangle rect) {
setTileFlag(rect, true);
}
public void validate(Rectangle rect) {
setTileFlag(rect, false);
}
public List<TileInfo> scan(boolean init) {
List<TileInfo> l = new ArrayList<TileInfo>();
synchronized (this) {
for (int i = 0; i < getTileRows(); i++) {
for (int j = 0; j < getTileCols(); j++) {
if (init || snapshot[i][j]) {
Rectangle rect = new Rectangle();
rect.y = i * tileHeight;
rect.x = j * tileWidth;
rect.width = Math.min(trackWidth - rect.x, tileWidth);
rect.height = Math.min(trackHeight - rect.y, tileHeight);
l.add(new TileInfo(i, j, rect));
snapshot[i][j] = false;
}
}
}
return l;
}
}
public boolean hasFullCoverage() {
synchronized (this) {
for (int i = 0; i < getTileRows(); i++) {
for (int j = 0; j < getTileCols(); j++) {
if (!snapshot[i][j])
return false;
}
}
}
return true;
}
public void initCoverageTest() {
synchronized (this) {
for (int i = 0; i < getTileRows(); i++) {
for (int j = 0; j < getTileCols(); j++) {
snapshot[i][j] = false;
}
}
}
}
// listener will be called while holding the object lock, use it
// with care to avoid deadlock condition being formed
public synchronized void scan(int nStartRow, int nStartCol, ITileScanListener listener) {
assert (listener != null);
int cols = getTileCols();
int rows = getTileRows();
nStartRow = nStartRow % rows;
nStartCol = nStartCol % cols;
int nPos = nStartRow * cols + nStartCol;
int nUnits = rows * cols;
int nStartPos = nPos;
int nRow;
int nCol;
do {
nRow = nPos / cols;
nCol = nPos % cols;
if (snapshot[nRow][nCol]) {
int nEndCol = nCol;
for (; nEndCol < cols && snapshot[nRow][nEndCol]; nEndCol++) {
snapshot[nRow][nEndCol] = false;
}
Rectangle rect = new Rectangle();
rect.y = nRow * tileHeight;
rect.height = tileHeight;
rect.x = nCol * tileWidth;
rect.width = (nEndCol - nCol) * tileWidth;
if (!listener.onTileChange(rect, nRow, nEndCol))
break;
}
nPos = (nPos + 1) % nUnits;
} while (nPos != nStartPos);
}
public void capture(ITileScanListener listener) {
assert (listener != null);
int cols = getTileCols();
int rows = getTileRows();
RegionClassifier classifier = new RegionClassifier();
int left, top, right, bottom;
synchronized (this) {
for (int i = 0; i < rows; i++) {
top = i * tileHeight;
bottom = Math.min(top + tileHeight, trackHeight);
for (int j = 0; j < cols; j++) {
left = j * tileWidth;
right = Math.min(left + tileWidth, trackWidth);
if (snapshot[i][j]) {
snapshot[i][j] = false;
classifier.add(new Rectangle(left, top, right - left, bottom - top));
}
}
}
}
listener.onRegionChange(classifier.getRegionList());
}
private synchronized void setTileFlag(Rectangle rect, boolean flag) {
int nStartTileRow;
int nStartTileCol;
int nEndTileRow;
int nEndTileCol;
int cols = getTileCols();
int rows = getTileRows();
if (rect != null) {
nStartTileRow = Math.min(getTileYPos(rect.y), rows - 1);
nStartTileCol = Math.min(getTileXPos(rect.x), cols - 1);
nEndTileRow = Math.min(getTileYPos(rect.y + rect.height - 1), rows - 1);
nEndTileCol = Math.min(getTileXPos(rect.x + rect.width - 1), cols - 1);
} else {
nStartTileRow = 0;
nStartTileCol = 0;
nEndTileRow = rows - 1;
nEndTileCol = cols - 1;
}
for (int i = nStartTileRow; i <= nEndTileRow; i++)
for (int j = nStartTileCol; j <= nEndTileCol; j++)
snapshot[i][j] = flag;
}
private int getTileRows() {
return (trackHeight + tileHeight - 1) / tileHeight;
}
private int getTileCols() {
return (trackWidth + tileWidth - 1) / tileWidth;
}
private int getTileXPos(int x) {
return x / tileWidth;
}
public int getTileYPos(int y) {
return y / tileHeight;
}
}