Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java')
-rw-r--r--org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java283
1 files changed, 283 insertions, 0 deletions
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java
new file mode 100644
index 00000000..902ca815
--- /dev/null
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/layout/LayoutUtils.java
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 John Krasnay and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * John Krasnay - initial API and implementation
+ * Igor Jacy Lino Campista - Java 5 warnings fixed (bug 311325)
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.layout;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.vex.core.internal.core.IntRange;
+import org.eclipse.vex.core.internal.css.CSS;
+import org.eclipse.vex.core.internal.css.StyleSheet;
+import org.eclipse.vex.core.internal.css.Styles;
+import org.eclipse.vex.core.internal.dom.Element;
+import org.eclipse.vex.core.internal.dom.Node;
+
+/**
+ * Tools for layout and rendering of CSS-styled boxes
+ */
+public class LayoutUtils {
+
+ /**
+ * Creates a list of generated inline boxes for the given pseudo-element.
+ *
+ * @param context
+ * LayoutContext in use
+ * @param pseudoElement
+ * Element representing the generated content.
+ */
+ public static List<InlineBox> createGeneratedInlines(LayoutContext context,
+ Element pseudoElement) {
+ String text = getGeneratedContent(context, pseudoElement);
+ List<InlineBox> list = new ArrayList<InlineBox>();
+ if (text.length() > 0) {
+ list.add(new StaticTextBox(context, pseudoElement, text));
+ }
+ return list;
+ }
+
+ /**
+ * Returns <code>true</code> if the given offset falls within the given
+ * element or range.
+ *
+ * @param elementOrRange
+ * Element or IntRange object representing a range of offsets.
+ * @param offset
+ * Offset to test.
+ */
+ public static boolean elementOrRangeContains(Object elementOrRange,
+ int offset) {
+ if (elementOrRange instanceof Element) {
+ Element element = (Element) elementOrRange;
+ return offset > element.getStartOffset()
+ && offset <= element.getEndOffset();
+ } else {
+ IntRange range = (IntRange) elementOrRange;
+ return offset >= range.getStart() && offset <= range.getEnd();
+ }
+ }
+
+ /**
+ * Creates a string representing the generated content for the given
+ * pseudo-element.
+ *
+ * @param context
+ * LayoutContext in use
+ * @param pseudoElement
+ * PseudoElement for which the generated content is to be
+ * returned.
+ */
+ private static String getGeneratedContent(LayoutContext context,
+ Element pseudoElement) {
+ Styles styles = context.getStyleSheet().getStyles(pseudoElement);
+ List<String> content = styles.getContent();
+ StringBuffer sb = new StringBuffer();
+ for (String string : content) {
+ sb.append(string); // TODO: change to ContentPart
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Call the given callback for each child matching one of the given display
+ * styles. Any nodes that do not match one of the given display types cause
+ * the onRange callback to be called, with a range covering all such
+ * contiguous nodes.
+ *
+ * @param context
+ * LayoutContext to use.
+ * @param displayStyles
+ * Display types to be explicitly recognized.
+ * @param element
+ * Element containing the children over which to iterate.
+ * @param startOffset
+ * Starting offset of the range containing nodes in which we're
+ * interested.
+ * @param endOffset
+ * Ending offset of the range containing nodes in which we're
+ * interested.
+ * @param callback
+ * DisplayStyleCallback through which the caller is notified of
+ * matching elements and non-matching ranges.
+ */
+ public static void iterateChildrenByDisplayStyle(StyleSheet styleSheet,
+ Set<String> displayStyles,
+ Element element,
+ int startOffset,
+ int endOffset,
+ ElementOrRangeCallback callback) {
+
+ List<Node> nonMatching = new ArrayList<Node>();
+
+ List<Node> nodes = element.getChildNodes();
+ for (int i = 0; i < nodes.size(); i++) {
+ if (nodes.get(i).getEndOffset() <= startOffset) {
+ continue;
+ } else if (nodes.get(i).getStartOffset() >= endOffset) {
+ break;
+ } else {
+ Node node = nodes.get(i);
+
+ if (node instanceof Element) {
+ Element childElement = (Element) node;
+ String display = styleSheet.getStyles(childElement)
+ .getDisplay();
+ if (displayStyles.contains(display)) {
+ if (!nonMatching.isEmpty()) {
+ Node firstNode = (Node) nonMatching.get(0);
+ Node lastNode = (Node) nonMatching.get(nonMatching
+ .size() - 1);
+ if (lastNode instanceof Element) {
+ callback.onRange(element, firstNode
+ .getStartOffset(), lastNode
+ .getEndOffset() + 1);
+ } else {
+ callback.onRange(element, firstNode
+ .getStartOffset(), lastNode
+ .getEndOffset());
+ }
+ nonMatching.clear();
+ }
+ callback.onElement(childElement, display);
+ } else {
+ nonMatching.add(node);
+ }
+ } else {
+ nonMatching.add(node);
+ }
+ }
+ }
+
+ if (!nonMatching.isEmpty()) {
+ Node firstNode = (Node) nonMatching.get(0);
+ Node lastNode = (Node) nonMatching.get(nonMatching.size() - 1);
+ if (lastNode instanceof Element) {
+ callback.onRange(element, firstNode.getStartOffset(), lastNode
+ .getEndOffset() + 1);
+ } else {
+ callback.onRange(element, firstNode.getStartOffset(), lastNode
+ .getEndOffset());
+ }
+ }
+ }
+
+ /**
+ * Call the given callback for each child matching one of the given display
+ * styles. Any nodes that do not match one of the given display types cause
+ * the onRange callback to be called, with a range covering all such
+ * contiguous nodes.
+ *
+ * @param context
+ * LayoutContext to use.
+ * @param displayStyles
+ * Display types to be explicitly recognized.
+ * @param table
+ * Element containing the children over which to iterate.
+ * @param callback
+ * DisplayStyleCallback through which the caller is notified of
+ * matching elements and non-matching ranges.
+ */
+ public static void iterateChildrenByDisplayStyle(StyleSheet styleSheet,
+ Set<String> displayStyles,
+ Element table,
+ ElementOrRangeCallback callback) {
+ iterateChildrenByDisplayStyle(styleSheet, displayStyles, table,
+ table.getStartOffset() + 1, table.getEndOffset(), callback);
+ }
+
+ /**
+ * Returns true if the given styles represent an element that can be the
+ * child of a table element.
+ *
+ * @param styleSheet
+ * StyleSheet to use.
+ * @param element
+ * Element to test.
+ */
+ public static boolean isTableChild(StyleSheet styleSheet, Element element) {
+ String display = styleSheet.getStyles(element).getDisplay();
+ return TABLE_CHILD_STYLES.contains(display);
+ }
+
+ public static void iterateTableRows(final StyleSheet styleSheet,
+ final Element element, int startOffset, int endOffset,
+ final ElementOrRangeCallback callback) {
+
+ iterateChildrenByDisplayStyle(styleSheet, NON_ROW_STYLES, element,
+ startOffset, endOffset, new ElementOrRangeCallback() {
+ public void onElement(Element child, String displayStyle) {
+ if (displayStyle.equals(CSS.TABLE_ROW_GROUP)
+ || displayStyle.equals(CSS.TABLE_HEADER_GROUP)
+ || displayStyle.equals(CSS.TABLE_FOOTER_GROUP)) {
+
+ // iterate rows in group
+ iterateChildrenByDisplayStyle(styleSheet,
+ ROW_STYLES, child,
+ child.getStartOffset() + 1, child
+ .getEndOffset(), callback);
+ } else {
+ // other element's can't contain rows
+ }
+ }
+
+ public void onRange(Element parent, int startOffset,
+ int endOffset) {
+ // iterate over rows in range
+ iterateChildrenByDisplayStyle(styleSheet, ROW_STYLES,
+ element, startOffset, endOffset, callback);
+ }
+ });
+
+ }
+
+ public static void iterateTableCells(StyleSheet styleSheet,
+ Element element, int startOffset, int endOffset,
+ final ElementOrRangeCallback callback) {
+ iterateChildrenByDisplayStyle(styleSheet, CELL_STYLES, element,
+ startOffset, endOffset, callback);
+ }
+
+ public static void iterateTableCells(StyleSheet styleSheet,
+ Element row, final ElementOrRangeCallback callback) {
+ iterateChildrenByDisplayStyle(styleSheet, CELL_STYLES, row, row
+ .getStartOffset(), row.getEndOffset(), callback);
+ }
+
+ /**
+ * Set of CSS display values that represent elements that can be children of
+ * table elements.
+ */
+ public static final Set<String> TABLE_CHILD_STYLES = new HashSet<String>();
+
+ private static final Set<String> NON_ROW_STYLES = new HashSet<String>();
+ private static final Set<String> ROW_STYLES = new HashSet<String>();
+ private static final Set<String> CELL_STYLES = new HashSet<String>();
+
+ static {
+ NON_ROW_STYLES.add(CSS.TABLE_CAPTION);
+ NON_ROW_STYLES.add(CSS.TABLE_COLUMN);
+ NON_ROW_STYLES.add(CSS.TABLE_COLUMN_GROUP);
+ NON_ROW_STYLES.add(CSS.TABLE_ROW_GROUP);
+ NON_ROW_STYLES.add(CSS.TABLE_HEADER_GROUP);
+ NON_ROW_STYLES.add(CSS.TABLE_FOOTER_GROUP);
+
+ ROW_STYLES.add(CSS.TABLE_ROW);
+
+ CELL_STYLES.add(CSS.TABLE_CELL);
+
+ TABLE_CHILD_STYLES.addAll(NON_ROW_STYLES);
+ TABLE_CHILD_STYLES.addAll(ROW_STYLES);
+ TABLE_CHILD_STYLES.addAll(CELL_STYLES);
+ }
+
+}

Back to the top