Index: modules/swing/src/main/java/common/org/apache/harmony/x/swing/StringConstants.java =================================================================== --- modules/swing/src/main/java/common/org/apache/harmony/x/swing/StringConstants.java (revision 424221) +++ modules/swing/src/main/java/common/org/apache/harmony/x/swing/StringConstants.java (working copy) @@ -88,6 +88,7 @@ String TEXT_COMPONENT_MARGIN_PROPERTY = "margin"; String TEXT_COMPONENR_KEYMAP_PROPERTY = "keymap"; String TEXT_COMPONENT_NAV_FILTER_NAME = "navigationFilter"; + String IGNORE_CHARSET_DIRECTIVE = "IgnoreCharsetDirective"; String EDITOR_PANE_EDITOR_KIT_PROPERTY = "editorKit"; Index: modules/swing/src/main/java/common/javax/swing/JEditorPane.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/JEditorPane.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/JEditorPane.java (working copy) @@ -22,11 +22,14 @@ import java.awt.Container; import java.awt.Dimension; +import java.awt.Rectangle; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.StringReader; import java.io.StringWriter; import java.net.URL; +import java.nio.charset.Charset; import java.util.ArrayList; import javax.accessibility.AccessibleContext; @@ -40,6 +43,7 @@ import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; +import javax.swing.text.ChangedCharSetException; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; import javax.swing.text.EditorKit; @@ -51,7 +55,11 @@ import javax.swing.text.WrappedPlainView; //import javax.swing.text.html.HTML; //import javax.swing.text.html.HTMLDocument; +//import javax.swing.text.html.HTMLEditorKit; +//import javax.swing.text.rtf.RTFEditorKit; +import org.apache.harmony.x.swing.StringConstants; + public class JEditorPane extends JTextComponent { protected class AccessibleJEditorPane extends JTextComponent.AccessibleJTextComponent { @@ -176,7 +184,7 @@ private static final String RTF_HEADER = "{\\rtf"; - private static final String HTML_HEADER = ""; + private static final String HTML_HEADER = "= 0) ? (String)contentTypes.get(index) : PLAIN_CONTENT_TYPE; - EditorKit kit = JEditorPane.createEditorKitForContentType(contentType); - updateEditorKit((kit != null) ? kit : new PlainEditorKit()); - updateDocument(editorKit); */ + if (changeEditoKit(contentType)) { + EditorKit kit = getEditorKitForContentType(contentType); + updateEditorKit((kit != null) ? kit : new PlainEditorKit()); + updateDocument(editorKit); + } + */ } private String getContentTypeByEditorKit(final EditorKit kit) { @@ -577,13 +598,12 @@ updateEditorKit(kit); updateDocument(kit); } - /*String newContentType = getContentTypeByEditorKit(kit); - if (newContentType == "text/html" || newContentType == "text/rtf") { - throw new UnsupportedOperationException("Not implemented"); - } + /* + String newContentType = getContentTypeByEditorKit(kit); updateEditorKit(kit); updateDocument(kit); - contentType = newContentType; */ + contentType = newContentType; + */ } public void setEditorKitForContentType(final String type, @@ -601,10 +621,27 @@ setPage(new URL(page)); } - private void documentLoading(final InputStream str, final Document doc) + private void documentLoading(final InputStream str, final Document doc, + final URL url) throws IOException { try { editorKit.read(str, doc, 0); + } catch (ChangedCharSetException e) { + try { + doc.putProperty(StringConstants.IGNORE_CHARSET_DIRECTIVE, + Boolean.TRUE); + doc.remove(0, doc.getLength()); + final String htmlAttribute = e.getCharSetSpec(); + final int charSetIndex = htmlAttribute.lastIndexOf("charset="); + if (charSetIndex >= 0) { + String charSet = htmlAttribute.substring(charSetIndex + 8); + InputStreamReader reader = + new InputStreamReader(url.openStream(), + Charset.forName(charSet)); + editorKit.read(reader, doc, 0); + } + } catch (BadLocationException e1) { + } } catch (BadLocationException e) { } } @@ -612,14 +649,17 @@ private class AsynchLoad extends Thread { InputStream inputStream; boolean successfulLoading = true; - public AsynchLoad(final int priority, final InputStream stream) { + URL url; + public AsynchLoad(final int priority, final InputStream stream, + final URL url) { super(); setPriority(priority); inputStream = stream; + this.url = url; } public void run() { try { - documentLoading(inputStream, getDocument()); + documentLoading(inputStream, getDocument(), url); } catch (IOException e) { successfulLoading = false; } @@ -627,11 +667,9 @@ } public void setPage(final URL page) throws IOException { - /*if (true) { - throw new UnsupportedOperationException("Not implemented"); - }*/ - //temporarily commented-out: HTMLDocument not implemented - /*String url = page.toString(); + //temporarily commented-out: HTMLDocument not implemented + /* + String url = page.toString(); String baseUrl = getBaseURL(url); Document oldDoc = getDocument(); if (baseUrl != null @@ -650,7 +688,8 @@ //Perhaps, it is reasonable only for HTMLDocument... if (newDoc instanceof HTMLDocument) { newDoc.putProperty(Document.StreamDescriptionProperty, baseUrl); - newDoc.putProperty("IgnoreCharsetDirective", new Boolean(true)); + newDoc.putProperty(StringConstants.IGNORE_CHARSET_DIRECTIVE, + new Boolean(false)); try { ((HTMLDocument)newDoc).setBase(new URL(baseUrl)); } catch (IOException e) { @@ -665,20 +704,21 @@ if (asynchronousLoadPriority >= 0) { setDocument(newDoc); AsynchLoad newThread = new AsynchLoad(asynchronousLoadPriority, - stream); + stream, page); newThread.start(); if (newThread.successfulLoading) { changePage(page); } } else { try { - documentLoading(stream, newDoc); + documentLoading(stream, newDoc, page); stream.close(); setDocument(newDoc); changePage(page); } catch (IOException e) { } - } */ + } + */ } private void changePage(final URL newPage) { Index: modules/swing/src/main/java/common/javax/swing/text/ParagraphView.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/text/ParagraphView.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/text/ParagraphView.java (working copy) @@ -56,6 +56,11 @@ return super.getEndOffset(); } + public AttributeSet getAttributes() { + final View parent = getParent(); + return parent != null ? parent.getAttributes() : null; + } + protected void loadChildren(final ViewFactory factory) { } @@ -75,9 +80,6 @@ SizeRequirements result = baselineRequirements(axis, r); lineSpace = (int)(result.preferred * lineSpacing); - result.minimum += lineSpace; - result.preferred += lineSpace; - result.maximum = result.preferred; return result; } Index: modules/swing/src/main/java/common/javax/swing/text/AbstractDocument.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/text/AbstractDocument.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/text/AbstractDocument.java (working copy) @@ -65,7 +65,7 @@ private transient AttributeSet attrs; - private Element parent; + private final Element parent; public AbstractElement(final Element parent, final AttributeSet attributes) { @@ -180,11 +180,9 @@ public Object getAttribute(final Object key) { Object value = attrs.getAttribute(key); - if (value == null && parent != null) { - AttributeSet resolveSet = parent.getAttributes(); - if (resolveSet != null) { - value = resolveSet.getAttribute(key); - } + AttributeSet resolver = getResolveParent(); + if (value == null && resolver != null) { + value = resolver.getAttribute(key); } return value; } Index: modules/swing/src/main/java/common/javax/swing/text/DefaultStyledDocument.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/text/DefaultStyledDocument.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/text/DefaultStyledDocument.java (working copy) @@ -82,6 +82,7 @@ private transient Stack changeStack; private transient List changes; private transient boolean create; + private transient Element tail; public ElementBuffer(final Element root) { this.root = root; @@ -145,67 +146,38 @@ protected void insertUpdate(final ElementSpec[] spec) { // Find the deepest branch - BranchElement branch = (BranchElement)root; - Element child; + Element branch = root; do { changeStack.push(new ChangeDesc(branch)); - child = branch.getElement(branch.getElementIndex(offset)); - if (!child.isLeaf()) { - branch = (BranchElement)child; - } - } while (!child.isLeaf()); + branch = branch.getElement(branch.getElementIndex(offset)); + } while (!branch.isLeaf()); current = (ChangeDesc)changeStack.peek(); - //Element leaf = getCharacterElement(offset); - //current = (BranchElement)leaf.getParentElement(); - // Apply each spec to the tree - for (int i = 0; i < spec.length; i++) { - switch (spec[i].getType()) { - case ElementSpec.ContentType: - insertContent(spec[i]); - break; - - case ElementSpec.EndTagType: - insertEndTag(); - break; - - case ElementSpec.StartTagType: - insertStartTag(spec[i]); - break; - - default: - throw new Error("Unknown type in the spec"); - } - } + performSpecs(spec); leaveParagraph(); } protected void removeUpdate() { final int endOffset = offset + length; final Element startLeaf = getCharacterElement(offset); + final Element startBranch = startLeaf.getParentElement(); + final Element endLeaf = endOffset == startLeaf.getEndOffset() - && endOffset < startLeaf.getParentElement() - .getEndOffset() + && endOffset < startBranch.getEndOffset() ? startLeaf : getCharacterElement(endOffset); + final Element endBranch = endLeaf.getParentElement(); if (startLeaf == endLeaf) { if (startLeaf.getStartOffset() == offset && endOffset == startLeaf.getEndOffset()) { - current = new ChangeDesc(startLeaf.getParentElement()); - current.setIndex(current.element.getElementIndex(offset)); + current = new ChangeDesc(startBranch, offset); current.removed.add(startLeaf); changes.add(current); } - return; - } - - final Element startBranch = startLeaf.getParentElement(); - final Element endBranch = endLeaf.getParentElement(); - - if (startBranch == endBranch) { + } else if (startBranch == endBranch) { final int index = startBranch.getElementIndex(offset); current = new ChangeDesc(startBranch); for (int i = index; i < startBranch.getElementCount(); i++) { @@ -213,9 +185,7 @@ if (offset <= child.getStartOffset() && child.getEndOffset() <= endOffset) { - if (current.getIndex() < 0) { - current.setIndex(i); - } + current.setChildIndex(i); current.removed.add(child); } if (endOffset < child.getEndOffset()) { @@ -227,39 +197,55 @@ } else { final BranchElement parent = (BranchElement)startBranch.getParentElement(); - current = new ChangeDesc(parent); - current.setIndex(parent.getElementIndex(offset)); - - final BranchElement branch = - (BranchElement)createBranchElement(parent, - startBranch - .getAttributes()); - - List children = new LinkedList(); - - // Copy elements from startBranch - int index = startBranch.getElementIndex(offset); - if (startBranch.getElement(index).getStartOffset() < offset) { - ++index; + if (parent != null) { + current = new ChangeDesc(parent, offset); + + BranchElement branch = (BranchElement)createBranchElement(parent, + startBranch.getAttributes()); + List children = new LinkedList(); + + // Copy elements from startBranch + int index = startBranch.getElementIndex(offset); + if (startBranch.getElement(index).getStartOffset() < offset) { + ++index; + } + for (int i = 0; i < index; i++) { + children.add(clone(branch, startBranch.getElement(i))); + } + + // Copy elements from endBranch + index = endBranch.getElementIndex(endOffset); + for (int i = index; i < endBranch.getElementCount(); i++) { + children.add(clone(branch, endBranch.getElement(i))); + } + + index = parent.getElementIndex(endOffset); + for (int i = current.getChildIndex(); i <= index; i++) { + current.removeChildElement(i); + } + current.added.add(branch); + + branch.replace(0, 0, listToElementArray(children)); + } else { + current = new ChangeDesc(startBranch, offset); + + // Copy elements from endBranch + int index = endBranch.getElementIndex(endOffset); + for (int i = index; i < endBranch.getElementCount(); i++) { + current.added.add(clone(startBranch, endBranch.getElement(i))); + } + + // Copy elements from startBranch + int startIndex = startBranch.getElementIndex(offset); + int endIndex = startBranch.getElementIndex(endOffset); + for (int i = startIndex; i <= endIndex; i++) { + current.removeChildElement(i); + } + current.setChildIndex(startIndex); + + current.apply(); } - for (int i = 0; i < index; i++) { - children.add(clone(branch, startBranch.getElement(i))); - } - // Copy elements from endBranch - index = endBranch.getElementIndex(endOffset); - for (int i = index; i < endBranch.getElementCount(); i++) { - children.add(clone(branch, endBranch.getElement(i))); - } - - index = parent.getElementIndex(endOffset); - for (int i = current.getIndex(); i <= index; i++) { - current.removed.add(parent.getElement(i)); - } - current.added.add(branch); - - branch.replace(0, 0, listToElementArray(children)); - changes.add(current); } } @@ -275,78 +261,43 @@ } if (startLeaf == endLeaf) { - final int start = startLeaf.getStartOffset(); - final int end = startLeaf.getEndOffset(); - if (start == offset && endOffset == end) { - return; - } - final AttributeSet attrs = startLeaf.getAttributes(); + current = new ChangeDesc(startLeaf.getParentElement(), offset); + current.splitLeafElement(startLeaf, offset, endOffset, true, startLeaf.getAttributes()); - current = new ChangeDesc(startLeaf.getParentElement()); - current.setIndex(current.element.getElementIndex(offset)); - current.removed.add(startLeaf); - - if (startLeaf.getStartOffset() < offset) { - current.added.add(createLeafElement(current.element, attrs, - start, offset)); - } - current.added.add(createLeafElement(current.element, attrs, - offset, endOffset)); - if (endOffset < end) { - current.added.add(createLeafElement(current.element, attrs, - endOffset, end)); - } - changes.add(current); } else { // Break the startLeaf int start = startLeaf.getStartOffset(); int end = startLeaf.getEndOffset(); - AttributeSet attrs = startLeaf.getAttributes(); if (start < offset) { - current = new ChangeDesc(startLeaf.getParentElement()); - current.setIndex(current.element.getElementIndex(offset)); - current.removed.add(startLeaf); - - current.added.add(createLeafElement(current.element, attrs, - start, offset)); - current.added.add(createLeafElement(current.element, attrs, - offset, end)); + current = new ChangeDesc(startLeaf.getParentElement(), offset); + current.splitLeafElement(startLeaf, offset); changes.add(current); } // Break the endLeaf start = endLeaf.getStartOffset(); end = endLeaf.getEndOffset(); - attrs = endLeaf.getAttributes(); if (start < endOffset && endOffset < end) { final boolean sameParents = current != null && current.element == endLeaf.getParentElement(); if (!sameParents) { - current = new ChangeDesc(endLeaf.getParentElement()); - current.setIndex(current.element - .getElementIndex(endOffset)); + current = new ChangeDesc(endLeaf.getParentElement(), endOffset); } else { - final int endIndex = current.element - .getElementIndex(endOffset); - for (int i = current.getIndex() + 1; + final int endIndex = current.getChildIndexAtOffset(endOffset); + for (int i = current.getChildIndex() + 1; i < endIndex; i++) { - final Element child = current.element.getElement(i); + final Element child = current.getChildElement(i); current.removed.add(child); current.added.add(child); } } - current.removed.add(endLeaf); + current.splitLeafElement(endLeaf, endOffset); - current.added.add(createLeafElement(current.element, attrs, - start, endOffset)); - current.added.add(createLeafElement(current.element, attrs, - endOffset, end)); - if (!sameParents) { changes.add(current); } @@ -361,23 +312,27 @@ // Remove all elements from the only paragraph current = new ChangeDesc(getParagraphElement(0)); - current.setIndex(0); - current.added.add(createLeafElement(current.element, - current.element - .getElement(0).getAttributes(), - length, length + 1)); + current.setChildIndex(0); + current.createLeafElement(current.getChildElement(0).getAttributes(), + length, length + 1); for (int i = 0; i < current.element.getElementCount(); i++) { - current.removed.add(current.element.getElement(i)); + current.removeChildElement(i); } current.apply(); changes.add(current); current = null; - // Apply each spec to the tree - for (int i = 0; i < specs.length; i++) { - switch (specs[i].getType()) { + performSpecs(specs); + leaveParagraph(); + + collectEdits(); + } + + private void performSpecs(final ElementSpec[] spec) throws Error { + for (int i = 0; i < spec.length; i++) { + switch (spec[i].getType()) { case ElementSpec.ContentType: - insertContent(specs[i]); + insertContent(spec[i]); break; case ElementSpec.EndTagType: @@ -385,16 +340,13 @@ break; case ElementSpec.StartTagType: - insertStartTag(specs[i]); + insertStartTag(spec[i]); break; default: throw new Error("Unknown type in the spec"); } } - leaveParagraph(); - - collectEdits(); } private void applyEdits() { @@ -419,8 +371,15 @@ } } changes.clear(); + + clear(); } + private void clear() { + event = null; + current = null; + } + private void insertContent(final ElementSpec spec) { switch (spec.getDirection()) { case ElementSpec.OriginateDirection: @@ -443,64 +402,66 @@ } private void insertContentOriginate(final ElementSpec spec) { - // First we should remove the element that was at the place + final AttributeSet specAttr = spec.getAttributes(); if (current.element.getElementCount() == 0) { - if (current.getIndex() < 0) { - current.setIndex(0); + current.setChildIndex(0); + current.createLeafElement(specAttr, + offset, offset + spec.length); + } else { + current.setChildIndexByOffset(offset); + final Element leafToRemove = current.getCurrentChild(); + if (offset == 0 && leafToRemove.isLeaf()) { + current.removed.add(leafToRemove); + current.createLeafElement(specAttr, + offset, offset + spec.length); + current.createLeafElement(leafToRemove.getAttributes(), + offset + length, leafToRemove.getEndOffset()); + tail = current.getLastAddedElement(); + current.added.remove(tail); + } else if (offset == event.getOffset() + && leafToRemove.getStartOffset() < offset + && offset < leafToRemove.getEndOffset()) { + if (leafToRemove.isLeaf()) { + current.splitLeafElement(leafToRemove, offset, + offset + spec.length, + offset + length, + true, specAttr); + tail = current.getLastAddedElement(); + current.added.remove(tail); + } else { + tail = splitBranch(leafToRemove); + current.createLeafElement(specAttr, + offset, offset + spec.length); + current.childIndex = current.getChildIndex() + 1; + } + } else { + current.createLeafElement(specAttr, + offset, offset + spec.length); + if (offset >= current.element.getEndOffset() + && current.getChildIndex() < current.element + .getElementCount()) { + current.childIndex = current.getChildIndex() + 1; + } } - current.added.add(createLeafElement(current.element, - spec.getAttributes(), - offset, - offset + spec.getLength())); - return; } - - if (current.getIndex() < 0) { - current.setIndex(current.element.getElementIndex(offset)); - } - final Element leafToRemove = current.element - .getElement(current.getIndex()); - - if (offset == 0) { - current.removed.add(leafToRemove); - } else if (offset == event.getOffset() - && leafToRemove.getStartOffset() < offset - && offset < leafToRemove.getEndOffset()) { - current.removed.add(leafToRemove); - current.added.add(createLeafElement(current.element, - leafToRemove.getAttributes(), - leafToRemove.getStartOffset(), - offset)); - } - current.added.add(createLeafElement(current.element, - spec.getAttributes(), - offset, offset + spec.length)); } private void insertContentJoinNext(final ElementSpec spec) { - if (current.getIndex() < 0) { - current.setIndex(current.element.getElementIndex(offset)); - } - final Element leaf = current.element.getElement(current.getIndex()); + current.setChildIndexByOffset(offset); + final Element leaf = current.getCurrentChild(); if (leaf.getStartOffset() >= offset) { current.removed.add(leaf); - current.added.add(createLeafElement(current.element, - leaf.getAttributes(), - offset, - leaf.getEndOffset())); + current.createLeafElement(leaf.getAttributes(), + offset, leaf.getEndOffset()); } else { final Element next = - current.element.getElement(current.getIndex() + 1); + current.getChildElement(current.getChildIndex() + 1); current.removed.add(leaf); current.removed.add(next); - current.added.add(createLeafElement(current.element, - leaf.getAttributes(), - leaf.getStartOffset(), - offset)); - current.added.add(createLeafElement(current.element, - next.getAttributes(), - offset, - next.getEndOffset())); + current.createLeafElement(leaf.getAttributes(), + leaf.getStartOffset(), offset); + current.createLeafElement(next.getAttributes(), + offset, next.getEndOffset()); } } @@ -515,7 +476,7 @@ break; case ElementSpec.JoinPreviousDirection: - insertStartJoinPrevious(); + insertStartJoinPrevious(spec); break; case ElementSpec.JoinFractureDirection: @@ -528,93 +489,87 @@ } private void insertStartFracture(final ElementSpec spec) { - final ChangeDesc lastChange = (ChangeDesc)changes.get(changes.size() - - 1); - final BranchElement lastBranch = lastChange.element; final AttributeSet attrs = spec.getDirection() == ElementSpec.OriginateDirection ? spec.getAttributes() : findLastExistedBranch().getAttributes(); - final BranchElement branch = + final BranchElement newBranch = (BranchElement)createBranchElement(current.element, attrs); - final ChangeDesc change = new ChangeDesc(branch, true); - int index = lastBranch.getElementIndex(offset); - if (lastBranch.getElement(index).getEndOffset() <= offset) { - ++index; - } - // Now copy all elements from lastBranch to the new one - final List children = new ArrayList(); - final int count = lastBranch.getElementCount(); - for (int i = index; i < count; i++) { - children.add(clone(branch, lastBranch.getElement(i))); - } - // Now we need to remove all previously added elements which were - // copied from added list - for (int i = index - lastChange.index, j = index; j < count; j++) { - final Object addedElement = - i > 0 && i < lastChange.added.size() - ? lastChange.added.get(i) - : null; - final Object existingElement = lastBranch.getElement(j); - if (addedElement == existingElement) { - lastChange.added.remove(addedElement); - } else if (!lastChange.justCreated) { - lastChange.removed.add(existingElement); - } + final ChangeDesc lastChange = (ChangeDesc)changes.get(changes.size() - 1); + int startIndex = lastChange.getChildIndexAtOffset(offset); + if (lastChange.getChildElement(startIndex).getEndOffset() <= offset) { + ++startIndex; } - // Complete the removal of elements from last branch - if (count - index > 0) { - lastBranch.replace(index, count - index, new Element[0]); - } + moveChildren(newBranch, lastChange, startIndex); - // Place copied children into the new element - branch.replace(0, 0, - (Element[])children.toArray(new Element[children.size()])); - //change.setIndex(0); - //change.added.addAll(children); - //change.apply(); - - current.added.add(branch); - if (current.index == -1) { - current.index = current.element.getElementIndex(offset); - if (branch.getElementCount() > 0 - && branch.getEndOffset() - > current.element.getElement(current.index) - .getStartOffset()) { - ++current.index; + current.added.add(newBranch); + if (current.getChildIndex() == -1) { + int newIndex = current.getChildIndexAtOffset(offset); + if (newBranch.getElementCount() > 0 + && newBranch.getEndOffset() + > current.getChildElement(newIndex).getStartOffset()) { + ++newIndex; } + current.setChildIndex(newIndex); } - if (!current.isApplied()) { - current.apply(); - } else { - int replaceIndex = current.element.getElementIndex(offset); - if (branch.getElementCount() > 0 - && branch.getEndOffset() - > current.element - .getElement(replaceIndex).getStartOffset()) { + if (current.isApplied()) { + int replaceIndex = current.getChildIndexAtOffset(offset); + if (newBranch.getElementCount() > 0 + && newBranch.getEndOffset() + > current.getChildElement(replaceIndex).getStartOffset()) { ++replaceIndex; } current.element.replace(replaceIndex, 0, - new Element[] {branch}); + new Element[] {newBranch}); + } else { + current.apply(); } - current = change; + current = new ChangeDesc(newBranch, true); changeStack.push(current); } + private void moveChildren(final BranchElement newParent, + final ChangeDesc sourceDesc, + final int startIndex) { + // copy all elements from lastBranch to the new one + final int count = sourceDesc.element.getElementCount(); + final Element[] children = new Element[count - startIndex]; + for (int i = startIndex; i < count; i++) { + children[i - startIndex] = clone(newParent, sourceDesc.getChildElement(i)); + } + // Now we need to remove all previously added elements which were + // copied from added list + final int i = startIndex - sourceDesc.getChildIndex(); + for (int j = startIndex; j < count; j++) { + final Object addedElement = sourceDesc.getAddedElement(i); + final Object existingElement = sourceDesc.getChildElement(j); + if (addedElement == existingElement) { + sourceDesc.added.remove(addedElement); + } else if (!sourceDesc.justCreated) { + sourceDesc.removed.add(existingElement); + } + } + // Complete the removal of elements from source + if (count - startIndex > 0) { + sourceDesc.element.replace(startIndex, count - startIndex, new Element[0]); + } + + // Place copied children into the new parent + newParent.replace(0, 0, children); + } + private void insertStartOriginate(final ElementSpec spec) { - if (!create) { + if (current == null) { + insertStartJoinPrevious(spec); + } else if (!create && !changes.isEmpty()) { insertStartFracture(spec); - } else if (current == null) { - insertStartJoinPrevious(); } else { Element branch = createBranchElement(current.element, spec.getAttributes()); - if (current.getIndex() < 0) { - current.setIndex(current.element.getElementIndex(offset)); - } + current.setChildIndexByOffset(offset); current.added.add(branch); current = new ChangeDesc(branch, true); changeStack.push(current); @@ -622,55 +577,63 @@ } private void insertStartJoinNext(final ElementSpec spec) { - final int index = current.element.getElementIndex(offset); - current = new ChangeDesc(current.element.getElement(index)); + current = new ChangeDesc(current.getChildAtOffset(offset)); changeStack.push(current); } - private void insertStartJoinPrevious() { + private void insertStartJoinPrevious(final ElementSpec spec) { if (current == null) { current = new ChangeDesc(getRootElement()); + // TODO are old attributes to be removed? + final AttributeSet specAttr = spec.getAttributes(); + if (specAttr != null) { + ((AbstractElement)getRootElement()).addAttributes(specAttr); + } changeStack.push(current); } else { - final int index = current.element.getElementIndex(offset); - current = new ChangeDesc(current.element.getElement(index)); + current = new ChangeDesc(current.getChildAtOffset(offset)); changeStack.push(current); } } private void insertEndTag() { - if (current.removed.size() == 0 && current.added.size() == 0) { - current.setIndex(current.element.getElementIndex(offset)); - Element leaf = current.element.getElement(current.getIndex()); + if (current.isEmpty()) { + current.setChildIndexByOffset(offset); + Element leaf = current.getCurrentChild(); final int start = leaf.getStartOffset(); final int end = leaf.getEndOffset(); if (start < offset && offset < end || start < offset + length && offset + length < end) { - current.removed.add(leaf); - - if (leaf.getStartOffset() < offset) { - current.added.add( - createLeafElement(current.element, - leaf.getAttributes(), - leaf.getStartOffset(), - offset)); + if (leaf.isLeaf()) { + current.splitLeafElement(leaf, offset, offset + length, false, null); + } else if (length != 0) { + BranchElement rightBranch = splitBranch(leaf); + current.added.add(rightBranch); + int newIndex = current.getChildIndexAtOffset(offset + length); + if (rightBranch.getElementCount() > 0 + && rightBranch.getEndOffset() + > current.getChildElement(newIndex).getStartOffset()) { + ++newIndex; + } + current.childIndex = newIndex; } - if (offset + length < leaf.getEndOffset()) { - current.added.add( - createLeafElement(current.element, - leaf.getAttributes(), - offset + length, - leaf.getEndOffset())); - } } } leaveParagraph(); changes.add(current); changeStack.pop(); - current = (ChangeDesc)changeStack.peek(); + current = changeStack.empty() ? null : (ChangeDesc)changeStack.peek(); } + private BranchElement splitBranch(final Element branch) { + BranchElement result = current.createBranchElement(branch.getAttributes()); + final ChangeDesc lastChange = (ChangeDesc)changes.get(changes.size() - 1); + int startIndex = lastChange.getChildIndexAtOffset(offset + length); + moveChildren(result, lastChange, startIndex); + return result; + } + private BranchElement findLastExistedBranch() { int i = changes.size() - 1; ChangeDesc desc = null; @@ -681,35 +644,19 @@ } private void leaveParagraph() { - if ((current.removed.size() == 0 && current.added.size() == 0)) { + if (current == null || current.isEmpty()) { return; } - if (current.removed.size() > 0 - && offset < ((Element)current.removed.get(current.removed.size() - - 1)).getEndOffset() - && !(current.added.size() > 0 - && offset < ((Element)current.added - .get(current.added.size() - 1)) - .getEndOffset())) { - final Element leaf = current.element - .getElement(current.getIndex()); - if (event.getOffset() + event.getLength() - < leaf.getEndOffset()) { - - current.added.add(createLeafElement(current.element, - leaf.getAttributes(), - event.getOffset() - + event.getLength(), - leaf.getEndOffset())); - } + if (tail != null) { + current.added.add(tail); } + tail = null; current.apply(); } private Element[] listToElementArray(final List list) { - Element[] result = new Element[list.size()]; - return (Element[])list.toArray(result); + return (Element[])list.toArray(new Element[list.size()]); } private void initChangeLists() { @@ -725,8 +672,10 @@ this.changes.clear(); this.changeStack.clear(); + this.current = null; this.create = false; + this.tail = null; } private void readObject(final ObjectInputStream ois) @@ -875,9 +824,9 @@ } } - private static final class ChangeDesc { + private final class ChangeDesc { public final BranchElement element; - private int index = -1; + private int childIndex = -1; public final List added = new ArrayList(); public final List removed = new ArrayList(); public final boolean justCreated; @@ -893,30 +842,32 @@ this.justCreated = justCreated; } - public void setIndex(final int index) { - if (this.index != -1) { - throw new Error("Index has already been set, " - + "and cannot be changed."); + public ChangeDesc(final Element element, + final int offset) { + this(element, false); + setChildIndexByOffset(offset); + } + + public void setChildIndex(final int index) { + if (this.childIndex == -1) { + this.childIndex = index; } - this.index = index; } - public int getIndex() { - return index; + public int getChildIndex() { + return childIndex; } public Element[] getChildrenAdded() { - final Element[] result = new Element[added.size()]; - return (Element[])added.toArray(result); + return (Element[])added.toArray(new Element[added.size()]); } public Element[] getChildrenRemoved() { - final Element[] result = new Element[removed.size()]; - return (Element[])removed.toArray(result); + return (Element[])removed.toArray(new Element[removed.size()]); } public ElementEdit toElementEdit() { - return new ElementEdit(element, index, + return new ElementEdit(element, childIndex, getChildrenRemoved(), getChildrenAdded()); } @@ -925,12 +876,12 @@ if (applied || isEmpty()) { return; } - if (index == -1) { - throw new Error("Index is not initialized"); + if (childIndex == -1) { + childIndex = 0; } applied = true; - element.replace(index, removed.size(), getChildrenAdded()); + element.replace(childIndex, removed.size(), getChildrenAdded()); } public boolean isEmpty() { @@ -940,6 +891,84 @@ public boolean isApplied() { return applied; } + + public void createLeafElement(final AttributeSet attr, final int start, + final int end) { + added.add(DefaultStyledDocument.this.createLeafElement(element, attr, start, end)); + } + + public BranchElement createBranchElement(final AttributeSet attr) { + return (BranchElement)DefaultStyledDocument.this.createBranchElement(element, attr); + } + + public void splitLeafElement(final Element leaf, final int splitOffset) { + final AttributeSet attrs = leaf.getAttributes(); + createLeafElement(attrs , leaf.getStartOffset(), splitOffset); + createLeafElement(attrs, splitOffset, leaf.getEndOffset()); + removed.add(leaf); + } + + public void splitLeafElement(final Element child, + final int splitOffset1, + final int splitOffset2, + final boolean createMiddle, + final AttributeSet middleAttr) { + splitLeafElement(child, splitOffset1, splitOffset2, splitOffset2, createMiddle, middleAttr); + } + + public void splitLeafElement(final Element child, + final int splitOffset1, + final int splitOffset2, + final int splitOffset3, + final boolean createMiddle, + final AttributeSet middleAttr) { + final AttributeSet attrs = child.getAttributes(); + if (child.getStartOffset() < splitOffset1) { + createLeafElement(attrs, child.getStartOffset(), splitOffset1); + } + if (createMiddle) { + createLeafElement(middleAttr, splitOffset1, splitOffset2); + } + if (splitOffset3 < child.getEndOffset()) { + createLeafElement(attrs, splitOffset3, child.getEndOffset()); + } + removed.add(child); + } + + public void setChildIndexByOffset(final int offset) { + setChildIndex(element.getElementIndex(offset)); + } + + public Element getChildAtOffset(final int offset) { + return element.getElement(element.getElementIndex(offset)); + } + + public int getChildIndexAtOffset(final int offset) { + return element.getElementIndex(offset); + } + + public Element getCurrentChild() { + return element.getElement(childIndex); + } + + public Element getChildElement(final int index) { + return element.getElement(index); + } + + public void removeChildElement(final int index) { + removed.add(element.getElement(index)); + } + + public Element getAddedElement(final int i) { + return (i > 0 && i < added.size()) ? (Element)added.get(i) : null; + } + + public Element getLastAddedElement() { + return (Element)added.get(added.size() - 1); + } + public Element getLastRemovedElement() { + return (Element)removed.get(removed.size() - 1); + } } public static final int BUFFER_SIZE_DEFAULT = 4096; @@ -1004,8 +1033,13 @@ } public Element getParagraphElement(final int offset) { - Element root = getDefaultRootElement(); - return root.getElement(root.getElementIndex(offset)); + Element branch; + Element child = getDefaultRootElement(); + do { + branch = child; + child = branch.getElement(branch.getElementIndex(offset)); + } while (!child.isLeaf()); + return branch; } public void setCharacterAttributes(final int offset, @@ -1132,13 +1166,7 @@ } protected void create(final ElementSpec[] specs) { - final StringBuffer text = new StringBuffer(); - for (int i = 0; i < specs.length; i++) { - if (specs[i].getLength() > 0) { - text.append(specs[i].getArray(), specs[i].getOffset(), - specs[i].getLength()); - } - } + final StringBuffer text = appendSpecsText(specs); writeLock(); try { @@ -1188,13 +1216,7 @@ protected void insert(final int offset, final ElementSpec[] specs) throws BadLocationException { - final StringBuffer text = new StringBuffer(); - for (int i = 0; i < specs.length; i++) { - if (specs[i].getLength() > 0) { - text.append(specs[i].getArray(), specs[i].getOffset(), - specs[i].getLength()); - } - } + final StringBuffer text = appendSpecsText(specs); writeLock(); try { UndoableEdit contentInsert = @@ -1246,15 +1268,15 @@ final boolean hasLineBreak = firstBreak != -1; Element charElem = getCharacterElement(offset); - ElementSpec spec; + ElementSpec spec = null; if (!hasLineBreak) { if (splitPrevParagraph) { - specs.add(new ElementSpec(null, ElementSpec.EndTagType)); - - spec = new ElementSpec(defaultLogicalStyle, - ElementSpec.StartTagType); - spec.setDirection(ElementSpec.JoinNextDirection); - specs.add(spec); + splitBranch(specs, offset, length, charElem, + ElementSpec.JoinNextDirection); + // The direction of the next Content element must be chosen + // based on attributes of the first Content element + // in the next paragraph + charElem = getCharacterElement(offset + length); } spec = new ElementSpec(attributes, ElementSpec.ContentType, length); if (charElem.getAttributes().isEqual(attributes)) { @@ -1269,10 +1291,8 @@ int processedLength = 0; if (splitPrevParagraph) { - specs.add(new ElementSpec(null, ElementSpec.EndTagType)); - - specs.add(new ElementSpec(defaultLogicalStyle, - ElementSpec.StartTagType)); + splitBranch(specs, offset, length, charElem, + ElementSpec.OriginateDirection); } while (currentOffset < offset + length) { @@ -1322,6 +1342,31 @@ super.insertUpdate(event, attrs); } + private void splitBranch(final List specs, + final int offset, final int length, + final Element leaf, + final short lastSpecDirection) { + ElementSpec spec = null; + Element branch = leaf.getParentElement(); + final int endOffset = offset + length; + while (branch != null && branch.getEndOffset() == endOffset) { + specs.add(new ElementSpec(null, ElementSpec.EndTagType)); + branch = branch.getParentElement(); + } + + branch = branch.getElement(branch.getElementIndex(offset) + 1); + while (branch != null + && !branch.isLeaf() + && branch.getStartOffset() == endOffset) { + spec = new ElementSpec(branch.getAttributes(), + ElementSpec.StartTagType); + spec.setDirection(ElementSpec.JoinNextDirection); + specs.add(spec); + branch = branch.getElement(0); + } + spec.setDirection(lastSpecDirection); + } + protected void removeUpdate(final DefaultDocumentEvent event) { buffer.remove(event.getOffset(), event.getLength(), event); } @@ -1329,6 +1374,17 @@ protected void styleChanged(final Style style) { } + private StringBuffer appendSpecsText(final ElementSpec[] specs) { + final StringBuffer result = new StringBuffer(); + for (int i = 0; i < specs.length; i++) { + if (specs[i].getLength() > 0) { + result.append(specs[i].getArray(), specs[i].getOffset(), + specs[i].getLength()); + } + } + return result; + } + private void addListenerToStyles() { final Enumeration names = getStyleNames(); while (names.hasMoreElements()) { Index: modules/swing/src/main/java/common/javax/swing/text/DefaultEditorKit.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/text/DefaultEditorKit.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/text/DefaultEditorKit.java (working copy) @@ -22,7 +22,9 @@ import java.awt.event.ActionEvent; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import javax.swing.Action; @@ -316,15 +318,7 @@ public void read(final InputStream in, final Document doc, final int pos) throws IOException, BadLocationException { - byte[] readArray = new byte[in.available()]; - in.read(readArray); - String readStr = new String(readArray); - doc.putProperty(EndOfLineStringProperty, null); - if (checkDelimiters(readStr, doc)) { - readStr = replaceLineDelimiters(doc, readStr); - } - AttributeSet attributes = doc.getDefaultRootElement().getAttributes(); - doc.insertString(pos, readStr, attributes); + read(new InputStreamReader(in), doc, pos); } public void read(final Reader in, final Document doc, final int pos) @@ -342,10 +336,14 @@ while ((numCharRead = in.read(readArray, 0, maxCharToRead)) != -1) { String readStr = new String(readArray, 0, numCharRead); if (!delimiterInitialised) { - delimiterInitialised = checkDelimiters(readStr, doc); + final String lineDelimeter = checkDelimiters(readStr); + if (lineDelimeter != null) { + doc.putProperty(EndOfLineStringProperty, lineDelimeter); + delimiterInitialised = true; + } } if (delimiterInitialised) { - readStr = replaceLineDelimiters(doc, readStr); + readStr = replaceLineDelimiters(readStr); } doc.insertString(offset, readStr, attributes); offset += readStr.length(); @@ -355,13 +353,7 @@ public void write(final OutputStream out, final Document doc, final int pos, final int len) throws IOException, BadLocationException { - String writeStr = doc.getText(pos, len); - String newLine = (String) doc.getProperty(EndOfLineStringProperty); - if (newLine != null) { - writeStr = writeStr.replaceAll("\n", (String) doc - .getProperty(EndOfLineStringProperty)); - } - out.write(writeStr.getBytes()); + write(new OutputStreamWriter(out), doc, pos, len); } public void write(final Writer out, final Document doc, final int pos, @@ -375,7 +367,7 @@ out.write(writeStr); } - private boolean checkDelimiters(final String str, final Document doc) { + private String checkDelimiters(final String str) { String lineDelimeter = null; final int length = str.length(); for (int i = 0; i < length; i++) { @@ -392,14 +384,10 @@ break; } } - if (lineDelimeter == null) { - return false; - } - doc.putProperty(EndOfLineStringProperty, lineDelimeter); - return true; + return lineDelimeter; } - private String replaceLineDelimiters(final Document doc, final String str) { + private String replaceLineDelimiters(final String str) { int index = str.indexOf('\r'); if (index == -1) { return str; Index: modules/swing/src/main/java/common/javax/swing/text/View.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/text/View.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/text/View.java (working copy) @@ -205,7 +205,9 @@ } final View view = getView(index); - return view != null ? view.getToolTipText(x, y, shape) : null; + return view != null + ? view.getToolTipText(x, y, getChildAllocation(index, shape)) + : null; } public View getView(final int index) { @@ -221,9 +223,14 @@ } public int getViewIndex(final float x, final float y, final Shape shape) { + if (shape == null) { + return -1; + } + final int count = getViewCount(); for (int i = 0; i < count; i++) { - if (getChildAllocation(i, shape).contains(x, y)) { + final Shape childAllocation = getChildAllocation(i, shape); + if (childAllocation != null && childAllocation.contains(x, y)) { return i; } } Index: modules/swing/src/main/java/common/javax/swing/text/BoxView.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/text/BoxView.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/text/BoxView.java (working copy) @@ -30,6 +30,7 @@ import javax.swing.text.Position.Bias; import org.apache.harmony.x.swing.SizeRequirementsHelper; +import org.apache.harmony.x.swing.Utilities; public class BoxView extends CompositeView { @@ -85,19 +86,20 @@ public float getMinimumSpan(final int axis) { isAxisValid(axis); - return getTotalRequirements(axis).minimum; + return getTotalRequirements(axis).minimum + getSideInset(axis); } public float getPreferredSpan(final int axis) { isAxisValid(axis); - return getTotalRequirements(axis).preferred; + return getTotalRequirements(axis).preferred + getSideInset(axis); } public float getMaximumSpan(final int axis) { isAxisValid(axis); - return getTotalRequirements(axis).maximum; + return Utilities.safeIntSum(getTotalRequirements(axis).maximum, + getSideInset(axis)); } public int getResizeWeight(final int axis) { @@ -116,12 +118,12 @@ } public void paint(final Graphics g, final Shape shape) { - final Rectangle bounds = shape.getBounds(); + final Rectangle insideAlloc = getInsideAllocation(shape); final Rectangle allocation = new Rectangle(); final Rectangle clipBounds = g.getClipBounds(); for (int i = 0; i < getViewCount(); i++) { - allocation.setBounds(bounds); + allocation.setBounds(insideAlloc); childAllocation(i, allocation); if (allocation.intersects(clipBounds)) { paintChild(g, allocation, i); @@ -160,8 +162,8 @@ } public void setSize(final float width, final float height) { - layout((int)(width - getLeftInset() - getRightInset()), - (int)(height - getTopInset() - getBottomInset())); + layout((int)(width - getSideInset(X_AXIS)), + (int)(height - getSideInset(Y_AXIS))); } public int getWidth() { @@ -560,4 +562,10 @@ return newArray; } + private int getSideInset(final int axis) { + if (axis == X_AXIS) { + return getLeftInset() + getRightInset(); + } + return getTopInset() + getBottomInset(); + } } Index: modules/swing/src/main/java/common/javax/swing/text/FlowView.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/text/FlowView.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/text/FlowView.java (working copy) @@ -30,6 +30,8 @@ public abstract class FlowView extends BoxView { public static class FlowStrategy { + private static FlowStrategy sharedStrategy; + public void insertUpdate(final FlowView fv, final DocumentEvent event, final Rectangle alloc) { @@ -127,12 +129,16 @@ span = (int)view.getPreferredSpan(flowAxis); weight = view.getBreakWeight(flowAxis, offset, rowSpan); if (weight >= ForcedBreakWeight) { - view = view.breakView(flowAxis, offset, x, rowSpan); + final View broken = view.breakView(flowAxis, offset, x, rowSpan); + if (view == broken && row.getViewCount() > 0) { + break; + } + view = broken; } row.append(view); offset = view.getEndOffset(); } - } while (view != null && span < rowSpan + } while (view != null && span <= rowSpan && weight < ForcedBreakWeight); if (span > rowSpan) { @@ -163,6 +169,14 @@ return result; } + static FlowStrategy getSharedStrategy() { + if (sharedStrategy == null) { + sharedStrategy = new FlowStrategy(); + } + + return sharedStrategy; + } + private void invalidateFlow(final FlowView fv, final DocumentEvent event, final Rectangle alloc) { @@ -190,31 +204,14 @@ super(element); } - protected void childAllocation(final int index, final Rectangle rc) { + public int getResizeWeight(final int axis) { + return 1; } - protected View getViewAtPoint(final int x, final int y, - final Rectangle alloc) { - throw new UnsupportedOperationException("Not implemented"); + public float getMinimumSpan(final int axis) { + return 0; } - protected int getViewIndexAtPosition(final int pos) { - if (pos < getStartOffset() || pos >= getEndOffset()) { - return -1; - } - return super.getViewIndexAtPosition(pos); - } - - protected boolean isAfter(final int x, final int y, - final Rectangle rc) { - throw new UnsupportedOperationException("Not implemented"); - } - - protected boolean isBefore(final int x, final int y, - final Rectangle rc) { - throw new UnsupportedOperationException("Not implemented"); - } - public float getPreferredSpan(final int axis) { if (axis == X_AXIS) { if (spanX == -1) { @@ -229,8 +226,13 @@ return spanY; } + public float getMaximumSpan(final int axis) { + return getPreferredSpan(axis); + } + public void paint(final Graphics g, final Shape shape) { - throw new UnsupportedOperationException("Not implemented"); + throw new UnsupportedOperationException("Not applicable to " + + "Layout Pool"); } public void preferenceChanged(final View child, @@ -245,6 +247,11 @@ super.preferenceChanged(child, width, height); } + public AttributeSet getAttributes() { + final View parent = getParent(); + return parent != null ? parent.getAttributes() : null; + } + protected void loadChildren(final ViewFactory factory) { if (factory != null) { super.loadChildren(factory); @@ -259,6 +266,34 @@ super.forwardUpdateToView(view, event, shape, factory); } + protected void childAllocation(final int index, final Rectangle rc) { + } + + protected View getViewAtPoint(final int x, final int y, + final Rectangle alloc) { + throw new UnsupportedOperationException("Not applicable to " + + "Layout Pool"); + } + + protected int getViewIndexAtPosition(final int pos) { + if (pos < getStartOffset() || pos >= getEndOffset()) { + return -1; + } + return super.getViewIndexAtPosition(pos); + } + + protected boolean isAfter(final int x, final int y, + final Rectangle rc) { + throw new UnsupportedOperationException("Not applicable to " + + "Layout Pool"); + } + + protected boolean isBefore(final int x, final int y, + final Rectangle rc) { + throw new UnsupportedOperationException("Not applicable to " + + "Layout Pool"); + } + private float getSpanX() { float span = 0; for (int i = 0; i < getViewCount(); i++) { @@ -279,7 +314,7 @@ protected View layoutPool; protected int layoutSpan = Short.MAX_VALUE; - protected FlowStrategy strategy = new FlowStrategy(); + protected FlowStrategy strategy = FlowStrategy.getSharedStrategy(); public FlowView(final Element element, final int axis) { super(element, axis); @@ -317,17 +352,13 @@ strategy.changedUpdate(this, event, shapeToRect(alloc)); } - public void setParent(final View parentView) { - super.setParent(parentView); - } - protected SizeRequirements calculateMinorAxisRequirements(final int axis, final SizeRequirements sr) { SizeRequirements result = sr != null ? sr : new SizeRequirements(); result.minimum = (int)layoutPool.getMinimumSpan(axis); result.preferred = (int)layoutPool.getPreferredSpan(axis); - result.maximum = Short.MAX_VALUE; + result.maximum = Integer.MAX_VALUE; result.alignment = ALIGN_CENTER; return result; } Index: modules/swing/src/main/java/common/javax/swing/text/CompositeView.java =================================================================== --- modules/swing/src/main/java/common/javax/swing/text/CompositeView.java (revision 424221) +++ modules/swing/src/main/java/common/javax/swing/text/CompositeView.java (working copy) @@ -102,7 +102,7 @@ public void setParent(final View parentView) { super.setParent(parentView); - if (getViewCount() == 0) { + if (parentView != null && getViewCount() == 0) { loadChildren(getViewFactory()); } } @@ -175,7 +175,7 @@ final Bias[] biasReturn) { biasReturn[0] = Bias.Forward; - Rectangle bounds = shape.getBounds(); + Rectangle bounds = getInsideAllocation(shape); if (isBefore((int)x, (int)y, bounds)) { return getStartOffset(); @@ -212,6 +212,10 @@ } protected void loadChildren(final ViewFactory factory) { + if (factory == null) { + return; + } + final int count = getElement().getElementCount(); View[] views = new View[count];