// Copyright 2012 Citrix Systems, Inc. Licensed under the
// Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. Citrix Systems, Inc.
// reserves all rights not expressly granted by 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.
//
// Automatically generated by addcopyright.py at 04/03/2012
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;
}
}