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