// 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; } }