/*
GNU GENERAL LICENSE
Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
verion 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General License for more details.
You should have received a copy of the GNU General Public
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it
*/
/*
* Created on Apr 16, 2005
*/
package org.lobobrowser.html.renderer;
import java.awt.Point;
import java.awt.Rectangle;
import org.lobobrowser.util.Diagnostics;
/**
* The Class MarkupUtilities.
*
* @author J. H. S.
*/
public class MarkupUtilities {
/**
* Instantiates a new markup utilities.
*/
private MarkupUtilities() {
super();
}
/**
* Find renderable.
*
* @param renderables
* the renderables
* @param point
* the point
* @param vertical
* the vertical
* @return the boundable renderable
*/
public static BoundableRenderable findRenderable(Renderable[] renderables,
Point point, boolean vertical) {
return findRenderable(renderables, point, 0, renderables.length,
vertical);
}
/**
* Find renderable.
*
* @param renderables
* the renderables
* @param x
* the x
* @param y
* the y
* @param vertical
* the vertical
* @return the boundable renderable
*/
public static BoundableRenderable findRenderable(Renderable[] renderables,
int x, int y, boolean vertical) {
return findRenderable(renderables, x, y, 0, renderables.length,
vertical);
}
/**
* Find renderable.
*
* @param renderables
* the renderables
* @param point
* the point
* @param firstIndex
* the first index
* @param length
* the length
* @param vertical
* the vertical
* @return the boundable renderable
*/
private static BoundableRenderable findRenderable(Renderable[] renderables,
Point point, int firstIndex, int length, boolean vertical) {
return findRenderable(renderables, point.x, point.y, firstIndex,
length, vertical);
}
/**
* Find renderable.
*
* @param renderables
* the renderables
* @param x
* the x
* @param y
* the y
* @param firstIndex
* the first index
* @param length
* the length
* @param vertical
* the vertical
* @return the boundable renderable
*/
private static BoundableRenderable findRenderable(Renderable[] renderables,
int x, int y, int firstIndex, int length, boolean vertical) {
if (length == 0) {
return null;
}
if (length == 1) {
Renderable r = renderables[firstIndex];
if (!(r instanceof BoundableRenderable)) {
return null;
}
BoundableRenderable br = (BoundableRenderable) r;
Rectangle rbounds = br.getBounds();
return rbounds.contains(x, y) ? br : null;
} else {
int middleIndex = firstIndex + (length / 2);
Renderable r = renderables[middleIndex];
Rectangle rbounds;
if (r instanceof BoundableRenderable) {
rbounds = ((BoundableRenderable) r).getBounds();
} else {
BoundableRenderable rleft = findRenderable(renderables, x, y,
firstIndex, middleIndex - firstIndex, vertical);
if (rleft != null) {
return rleft;
}
return findRenderable(renderables, x, y, middleIndex + 1,
length - ((middleIndex - firstIndex) + 1), vertical);
}
if (rbounds.contains(x, y)) {
return (BoundableRenderable) r;
}
if (vertical) {
if (y < rbounds.y) {
return findRenderable(renderables, x, y, firstIndex,
middleIndex - firstIndex, vertical);
} else {
return findRenderable(renderables, x, y, middleIndex + 1,
length - ((middleIndex - firstIndex) + 1), vertical);
}
} else {
if (x < rbounds.x) {
return findRenderable(renderables, x, y, firstIndex,
middleIndex - firstIndex, vertical);
} else {
return findRenderable(renderables, x, y, middleIndex + 1,
length - ((middleIndex - firstIndex) + 1), vertical);
}
}
}
}
/**
* Find renderables.
*
* @param renderables
* the renderables
* @param clipArea
* the clip area
* @param vertical
* the vertical
* @return the range
*/
public static Range findRenderables(Renderable[] renderables,
Rectangle clipArea, boolean vertical) {
return findRenderables(renderables, clipArea, 0, renderables.length,
vertical);
}
/**
* Find renderables.
*
* @param renderables
* the renderables
* @param clipArea
* the clip area
* @param firstIndex
* the first index
* @param length
* the length
* @param vertical
* the vertical
* @return the range
*/
private static Range findRenderables(Renderable[] renderables,
Rectangle clipArea, int firstIndex, int length, boolean vertical) {
if (length == 0) {
return new Range(0, 0);
}
int offset1 = findFirstIndex(renderables, clipArea, firstIndex, length,
vertical);
int offset2 = findLastIndex(renderables, clipArea, firstIndex, length,
vertical);
if ((offset1 == -1) && (offset2 == -1)) {
// if(logger.isEnabled(Level.INFO))logger.info("findRenderables(): Range not found for clipArea="
// + clipArea + ",length=" + length);
// for(int i = firstIndex; i < length; i++) {
// logger.info("findRenderables(): renderable.bounds=" +
// renderables[i].getBounds());
//}
return new Range(0, 0);
}
if (offset1 == -1) {
offset1 = firstIndex;
}
if (offset2 == -1) {
offset2 = (firstIndex + length) - 1;
}
return new Range(offset1, (offset2 - offset1) + 1);
}
/**
* Find first index.
*
* @param renderables
* the renderables
* @param clipArea
* the clip area
* @param index
* the index
* @param length
* the length
* @param vertical
* the vertical
* @return the int
*/
private static int findFirstIndex(Renderable[] renderables,
Rectangle clipArea, int index, int length, boolean vertical) {
Diagnostics.Assert(length > 0, "length=" + length);
if (length == 1) {
Renderable r = renderables[index];
Rectangle rbounds;
if (r instanceof BoundableRenderable) {
rbounds = ((BoundableRenderable) r).getBounds();
} else {
return -1;
}
if (intersects(rbounds, clipArea, vertical)) {
return index;
} else {
return -1;
}
} else {
int middleIndex = index + (length / 2);
Renderable r = renderables[middleIndex];
Rectangle rbounds;
if (r instanceof BoundableRenderable) {
rbounds = ((BoundableRenderable) r).getBounds();
} else {
int leftIndex = findFirstIndex(renderables, clipArea, index,
middleIndex - index, vertical);
if (leftIndex != -1) {
return leftIndex;
}
return findFirstIndex(renderables, clipArea, middleIndex + 1,
length - ((middleIndex - index) + 1), vertical);
}
if (vertical) {
if ((rbounds.y + rbounds.height) < clipArea.y) {
int newLen = length - ((middleIndex - index) + 1);
return newLen == 0 ? -1 : findFirstIndex(renderables,
clipArea, middleIndex + 1, newLen, vertical);
} else {
int newLen = middleIndex - index;
int resultIdx = newLen == 0 ? -1 : findFirstIndex(
renderables, clipArea, index, newLen, vertical);
if (resultIdx == -1) {
if (intersects(clipArea, rbounds, vertical)) {
return middleIndex;
}
}
return resultIdx;
}
} else {
if ((rbounds.x + rbounds.width) < clipArea.x) {
return findFirstIndex(renderables, clipArea,
middleIndex + 1, length - (middleIndex - index),
vertical);
} else {
int resultIdx = findFirstIndex(renderables, clipArea,
index, middleIndex - index, vertical);
if (resultIdx == -1) {
if (intersects(clipArea, rbounds, vertical)) {
return middleIndex;
}
}
return resultIdx;
}
}
}
}
/**
* Find last index.
*
* @param renderables
* the renderables
* @param clipArea
* the clip area
* @param index
* the index
* @param length
* the length
* @param vertical
* the vertical
* @return the int
*/
private static int findLastIndex(Renderable[] renderables,
Rectangle clipArea, int index, int length, boolean vertical) {
Diagnostics.Assert(length > 0, "length<=0");
if (length == 1) {
Renderable r = renderables[index];
Rectangle rbounds;
if (r instanceof BoundableRenderable) {
rbounds = ((BoundableRenderable) r).getBounds();
} else {
return -1;
}
if (intersects(clipArea, rbounds, vertical)) {
return index;
} else {
return -1;
}
} else {
int middleIndex = index + (length / 2);
Renderable r = renderables[middleIndex];
Rectangle rbounds;
if (r instanceof BoundableRenderable) {
rbounds = ((BoundableRenderable) r).getBounds();
} else {
int rightIndex = findLastIndex(renderables, clipArea,
middleIndex + 1, length - ((middleIndex - index) + 1),
vertical);
if (rightIndex != -1) {
return rightIndex;
}
return findLastIndex(renderables, clipArea, index, middleIndex
- index, vertical);
}
if (vertical) {
if (rbounds.y > (clipArea.y + clipArea.height)) {
return findLastIndex(renderables, clipArea, index,
middleIndex - index, vertical);
} else {
int newLen = length - ((middleIndex - index) + 1);
int resultIdx = newLen == 0 ? -1 : findLastIndex(
renderables, clipArea, middleIndex + 1, newLen,
vertical);
if (resultIdx == -1) {
if (intersects(clipArea, rbounds, vertical)) {
return middleIndex;
}
}
return resultIdx;
}
} else {
if (rbounds.x > (clipArea.x + clipArea.width)) {
return findLastIndex(renderables, clipArea, index,
middleIndex - index, vertical);
} else {
int resultIdx = findLastIndex(renderables, clipArea,
middleIndex + 1, length
- ((middleIndex - index) + 1), vertical);
if (resultIdx == -1) {
if (intersects(clipArea, rbounds, vertical)) {
return middleIndex;
}
}
return resultIdx;
}
}
}
}
/**
* Intersects.
*
* @param rect1
* the rect1
* @param rect2
* the rect2
* @param vertical
* the vertical
* @return true, if successful
*/
private static boolean intersects(Rectangle rect1, Rectangle rect2,
boolean vertical) {
if (vertical) {
return !((rect1.y > (rect2.y + rect2.height)) || (rect2.y > (rect1.y + rect1.height)));
} else {
return !((rect1.x > (rect2.x + rect2.width)) || (rect2.x > (rect1.x + rect1.width)));
}
}
}