Exemplo n.º 1
0
TEST_F(StaticRangeTest, InvalidToRange)
{
    document().body()->setInnerHTML("1234", ASSERT_NO_EXCEPTION);
    Text* oldText = toText(document().body()->firstChild());

    StaticRange* staticRange04 = StaticRange::create(document(), oldText, 0, oldText, 4);

    // Valid StaticRange.
    staticRange04->toRange(ASSERT_NO_EXCEPTION);

    oldText->splitText(2, ASSERT_NO_EXCEPTION);
    // StaticRange shouldn't mutate, endOffset() become invalid after splitText().
    EXPECT_EQ(oldText, staticRange04->startContainer());
    EXPECT_EQ(0, staticRange04->startOffset());
    EXPECT_EQ(oldText, staticRange04->endContainer());
    EXPECT_EQ(4, staticRange04->endOffset());

    // Invalid StaticRange.
    TrackExceptionState exceptionState;
    staticRange04->toRange(exceptionState);
    EXPECT_TRUE(exceptionState.hadException());
}
Exemplo n.º 2
0
unsigned CharacterData::parserAppendData(const String& string, unsigned offset, unsigned lengthLimit)
{
    unsigned oldLength = m_data.length();

    ASSERT(lengthLimit >= oldLength);

    unsigned characterLength = string.length() - offset;
    unsigned characterLengthLimit = min(characterLength, lengthLimit - oldLength);

    // Check that we are not on an unbreakable boundary.
    // Some text break iterator implementations work best if the passed buffer is as small as possible,
    // see <https://bugs.webkit.org/show_bug.cgi?id=29092>.
    // We need at least two characters look-ahead to account for UTF-16 surrogates.
    if (characterLengthLimit < characterLength) {
        NonSharedCharacterBreakIterator it(string.characters() + offset, (characterLengthLimit + 2 > characterLength) ? characterLength : characterLengthLimit + 2);
        if (!isTextBreak(it, characterLengthLimit))
            characterLengthLimit = textBreakPreceding(it, characterLengthLimit);
    }

    if (!characterLengthLimit)
        return 0;

    if (string.is8Bit())
        m_data.append(string.characters8() + offset, characterLengthLimit);
    else
        m_data.append(string.characters16() + offset, characterLengthLimit);

    ASSERT(!renderer() || isTextNode());
    if (isTextNode())
        toText(this)->updateTextRenderer(oldLength, 0);

    document()->incDOMTreeVersion();
    // We don't call dispatchModifiedEvent here because we don't want the
    // parser to dispatch DOM mutation events.
    if (parentNode())
        parentNode()->childrenChanged();

    return characterLengthLimit;
}
Exemplo n.º 3
0
void replaceChildrenWithText(ContainerNode* container,
                             const String& text,
                             ExceptionState& exceptionState) {
  DCHECK(container);
  ContainerNode* containerNode(container);

  ChildListMutationScope mutation(*containerNode);

  // FIXME: This is wrong if containerNode->firstChild() has more than one ref!
  // Example:
  // <div>foo</div>
  // <script>
  // var oldText = div.firstChild;
  // console.log(oldText.data); // foo
  // div.innerText = "bar";
  // console.log(oldText.data); // bar!?!
  // </script>
  // I believe this is an intentional benchmark cheat from years ago.
  // We should re-visit if we actually want this still.
  if (containerNode->hasOneTextChild()) {
    toText(containerNode->firstChild())->setData(text);
    return;
  }

  // NOTE: This method currently always creates a text node, even if that text
  // node will be empty.
  Text* textNode = Text::create(containerNode->document(), text);

  // FIXME: No need to replace the child it is a text node and its contents are
  // already == text.
  if (containerNode->hasOneChild()) {
    containerNode->replaceChild(textNode, containerNode->firstChild(),
                                exceptionState);
    return;
  }

  containerNode->removeChildren();
  containerNode->appendChild(textNode, exceptionState);
}
Exemplo n.º 4
0
unsigned HTMLTextFormControlElement::indexForPosition(const Position& passedPosition) const
{
    TextControlInnerTextElement* innerText = innerTextElement();
    if (!innerText || !innerText->contains(passedPosition.anchorNode()) || passedPosition.isNull())
        return 0;

    if (positionBeforeNode(innerText) == passedPosition)
        return 0;

    unsigned index = 0;
    Node* startNode = passedPosition.computeNodeBeforePosition();
    if (!startNode)
        startNode = passedPosition.containerNode();
    ASSERT(startNode);
    ASSERT(innerText->contains(startNode));

    for (Node* node = startNode; node; node = NodeTraversal::previous(node, innerText)) {
        if (node->isTextNode()) {
            unsigned length = toText(*node).length();
            if (node == passedPosition.containerNode())
                index += std::min<unsigned>(length, passedPosition.offsetInContainerNode());
            else
                index += length;
        } else if (node->hasTagName(brTag))
            index++;
    }

    unsigned length = innerTextValue().length();
    index = std::min(index, length); // FIXME: We shouldn't have to call innerTextValue() just to ignore the last LF. See finishText.
#ifndef ASSERT_DISABLED
    VisiblePosition visiblePosition = passedPosition;
    unsigned indexComputedByVisiblePosition = 0;
    if (visiblePosition.isNotNull())
        indexComputedByVisiblePosition = WebCore::indexForVisiblePosition(innerText, visiblePosition, false /* forSelectionPreservation */);
    ASSERT(index == indexComputedByVisiblePosition);
#endif
    return index;
}
Exemplo n.º 5
0
void InputMethodController::setCompositionFromExistingText(const Vector<CompositionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd)
{
    Element* editable = m_frame.selection().rootEditableElement();
    Position base = m_frame.selection().base().downstream();
    Node* baseNode = base.anchorNode();
    if (editable->firstChild() == baseNode && editable->lastChild() == baseNode && baseNode->isTextNode()) {
        m_compositionNode = nullptr;
        m_customCompositionUnderlines.clear();

        if (base.anchorType() != Position::PositionIsOffsetInAnchor)
            return;
        if (!baseNode || baseNode != m_frame.selection().extent().anchorNode())
            return;

        m_compositionNode = toText(baseNode);
        RefPtr<Range> range = PlainTextRange(compositionStart, compositionEnd).createRange(*editable);
        m_compositionStart = range->startOffset();
        m_compositionEnd = range->endOffset();
        m_customCompositionUnderlines = underlines;
        size_t numUnderlines = m_customCompositionUnderlines.size();
        for (size_t i = 0; i < numUnderlines; ++i) {
            m_customCompositionUnderlines[i].startOffset += m_compositionStart;
            m_customCompositionUnderlines[i].endOffset += m_compositionStart;
        }

        // TODO(ojan): What was this for? Do we need it in sky since we
        // don't need to support legacy IMEs?
        if (baseNode->renderer())
            baseNode->document().scheduleVisualUpdate();

        return;
    }

    Editor::RevealSelectionScope revealSelectionScope(&editor());
    SelectionOffsetsScope selectionOffsetsScope(this);
    setSelectionOffsets(PlainTextRange(compositionStart, compositionEnd));
    setComposition(m_frame.selectedText(), underlines, 0, 0);
}
Exemplo n.º 6
0
void MarkupAccumulator::appendStartMarkup(StringBuilder& result, const Node& node, Namespaces* namespaces)
{
    if (namespaces)
        namespaces->checkConsistency();

    switch (node.nodeType()) {
    case Node::TEXT_NODE:
        appendText(result, toText(node));
        break;
    case Node::COMMENT_NODE:
        appendComment(result, toComment(node).data());
        break;
    case Node::DOCUMENT_NODE:
        appendXMLDeclaration(result, toDocument(node));
        break;
    case Node::DOCUMENT_FRAGMENT_NODE:
        break;
    case Node::DOCUMENT_TYPE_NODE:
        appendDocumentType(result, toDocumentType(node));
        break;
    case Node::PROCESSING_INSTRUCTION_NODE:
        appendProcessingInstruction(result, toProcessingInstruction(node).target(), toProcessingInstruction(node).data());
        break;
    case Node::ELEMENT_NODE:
        appendElement(result, toElement(node), namespaces);
        break;
    case Node::CDATA_SECTION_NODE:
        appendCDATASection(result, toCDATASection(node).data());
        break;
    case Node::ATTRIBUTE_NODE:
    case Node::ENTITY_NODE:
    case Node::ENTITY_REFERENCE_NODE:
    case Node::NOTATION_NODE:
    case Node::XPATH_NAMESPACE_NODE:
        ASSERT_NOT_REACHED();
        break;
    }
}
Exemplo n.º 7
0
int main(int argc,char *argv[])
{
    const CniWrapper* cniWrapper = startCniWrapper();

    if (cniWrapper)
    {
        // Test the Dice class.

        printf("\nTesting the execution of the Dice class:\n\n");

        int i;

        for (i = 0;i < 12;i++)
        {
            Dice* theDice = rollDice();

            if (theDice)
            {
//              printf("White: %d Colored: %d Combined: %2d\n",
//                     whiteDieValue(theDice),
//                     coloredDieValue(theDice),
//                     combinedResult(theDice));

                printf("%s\n",toText(theDice));

                deleteDice(theDice);
            }

            else printf("New Dice object generation failed\n");
        }

        stopCniWrapper();
    }

    else printf("New CniWrapper object generation failed\n");

    return 0;
}
Exemplo n.º 8
0
void NodeRenderingContext::createRendererForTextIfNeeded()
{
    ASSERT(!m_node->renderer());

    Text* textNode = toText(m_node);

    if (!shouldCreateRenderer())
        return;

    RenderObject* parentRenderer = this->parentRenderer();
    ASSERT(parentRenderer);
    Document* document = textNode->document();

    if (resetStyleInheritance())
        m_style = document->styleResolver()->defaultStyleForElement();
    else
        m_style = parentRenderer->style();

    if (!textNode->textRendererIsNeeded(*this))
        return;
    RenderText* newRenderer = textNode->createTextRenderer(m_style.get());
    if (!newRenderer)
        return;
    if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) {
        newRenderer->destroy();
        return;
    }

    // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
    // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
    newRenderer->setFlowThreadState(parentRenderer->flowThreadState());

    RenderObject* nextRenderer = this->nextRenderer();
    textNode->setRenderer(newRenderer);
    // Parent takes care of the animations, no need to call setAnimatableStyle.
    newRenderer->setStyle(m_style.release());
    parentRenderer->addChild(newRenderer, nextRenderer);
}
// If this is the layoutObject for a first-letter pseudoNode then we have to look
// at the node for the remaining text to find our content.
Text* LayoutTextFragment::associatedTextNode() const
{
    Node* node = this->firstLetterPseudoElement();
    if (m_isRemainingTextLayoutObject || !node) {
        // If we don't have a node, then we aren't part of a first-letter pseudo
        // element, so use the actual node. Likewise, if we have a node, but
        // we're the remainingTextLayoutObject for a pseudo element use the real
        // text node.
        node = this->node();
    }

    if (!node)
        return nullptr;

    if (node->isFirstLetterPseudoElement()) {
        FirstLetterPseudoElement* pseudo = toFirstLetterPseudoElement(node);
        LayoutObject* nextLayoutObject = FirstLetterPseudoElement::firstLetterTextLayoutObject(*pseudo);
        if (!nextLayoutObject)
            return nullptr;
        node = nextLayoutObject->node();
    }
    return (node && node->isTextNode()) ? toText(node) : nullptr;
}
Exemplo n.º 10
0
void InputMethodController::setCompositionFromExistingText(const Vector<CompositionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd)
{
    Element* editable = frame().selection().rootEditableElement();
    Position base = frame().selection().base().downstream();
    Node* baseNode = base.anchorNode();
    if (baseNode && editable->firstChild() == baseNode && editable->lastChild() == baseNode && baseNode->isTextNode()) {
        m_compositionNode = nullptr;
        m_customCompositionUnderlines.clear();

        if (base.anchorType() != Position::PositionIsOffsetInAnchor)
            return;
        if (baseNode != frame().selection().extent().anchorNode())
            return;

        m_compositionNode = toText(baseNode);
        RefPtrWillBeRawPtr<Range> range = PlainTextRange(compositionStart, compositionEnd).createRange(*editable);
        if (!range)
            return;

        m_compositionStart = range->startOffset();
        m_compositionEnd = range->endOffset();
        m_customCompositionUnderlines = underlines;
        size_t numUnderlines = m_customCompositionUnderlines.size();
        for (size_t i = 0; i < numUnderlines; ++i) {
            m_customCompositionUnderlines[i].startOffset += m_compositionStart;
            m_customCompositionUnderlines[i].endOffset += m_compositionStart;
        }
        if (baseNode->layoutObject())
            baseNode->layoutObject()->setShouldDoFullPaintInvalidation();
        return;
    }

    Editor::RevealSelectionScope revealSelectionScope(&editor());
    SelectionOffsetsScope selectionOffsetsScope(this);
    setSelectionOffsets(PlainTextRange(compositionStart, compositionEnd));
    setComposition(frame().selectedText(), underlines, 0, 0);
}
Exemplo n.º 11
0
static void createTextRenderersForSiblingsAfterAttachIfNeeded(Node* sibling)
{
    ASSERT(sibling->previousSibling());
    ASSERT(sibling->previousSibling()->renderer());
    ASSERT(!sibling->renderer());
    ASSERT(sibling->attached());
    // If this node got a renderer it may be the previousRenderer() of sibling text nodes and thus affect the
    // result of Text::textRendererIsNeeded() for those nodes.
    for (; sibling; sibling = sibling->nextSibling()) {
        if (sibling->renderer())
            break;
        if (!sibling->attached())
            break; // Assume this means none of the following siblings are attached.
        if (!sibling->isTextNode())
            continue;
        ASSERT(!sibling->renderer());
        attachTextRenderer(*toText(sibling));
        // If we again decided not to create a renderer for next, we can bail out the loop,
        // because it won't affect the result of Text::textRendererIsNeeded() for the rest
        // of sibling nodes.
        if (!sibling->renderer())
            break;
    }
}
Exemplo n.º 12
0
 TextPtr Node::toTextChecked() const throw(Exceptions::CheckFailed)
 {
   TextPtr result = toText();
   ZS_THROW_CUSTOM_IF(Exceptions::CheckFailed, !result)
   return result;
 }
void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, const RenderRegion* region) const
{
    LayoutUnit logicalTopForRegion;
    LayoutUnit logicalBottomForRegion;

    // extend the first region top to contain everything up to its logical height
    if (region->isFirstRegion())
        logicalTopForRegion = LayoutUnit::min();
    else
        logicalTopForRegion =  region->logicalTopForFlowThreadContent();

    // extend the last region to contain everything above its y()
    if (region->isLastRegion())
        logicalBottomForRegion = LayoutUnit::max();
    else
        logicalBottomForRegion = region->logicalBottomForFlowThreadContent();

    Vector<Node*> nodes;
    // eliminate the contentNodes that are descendants of other contentNodes
    for (NamedFlowContentNodes::const_iterator it = contentNodes().begin(); it != contentNodes().end(); ++it) {
        Node* node = *it;
        if (!isContainedInNodes(nodes, node))
            nodes.append(node);
    }

    for (size_t i = 0; i < nodes.size(); i++) {
        Node* contentNode = nodes.at(i);
        if (!contentNode->renderer())
            continue;

        RefPtr<Range> range = Range::create(contentNode->document());
        bool foundStartPosition = false;
        bool startsAboveRegion = true;
        bool endsBelowRegion = true;
        bool skipOverOutsideNodes = false;
        Node* lastEndNode = 0;

        for (Node* node = contentNode; node; node = nextNodeInsideContentNode(node, contentNode)) {
            RenderObject* renderer = node->renderer();
            if (!renderer)
                continue;

            LayoutRect boundingBox;
            if (renderer->isRenderInline())
                boundingBox = toRenderInline(renderer)->linesBoundingBox();
            else if (renderer->isText())
                boundingBox = toRenderText(renderer)->linesBoundingBox();
            else {
                boundingBox =  toRenderBox(renderer)->frameRect();
                if (toRenderBox(renderer)->isRelPositioned())
                    boundingBox.move(toRenderBox(renderer)->relativePositionLogicalOffset());
            }

            LayoutUnit offsetTop = renderer->containingBlock()->offsetFromLogicalTopOfFirstPage();
            const LayoutPoint logicalOffsetFromTop(isHorizontalWritingMode() ? LayoutUnit() :  offsetTop,
                isHorizontalWritingMode() ? offsetTop : LayoutUnit());

            boundingBox.moveBy(logicalOffsetFromTop);

            LayoutUnit logicalTopForRenderer = region->logicalTopOfFlowThreadContentRect(boundingBox);
            LayoutUnit logicalBottomForRenderer = region->logicalBottomOfFlowThreadContentRect(boundingBox);

            // if the bounding box of the current element doesn't intersect the region box
            // close the current range only if the start element began inside the region,
            // otherwise just move the start position after this node and keep skipping them until we found a proper start position.
            if (!boxIntersectsRegion(logicalTopForRenderer, logicalBottomForRenderer, logicalTopForRegion, logicalBottomForRegion)) {
                if (foundStartPosition) {
                    if (!startsAboveRegion) {
                        if (range->intersectsNode(node, IGNORE_EXCEPTION))
                            range->setEndBefore(node, IGNORE_EXCEPTION);
                        rangeObjects.append(range->cloneRange(IGNORE_EXCEPTION));
                        range = Range::create(contentNode->document());
                        startsAboveRegion = true;
                    } else
                        skipOverOutsideNodes = true;
                }
                if (skipOverOutsideNodes)
                    range->setStartAfter(node, IGNORE_EXCEPTION);
                foundStartPosition = false;
                continue;
            }

            // start position
            if (logicalTopForRenderer < logicalTopForRegion && startsAboveRegion) {
                if (renderer->isText()) { // Text crosses region top
                    // for Text elements, just find the last textbox that is contained inside the region and use its start() offset as start position
                    RenderText* textRenderer = toRenderText(renderer);
                    for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
                        if (offsetTop + box->logicalBottom() < logicalTopForRegion)
                            continue;
                        range->setStart(Position(toText(node), box->start()));
                        startsAboveRegion = false;
                        break;
                    }
                } else { // node crosses region top
                    // for all elements, except Text, just set the start position to be before their children
                    startsAboveRegion = true;
                    range->setStart(Position(node, Position::PositionIsBeforeChildren));
                }
            } else { // node starts inside region
                // for elements that start inside the region, set the start position to be before them. If we found one, we will just skip the others until
                // the range is closed.
                if (startsAboveRegion) {
                    startsAboveRegion = false;
                    range->setStartBefore(node, IGNORE_EXCEPTION);
                }
            }
            skipOverOutsideNodes  = false;
            foundStartPosition = true;

            // end position
            if (logicalBottomForRegion < logicalBottomForRenderer && (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode)))) {
                // for Text elements, just find just find the last textbox that is contained inside the region and use its start()+len() offset as end position
                if (renderer->isText()) { // Text crosses region bottom
                    RenderText* textRenderer = toRenderText(renderer);
                    InlineTextBox* lastBox = 0;
                    for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
                        if ((offsetTop + box->logicalTop()) < logicalBottomForRegion) {
                            lastBox = box;
                            continue;
                        }
                        ASSERT(lastBox);
                        if (lastBox)
                            range->setEnd(Position(toText(node), lastBox->start() + lastBox->len()));
                        break;
                    }
                    endsBelowRegion = false;
                    lastEndNode = node;
                } else { // node crosses region bottom
                    // for all elements, except Text, just set the start position to be after their children
                    range->setEnd(Position(node, Position::PositionIsAfterChildren));
                    endsBelowRegion = true;
                    lastEndNode = node;
                }
            } else { // node ends inside region
                // for elements that ends inside the region, set the end position to be after them
                // allow this end position to be changed only by other elements that are not descendants of the current end node
                if (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode))) {
                    range->setEndAfter(node, IGNORE_EXCEPTION);
                    endsBelowRegion = false;
                    lastEndNode = node;
                }
            }
        }
        if (foundStartPosition || skipOverOutsideNodes)
            rangeObjects.append(range);
    }
}
Exemplo n.º 14
0
void resolveTree(Element* current, Change change)
{
    ASSERT(change != Detach);

    if (current->hasCustomStyleResolveCallbacks()) {
        if (!current->willRecalcStyle(change))
            return;
    }

    bool hasParentStyle = current->parentNodeForRenderingAndStyle() && current->parentNodeForRenderingAndStyle()->renderStyle();
    bool hasDirectAdjacentRules = current->childrenAffectedByDirectAdjacentRules();
    bool hasIndirectAdjacentRules = current->childrenAffectedByForwardPositionalRules();

    if (change > NoChange || current->needsStyleRecalc())
        current->resetComputedStyle();

    if (hasParentStyle && (change >= Inherit || current->needsStyleRecalc()))
        change = resolveLocal(current, change);

    if (change != Detach) {
        StyleResolverParentPusher parentPusher(current);

        RenderStyle* currentStyle = current->renderStyle();

        if (ShadowRoot* shadowRoot = current->shadowRoot()) {
            if (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc()) {
                parentPusher.push();
                resolveShadowTree(shadowRoot, currentStyle, change);
            }
        }

        current->updateBeforePseudoElement(change);

        // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
        // For now we will just worry about the common case, since it's a lot trickier to get the second case right
        // without doing way too much re-resolution.
        bool forceCheckOfNextElementSibling = false;
        bool forceCheckOfAnyElementSibling = false;
        for (Node* child = current->firstChild(); child; child = child->nextSibling()) {
            if (child->isTextNode()) {
                updateTextStyle(toText(child), currentStyle, change);
                continue;
            }
            if (!child->isElementNode())
                continue;
            Element* childElement = toElement(child);
            bool childRulesChanged = childElement->needsStyleRecalc() && childElement->styleChangeType() == FullStyleChange;
            if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
                childElement->setNeedsStyleRecalc();
            if (change >= Inherit || childElement->childNeedsStyleRecalc() || childElement->needsStyleRecalc()) {
                parentPusher.push();
                resolveTree(childElement, change);
            }
            forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
            forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
        }

        current->updateAfterPseudoElement(change);
    }

    current->clearNeedsStyleRecalc();
    current->clearChildNeedsStyleRecalc();
    
    if (current->hasCustomStyleResolveCallbacks())
        current->didRecalcStyle(change);
}
/**
 * @brief provides the representation for the text to be displayed
 * @param value of the item
 * @param locale -- not used
 * @return the text in the respresentation to be displayed
 *
 * This method is re-implemented
 */
QString TextPanelItemDelegate::displayText(const QVariant &value, const QLocale &locale) const
{
    Q_UNUSED(locale);
    return toText(value);
}
/**
 * @brief sets the data from the model into the editor field
 * @param editor that is used
 * @param index of the item
 *
 * This method is re-implemented
 */
void TextPanelItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    QLineEdit *lineeditor = qobject_cast<QLineEdit *>(editor);
    lineeditor->setText(toText(index.model()->data(index, Qt::EditRole)));
}
void InsertParagraphSeparatorCommand::doApply()
{
    if (!endingSelection().isNonOrphanedCaretOrRange())
        return;

    Position insertionPosition = endingSelection().start();

    EAffinity affinity = endingSelection().affinity();

    // Delete the current selection.
    if (endingSelection().isRange()) {
        calculateStyleBeforeInsertion(insertionPosition);
        deleteSelection(false, true);
        insertionPosition = endingSelection().start();
        affinity = endingSelection().affinity();
    }

    // FIXME: The parentAnchoredEquivalent conversion needs to be moved into enclosingBlock.
    RefPtr<Element> startBlock = enclosingBlock(insertionPosition.parentAnchoredEquivalent().containerNode());
    Position canonicalPos = VisiblePosition(insertionPosition).deepEquivalent();
    if (!startBlock
        || !startBlock->nonShadowBoundaryParentNode()
        // FIXME: If the node is hidden, we don't have a canonical position so we will do the wrong thing for tables and <hr>. https://bugs.webkit.org/show_bug.cgi?id=40342
        || (!canonicalPos.isNull() && isRenderedTableElement(canonicalPos.deprecatedNode()))) {
        applyCommandToComposite(InsertLineBreakCommand::create(document()));
        return;
    }

    // Use the leftmost candidate.
    insertionPosition = insertionPosition.upstream();
    if (!insertionPosition.isCandidate())
        insertionPosition = insertionPosition.downstream();

    // Adjust the insertion position after the delete
    insertionPosition = positionAvoidingSpecialElementBoundary(insertionPosition);
    VisiblePosition visiblePos(insertionPosition, affinity);
    calculateStyleBeforeInsertion(insertionPosition);

    //---------------------------------------------------------------------
    // Handle special case of typing return on an empty list item
    if (breakOutOfEmptyListItem())
        return;

    //---------------------------------------------------------------------
    // Prepare for more general cases.

    bool isFirstInBlock = isStartOfBlock(visiblePos);
    bool isLastInBlock = isEndOfBlock(visiblePos);
    bool nestNewBlock = false;

    // Create block to be inserted.
    RefPtr<Element> blockToInsert = nullptr;
    if (startBlock->isRootEditableElement()) {
        blockToInsert = createDefaultParagraphElement(document());
        nestNewBlock = true;
    } else if (shouldUseDefaultParagraphElement(startBlock.get())) {
        blockToInsert = createDefaultParagraphElement(document());
    } else {
        blockToInsert = startBlock->cloneElementWithoutChildren();
    }

    //---------------------------------------------------------------------
    // Handle case when position is in the last visible position in its block,
    // including when the block is empty.
    if (isLastInBlock) {
        if (nestNewBlock) {
            if (isFirstInBlock && !lineBreakExistsAtVisiblePosition(visiblePos)) {
                // The block is empty.  Create an empty block to
                // represent the paragraph that we're leaving.
                RefPtr<HTMLElement> extraBlock = createDefaultParagraphElement(document());
                appendNode(extraBlock, startBlock);
            }
            appendNode(blockToInsert, startBlock);
        } else {
            // Most of the time we want to stay at the nesting level of the startBlock (e.g., when nesting within lists). However,
            // for div nodes, this can result in nested div tags that are hard to break out of.
            Element* siblingElement = startBlock.get();
            insertNodeAfter(blockToInsert, siblingElement);
        }

        // Recreate the same structure in the new paragraph.

        Vector<RefPtr<Element> > ancestors;
        getAncestorsInsideBlock(positionOutsideTabSpan(insertionPosition).deprecatedNode(), startBlock.get(), ancestors);
        RefPtr<Element> parent = cloneHierarchyUnderNewBlock(ancestors, blockToInsert);

        setEndingSelection(VisibleSelection(firstPositionInNode(parent.get()), DOWNSTREAM, endingSelection().isDirectional()));
        return;
    }


    //---------------------------------------------------------------------
    // Handle case when position is in the first visible position in its block, and
    // similar case where previous position is in another, presumeably nested, block.
    if (isFirstInBlock || !inSameBlock(visiblePos, visiblePos.previous())) {
        Node* refNode = 0;
        insertionPosition = positionOutsideTabSpan(insertionPosition);

        if (isFirstInBlock && !nestNewBlock) {
            refNode = startBlock.get();
        } else if (isFirstInBlock && nestNewBlock) {
            // startBlock should always have children, otherwise isLastInBlock would be true and it's handled above.
            ASSERT(startBlock->hasChildren());
            refNode = startBlock->firstChild();
        }
        else if (insertionPosition.deprecatedNode() == startBlock && nestNewBlock) {
            refNode = NodeTraversal::childAt(*startBlock, insertionPosition.deprecatedEditingOffset());
            ASSERT(refNode); // must be true or we'd be in the end of block case
        } else
            refNode = insertionPosition.deprecatedNode();

        // find ending selection position easily before inserting the paragraph
        insertionPosition = insertionPosition.downstream();

        if (refNode)
            insertNodeBefore(blockToInsert, refNode);

        // Recreate the same structure in the new paragraph.

        Vector<RefPtr<Element> > ancestors;
        getAncestorsInsideBlock(positionAvoidingSpecialElementBoundary(positionOutsideTabSpan(insertionPosition)).deprecatedNode(), startBlock.get(), ancestors);

        // In this case, we need to set the new ending selection.
        setEndingSelection(VisibleSelection(insertionPosition, DOWNSTREAM, endingSelection().isDirectional()));
        return;
    }

    //---------------------------------------------------------------------
    // Handle the (more complicated) general case,

    // Move downstream. Typing style code will take care of carrying along the
    // style of the upstream position.
    insertionPosition = insertionPosition.downstream();

    // At this point, the insertionPosition's node could be a container, and we want to make sure we include
    // all of the correct nodes when building the ancestor list.  So this needs to be the deepest representation of the position
    // before we walk the DOM tree.
    insertionPosition = positionOutsideTabSpan(VisiblePosition(insertionPosition).deepEquivalent());

    // If the returned position lies either at the end or at the start of an element that is ignored by editing
    // we should move to its upstream or downstream position.
    if (editingIgnoresContent(insertionPosition.deprecatedNode())) {
        if (insertionPosition.atLastEditingPositionForNode())
            insertionPosition = insertionPosition.downstream();
        else if (insertionPosition.atFirstEditingPositionForNode())
            insertionPosition = insertionPosition.upstream();
    }

    // Make sure we do not cause a rendered space to become unrendered.
    // FIXME: We need the affinity for pos, but pos.downstream() does not give it
    Position leadingWhitespace = leadingWhitespacePosition(insertionPosition, VP_DEFAULT_AFFINITY);
    // FIXME: leadingWhitespacePosition is returning the position before preserved newlines for positions
    // after the preserved newline, causing the newline to be turned into a nbsp.
    if (leadingWhitespace.isNotNull() && leadingWhitespace.deprecatedNode()->isTextNode()) {
        Text* textNode = toText(leadingWhitespace.deprecatedNode());
        ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
        replaceTextInNodePreservingMarkers(textNode, leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    }

    // Split at pos if in the middle of a text node.
    Position positionAfterSplit;
    if (insertionPosition.anchorType() == Position::PositionIsOffsetInAnchor && insertionPosition.containerNode()->isTextNode()) {
        RefPtr<Text> textNode = toText(insertionPosition.containerNode());
        bool atEnd = static_cast<unsigned>(insertionPosition.offsetInContainerNode()) >= textNode->length();
        if (insertionPosition.deprecatedEditingOffset() > 0 && !atEnd) {
            splitTextNode(textNode, insertionPosition.offsetInContainerNode());
            positionAfterSplit = firstPositionInNode(textNode.get());
            insertionPosition.moveToPosition(textNode->previousSibling(), insertionPosition.offsetInContainerNode());
            visiblePos = VisiblePosition(insertionPosition);
        }
    }

    // If we got detached due to mutation events, just bail out.
    if (!startBlock->parentNode())
        return;

    // Put the added block in the tree.
    if (nestNewBlock) {
        appendNode(blockToInsert.get(), startBlock);
    } else {
        insertNodeAfter(blockToInsert.get(), startBlock);
    }

    document().updateLayoutIgnorePendingStylesheets();

    // Move the start node and the siblings of the start node.
    if (VisiblePosition(insertionPosition) != VisiblePosition(positionBeforeNode(blockToInsert.get()))) {
        Node* n;
        if (insertionPosition.containerNode() == startBlock)
            n = insertionPosition.computeNodeAfterPosition();
        else {
            Node* splitTo = insertionPosition.containerNode();
            if (splitTo->isTextNode() && insertionPosition.offsetInContainerNode() >= caretMaxOffset(splitTo))
                splitTo = NodeTraversal::next(*splitTo, startBlock.get());
            ASSERT(splitTo);
            splitTreeToNode(splitTo, startBlock.get());

            for (n = startBlock->firstChild(); n; n = n->nextSibling()) {
                VisiblePosition beforeNodePosition(positionBeforeNode(n));
                if (!beforeNodePosition.isNull() && comparePositions(VisiblePosition(insertionPosition), beforeNodePosition) <= 0)
                    break;
            }
        }

        moveRemainingSiblingsToNewParent(n, blockToInsert.get(), blockToInsert);
    }

    // Handle whitespace that occurs after the split
    if (positionAfterSplit.isNotNull()) {
        document().updateLayoutIgnorePendingStylesheets();
        if (!positionAfterSplit.isRenderedCharacter()) {
            // Clear out all whitespace and insert one non-breaking space
            ASSERT(!positionAfterSplit.containerNode()->renderer() || positionAfterSplit.containerNode()->renderer()->style()->collapseWhiteSpace());
            deleteInsignificantTextDownstream(positionAfterSplit);
            if (positionAfterSplit.deprecatedNode()->isTextNode())
                insertTextIntoNode(toText(positionAfterSplit.containerNode()), 0, nonBreakingSpaceString());
        }
    }

    setEndingSelection(VisibleSelection(firstPositionInNode(blockToInsert.get()), DOWNSTREAM, endingSelection().isDirectional()));
}
Exemplo n.º 18
0
TEST_F(StaticRangeTest, SplitTextNodeRangeOutsideText)
{
    document().body()->setInnerHTML("<span id=\"outer\">0<span id=\"inner-left\">1</span>SPLITME<span id=\"inner-right\">2</span>3</span>", ASSERT_NO_EXCEPTION);

    Element* outer = document().getElementById(AtomicString::fromUTF8("outer"));
    Element* innerLeft = document().getElementById(AtomicString::fromUTF8("inner-left"));
    Element* innerRight = document().getElementById(AtomicString::fromUTF8("inner-right"));
    Text* oldText = toText(outer->childNodes()->item(2));

    StaticRange* staticRangeOuterOutside = StaticRange::create(document(), outer, 0, outer, 5);
    StaticRange* staticRangeOuterInside = StaticRange::create(document(), outer, 1, outer, 4);
    StaticRange* staticRangeOuterSurroundingText = StaticRange::create(document(), outer, 2, outer, 3);
    StaticRange* staticRangeInnerLeft = StaticRange::create(document(), innerLeft, 0, innerLeft, 1);
    StaticRange* staticRangeInnerRight = StaticRange::create(document(), innerRight, 0, innerRight, 1);
    StaticRange* staticRangeFromTextToMiddleOfElement = StaticRange::create(document(), oldText, 6, outer, 3);

    Range* rangeOuterOutside = staticRangeOuterOutside->toRange(ASSERT_NO_EXCEPTION);
    Range* rangeOuterInside = staticRangeOuterInside->toRange(ASSERT_NO_EXCEPTION);
    Range* rangeOuterSurroundingText = staticRangeOuterSurroundingText->toRange(ASSERT_NO_EXCEPTION);
    Range* rangeInnerLeft = staticRangeInnerLeft->toRange(ASSERT_NO_EXCEPTION);
    Range* rangeInnerRight = staticRangeInnerRight->toRange(ASSERT_NO_EXCEPTION);
    Range* rangeFromTextToMiddleOfElement = staticRangeFromTextToMiddleOfElement->toRange(ASSERT_NO_EXCEPTION);

    oldText->splitText(3, ASSERT_NO_EXCEPTION);
    Text* newText = toText(oldText->nextSibling());

    // Range should mutate.
    EXPECT_TRUE(rangeOuterOutside->boundaryPointsValid());
    EXPECT_EQ(outer, rangeOuterOutside->startContainer());
    EXPECT_EQ(0, rangeOuterOutside->startOffset());
    EXPECT_EQ(outer, rangeOuterOutside->endContainer());
    EXPECT_EQ(6, rangeOuterOutside->endOffset()); // Increased by 1 since a new node is inserted.

    EXPECT_TRUE(rangeOuterInside->boundaryPointsValid());
    EXPECT_EQ(outer, rangeOuterInside->startContainer());
    EXPECT_EQ(1, rangeOuterInside->startOffset());
    EXPECT_EQ(outer, rangeOuterInside->endContainer());
    EXPECT_EQ(5, rangeOuterInside->endOffset());

    EXPECT_TRUE(rangeOuterSurroundingText->boundaryPointsValid());
    EXPECT_EQ(outer, rangeOuterSurroundingText->startContainer());
    EXPECT_EQ(2, rangeOuterSurroundingText->startOffset());
    EXPECT_EQ(outer, rangeOuterSurroundingText->endContainer());
    EXPECT_EQ(4, rangeOuterSurroundingText->endOffset());

    EXPECT_TRUE(rangeInnerLeft->boundaryPointsValid());
    EXPECT_EQ(innerLeft, rangeInnerLeft->startContainer());
    EXPECT_EQ(0, rangeInnerLeft->startOffset());
    EXPECT_EQ(innerLeft, rangeInnerLeft->endContainer());
    EXPECT_EQ(1, rangeInnerLeft->endOffset());

    EXPECT_TRUE(rangeInnerRight->boundaryPointsValid());
    EXPECT_EQ(innerRight, rangeInnerRight->startContainer());
    EXPECT_EQ(0, rangeInnerRight->startOffset());
    EXPECT_EQ(innerRight, rangeInnerRight->endContainer());
    EXPECT_EQ(1, rangeInnerRight->endOffset());

    EXPECT_TRUE(rangeFromTextToMiddleOfElement->boundaryPointsValid());
    EXPECT_EQ(newText, rangeFromTextToMiddleOfElement->startContainer());
    EXPECT_EQ(3, rangeFromTextToMiddleOfElement->startOffset());
    EXPECT_EQ(outer, rangeFromTextToMiddleOfElement->endContainer());
    EXPECT_EQ(4, rangeFromTextToMiddleOfElement->endOffset());

    // StaticRange shouldn't mutate.
    EXPECT_EQ(outer, staticRangeOuterOutside->startContainer());
    EXPECT_EQ(0, staticRangeOuterOutside->startOffset());
    EXPECT_EQ(outer, staticRangeOuterOutside->endContainer());
    EXPECT_EQ(5, staticRangeOuterOutside->endOffset());

    EXPECT_EQ(outer, staticRangeOuterInside->startContainer());
    EXPECT_EQ(1, staticRangeOuterInside->startOffset());
    EXPECT_EQ(outer, staticRangeOuterInside->endContainer());
    EXPECT_EQ(4, staticRangeOuterInside->endOffset());

    EXPECT_EQ(outer, staticRangeOuterSurroundingText->startContainer());
    EXPECT_EQ(2, staticRangeOuterSurroundingText->startOffset());
    EXPECT_EQ(outer, staticRangeOuterSurroundingText->endContainer());
    EXPECT_EQ(3, staticRangeOuterSurroundingText->endOffset());

    EXPECT_EQ(innerLeft, staticRangeInnerLeft->startContainer());
    EXPECT_EQ(0, staticRangeInnerLeft->startOffset());
    EXPECT_EQ(innerLeft, staticRangeInnerLeft->endContainer());
    EXPECT_EQ(1, staticRangeInnerLeft->endOffset());

    EXPECT_EQ(innerRight, staticRangeInnerRight->startContainer());
    EXPECT_EQ(0, staticRangeInnerRight->startOffset());
    EXPECT_EQ(innerRight, staticRangeInnerRight->endContainer());
    EXPECT_EQ(1, staticRangeInnerRight->endOffset());

    EXPECT_EQ(oldText, staticRangeFromTextToMiddleOfElement->startContainer());
    EXPECT_EQ(6, staticRangeFromTextToMiddleOfElement->startOffset());
    EXPECT_EQ(outer, staticRangeFromTextToMiddleOfElement->endContainer());
    EXPECT_EQ(3, staticRangeFromTextToMiddleOfElement->endOffset());
}
Exemplo n.º 19
0
TEST_F(StaticRangeTest, SplitTextNodeRangeWithinText)
{
    document().body()->setInnerHTML("1234", ASSERT_NO_EXCEPTION);
    Text* oldText = toText(document().body()->firstChild());

    StaticRange* staticRange04 = StaticRange::create(document(), oldText, 0, oldText, 4);
    StaticRange* staticRange02 = StaticRange::create(document(), oldText, 0, oldText, 2);
    StaticRange* staticRange22 = StaticRange::create(document(), oldText, 2, oldText, 2);
    StaticRange* staticRange24 = StaticRange::create(document(), oldText, 2, oldText, 4);

    Range* range04 = staticRange04->toRange(ASSERT_NO_EXCEPTION);
    Range* range02 = staticRange02->toRange(ASSERT_NO_EXCEPTION);
    Range* range22 = staticRange22->toRange(ASSERT_NO_EXCEPTION);
    Range* range24 = staticRange24->toRange(ASSERT_NO_EXCEPTION);

    oldText->splitText(2, ASSERT_NO_EXCEPTION);
    Text* newText = toText(oldText->nextSibling());

    // Range should mutate.
    EXPECT_TRUE(range04->boundaryPointsValid());
    EXPECT_EQ(oldText, range04->startContainer());
    EXPECT_EQ(0, range04->startOffset());
    EXPECT_EQ(newText, range04->endContainer());
    EXPECT_EQ(2, range04->endOffset());

    EXPECT_TRUE(range02->boundaryPointsValid());
    EXPECT_EQ(oldText, range02->startContainer());
    EXPECT_EQ(0, range02->startOffset());
    EXPECT_EQ(oldText, range02->endContainer());
    EXPECT_EQ(2, range02->endOffset());

    // Our implementation always moves the boundary point at the separation point to the end of the original text node.
    EXPECT_TRUE(range22->boundaryPointsValid());
    EXPECT_EQ(oldText, range22->startContainer());
    EXPECT_EQ(2, range22->startOffset());
    EXPECT_EQ(oldText, range22->endContainer());
    EXPECT_EQ(2, range22->endOffset());

    EXPECT_TRUE(range24->boundaryPointsValid());
    EXPECT_EQ(oldText, range24->startContainer());
    EXPECT_EQ(2, range24->startOffset());
    EXPECT_EQ(newText, range24->endContainer());
    EXPECT_EQ(2, range24->endOffset());

    // StaticRange shouldn't mutate.
    EXPECT_EQ(oldText, staticRange04->startContainer());
    EXPECT_EQ(0, staticRange04->startOffset());
    EXPECT_EQ(oldText, staticRange04->endContainer());
    EXPECT_EQ(4, staticRange04->endOffset());

    EXPECT_EQ(oldText, staticRange02->startContainer());
    EXPECT_EQ(0, staticRange02->startOffset());
    EXPECT_EQ(oldText, staticRange02->endContainer());
    EXPECT_EQ(2, staticRange02->endOffset());

    EXPECT_EQ(oldText, staticRange22->startContainer());
    EXPECT_EQ(2, staticRange22->startOffset());
    EXPECT_EQ(oldText, staticRange22->endContainer());
    EXPECT_EQ(2, staticRange22->endOffset());

    EXPECT_EQ(oldText, staticRange24->startContainer());
    EXPECT_EQ(2, staticRange24->startOffset());
    EXPECT_EQ(oldText, staticRange24->endContainer());
    EXPECT_EQ(4, staticRange24->endOffset());
}
Exemplo n.º 20
0
string
Geometry::toString() const
{
	return toText();
}
Exemplo n.º 21
0
void Matrix4x4::print() const {
	char buffer[256];
	toText(buffer, 256);
	puts(buffer);
}
void InputMethodController::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
{
    UserTypingGestureIndicator typingGestureIndicator(m_frame);

    Editor::RevealSelectionScope revealSelectionScope(&editor());

    // Updates styles before setting selection for composition to prevent
    // inserting the previous composition text into text nodes oddly.
    // See https://bugs.webkit.org/show_bug.cgi?id=46868
    m_frame->document()->updateStyleIfNeeded();

    selectComposition();

    if (m_frame->selection().isNone())
        return;

    if (Element* target = m_frame->document()->focusedElement()) {
        // Dispatch an appropriate composition event to the focused node.
        // We check the composition status and choose an appropriate composition event since this
        // function is used for three purposes:
        // 1. Starting a new composition.
        //    Send a compositionstart and a compositionupdate event when this function creates
        //    a new composition node, i.e.
        //    m_compositionNode == 0 && !text.isEmpty().
        //    Sending a compositionupdate event at this time ensures that at least one
        //    compositionupdate event is dispatched.
        // 2. Updating the existing composition node.
        //    Send a compositionupdate event when this function updates the existing composition
        //    node, i.e. m_compositionNode != 0 && !text.isEmpty().
        // 3. Canceling the ongoing composition.
        //    Send a compositionend event when function deletes the existing composition node, i.e.
        //    m_compositionNode != 0 && test.isEmpty().
        RefPtr<CompositionEvent> event;
        if (!m_compositionNode) {
            // We should send a compositionstart event only when the given text is not empty because this
            // function doesn't create a composition node when the text is empty.
            if (!text.isEmpty()) {
                target->dispatchEvent(CompositionEvent::create(eventNames().compositionstartEvent, m_frame->domWindow(), m_frame->selectedText()));
                event = CompositionEvent::create(eventNames().compositionupdateEvent, m_frame->domWindow(), text);
            }
        } else {
            if (!text.isEmpty())
                event = CompositionEvent::create(eventNames().compositionupdateEvent, m_frame->domWindow(), text);
            else
                event = CompositionEvent::create(eventNames().compositionendEvent, m_frame->domWindow(), text);
        }
        if (event.get())
            target->dispatchEvent(event, IGNORE_EXCEPTION);
    }

    // If text is empty, then delete the old composition here. If text is non-empty, InsertTextCommand::input
    // will delete the old composition with an optimized replace operation.
    if (text.isEmpty()) {
        ASSERT(m_frame->document());
        TypingCommand::deleteSelection(*m_frame->document(), TypingCommand::PreventSpellChecking);
    }

    m_compositionNode = 0;
    m_customCompositionUnderlines.clear();

    if (!text.isEmpty()) {
        ASSERT(m_frame->document());
        TypingCommand::insertText(*m_frame->document(), text, TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextCompositionUpdate);

        // Find out what node has the composition now.
        Position base = m_frame->selection().base().downstream();
        Position extent = m_frame->selection().extent();
        Node* baseNode = base.deprecatedNode();
        unsigned baseOffset = base.deprecatedEditingOffset();
        Node* extentNode = extent.deprecatedNode();
        unsigned extentOffset = extent.deprecatedEditingOffset();

        if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
            m_compositionNode = toText(baseNode);
            m_compositionStart = baseOffset;
            m_compositionEnd = extentOffset;
            m_customCompositionUnderlines = underlines;
            size_t numUnderlines = m_customCompositionUnderlines.size();
            for (size_t i = 0; i < numUnderlines; ++i) {
                m_customCompositionUnderlines[i].startOffset += baseOffset;
                m_customCompositionUnderlines[i].endOffset += baseOffset;
            }
            if (baseNode->renderer())
                baseNode->renderer()->repaint();

            unsigned start = std::min(baseOffset + selectionStart, extentOffset);
            unsigned end = std::min(std::max(start, baseOffset + selectionEnd), extentOffset);
            RefPtr<Range> selectedRange = Range::create(baseNode->document(), baseNode, start, baseNode, end);
            m_frame->selection().setSelectedRange(selectedRange.get(), DOWNSTREAM, false);
        }
    }
}
Exemplo n.º 23
0
int main(int argc, char *argv[]) 
{
  ATerm bottomOfStack;
  ATerm at_tree;
  char *ATlibArgv[] = {"pandora", "-at-termtable", "21"};
  PT_ParseTree tree; 
  PT_Tree ptText;
  BOX_Start box;
  char *input = "-";
  char *output = "-";
  ATbool boxOutput = ATfalse;
  ATbool bytesOutput = ATfalse;
  int c;
  int i;
  ATbool useToolbus = ATfalse;

  ATinit(3, ATlibArgv, &bottomOfStack); 
  ASC_initRunTime(INITIAL_TABLE_SIZE);
  PT_initMEPTApi(); 
  PTPT_initPTMEPTApi();
  BOX_initBoxApi();
  ERR_initErrorManager("pandora", "all");

  register_Box_to_Text();
  resolve_Box_to_Text();
  init_Box_to_Text();


  for (i=1; !useToolbus && i < argc; i++) {
    useToolbus = !strcmp(argv[i], "-TB_TOOL_NAME");
  }

  if (useToolbus) {
    int cid;
    ATBinit(argc, argv, &bottomOfStack);
    cid = ATBconnect(NULL, NULL, -1, pandora_handler);
    ATBeventloop();
  }
  else {
    while ((c = getopt(argc, argv, myarguments)) != -1) {
      switch (c) {
	case 'b':  boxOutput=ATtrue; break;
	case 'B':  bytesOutput=ATtrue; break;
	case 'i':  input=optarg; break;
	case 'o':  output=optarg; break;
	case 'v':  run_verbose = ATtrue; break;
	case 'V':  version(); exit(0);
	case 'h':  usage(); exit(0);
	default:   usage(); exit(1); 
      }
    }

    at_tree = ATreadFromNamedFile(input);

    if (at_tree != NULL) {
      tree = PT_ParseTreeFromTerm(at_tree);

      if (run_verbose) {
	ATwarning("pandora: mapping parse trees to "
		  "BOX using default rules\n");
      }

      box = pandora(tree);

      if (!boxOutput) {      
	if (run_verbose) {
	  ATwarning("pandora: rendering BOX to list of characters\n");
	}

	ptText = toText(PT_ParseTreeFromTerm(BOX_StartToTerm(box)));


	if (run_verbose) {
	  ATwarning("pandora: yielding characters to output\n");
	}

	if (!strcmp(output, "-")) {
	  if (!bytesOutput) {
	    PT_yieldTreeToFile(ptText, stdout, ATfalse);
	  }
	  else {
	    ATwriteToNamedBinaryFile((ATerm) 
				     PT_makeValidParseTreeFromTree(ptText), 
				     "-");
	  }
	}
	else {
	  if (!bytesOutput) {
	    FILE *fp = fopen(output, "wb");
	    if (fp != NULL) {
	      PT_yieldTreeToFile(ptText, fp, ATfalse);
	    }
	    else {
	      ATerror("Could not open %s for writing.\n", output);
	    }
	  }
	  else {
	    ATwriteToNamedBinaryFile((ATerm) 
				     PT_makeValidParseTreeFromTree(ptText), 
				     output);
	  }
	}
      }
      else {
	PT_ParseTree ptBox = PT_ParseTreeFromTerm(BOX_StartToTerm(box));
	ATwriteToNamedSharedTextFile((ATerm) ptBox, output);
      }
    }
    else {
      ATwarning("Failed to read ATerm from file: %s\n", input); 
      return 1; 
    }
  }

  return 0;
}