package org.ebookdroid.core; import org.ebookdroid.common.bitmaps.GLBitmaps; import android.graphics.RectF; import java.util.List; public class PageTree { // private static final LogContext LCTX = Page.LCTX; static RectF[] splitMasks = { // Left Top new RectF(0, 0, 0.5f, 0.5f), // Right top new RectF(0.5f, 0, 1.0f, 0.5f), // Left Bottom new RectF(0, 0.5f, 0.5f, 1.0f), // Right Bottom new RectF(0.5f, 0.5f, 1.0f, 1.0f), }; final Page owner; public final PageTreeNode root; private PageTreeNode[] treeNodes; private volatile int maxNodeId; public PageTree(final Page owner) { this.owner = owner; this.root = new PageTreeNode(owner); this.maxNodeId = 1; } private synchronized PageTreeNode[] getNodes() { if (this.treeNodes == null) { this.treeNodes = new PageTreeNode[PageTreeLevel.NODES]; this.treeNodes[0] = root; } return this.treeNodes; } public boolean process(final IEvent event, final PageTreeLevel level, final boolean createNodes) { boolean res = false; if (createNodes || level.start < maxNodeId) { final PageTreeNode[] nodes = getNodes(); for (int nodeIndex = level.start; nodeIndex < level.end; nodeIndex++) { if (nodes[nodeIndex] == null) { createChildren(getParent(nodeIndex, true)); } res |= event.process(nodes[nodeIndex]); } } return res; } public boolean paintChildren(final EventGLDraw event, final PageTreeNode node, final RectF nodeRect) { boolean res = false; int childId = PageTree.getFirstChildId(node.id); if (childId < maxNodeId) { final PageTreeNode[] nodes = getNodes(); for (final int end = Math.min(nodes.length, childId + PageTree.splitMasks.length); childId < end; childId++) { final PageTreeNode child = nodes[childId]; if (child != null) { res |= event.paintChild(node, child, nodeRect); } } } return res; } public boolean createChildren(final PageTreeNode parent) { final PageTreeNode[] nodes = getNodes(); int childId = getFirstChildId(parent.id); for (int i = 0; i < splitMasks.length; i++, childId++) { if (nodes[childId] == null) { nodes[childId] = new PageTreeNode(owner, parent, childId, splitMasks[i]); } } maxNodeId = Math.max(maxNodeId, childId); return true; } public PageTreeNode getParent(final int nodeIndex, final boolean create) { if (nodeIndex == 0) { return null; } if (nodeIndex >= maxNodeId && !create) { return null; } final PageTreeNode[] nodes = getNodes(); final int parentIndex = (nodeIndex - 1) / 4; if (nodes[parentIndex] == null && create) { createChildren(getParent(parentIndex, true)); } return nodes[parentIndex]; } public boolean recycleAll(final List<GLBitmaps> bitmapsToRecycle, final boolean includeRoot) { boolean res = false; if (includeRoot) { res |= root.recycle(bitmapsToRecycle); } if (maxNodeId > 1) { final PageTreeNode[] nodes = getNodes(); for (int index = 1; index < maxNodeId; index++) { if (nodes[index] != null) { res |= nodes[index].recycle(bitmapsToRecycle); nodes[index] = null; } } } maxNodeId = 1; return res; } public boolean recycleParents(final PageTreeNode child, final List<GLBitmaps> bitmapsToRecycle) { if (child.id == 0) { return false; } boolean res = false; int childId = child.id; for (PageTreeNode p = getParent(childId, false); p != null; p = getParent(childId, false)) { res |= p.recycle(bitmapsToRecycle); childId = p.id; if (child.id == 0) { break; } } return res; } public boolean recycleChildren(final PageTreeNode node, final List<GLBitmaps> bitmapsToRecycle) { boolean res = false; int childId = getFirstChildId(node.id); if (childId >= maxNodeId) { return res; } final PageTreeNode[] nodes = getNodes(); for (final int end = Math.min(nodes.length, childId + splitMasks.length); childId < end; childId++) { if (nodes[childId] != null) { res |= nodes[childId].recycle(bitmapsToRecycle); nodes[childId] = null; } } if (childId >= maxNodeId) { if (childId >= nodes.length) { maxNodeId = nodes.length - 1; } while (maxNodeId > 0 && nodes[maxNodeId] == null) { maxNodeId--; } maxNodeId++; } return res; } public void recycleNodes(final PageTreeLevel level, final List<GLBitmaps> bitmapsToRecycle) { if (level.start >= maxNodeId) { return; } final PageTreeNode[] nodes = getNodes(); for (int i = level.start; i < maxNodeId; i++) { if (nodes[i] != null) { nodes[i].recycle(bitmapsToRecycle); nodes[i] = null; } } maxNodeId = level.start; while (maxNodeId > 0 && nodes[maxNodeId] == null) { maxNodeId--; } maxNodeId++; } public boolean isHiddenByChildren(final PageTreeNode parent, final ViewState viewState, final RectF pageBounds) { int childId = getFirstChildId(parent.id); if (childId >= maxNodeId) { return false; } final PageTreeNode[] nodes = getNodes(); for (final int end = Math.min(nodes.length, childId + splitMasks.length); childId < end; childId++) { final PageTreeNode child = nodes[childId]; if (child == null) { return false; } if (viewState.isNodeKeptInMemory(child, pageBounds) && !child.holder.hasBitmaps()) { return false; } } return true; } static int getFirstChildId(final long parentId) { return (int) (parentId * splitMasks.length + 1); } }