Example #1
0
void HistoryController::restoreDocumentState()
{
    Document* doc = m_frame->document();
        
    HistoryItem* itemToRestore = 0;
    
    switch (m_frame->loader()->loadType()) {
        case FrameLoadTypeReload:
        case FrameLoadTypeReloadFromOrigin:
        case FrameLoadTypeSame:
        case FrameLoadTypeReplace:
            break;
        case FrameLoadTypeBack:
        case FrameLoadTypeBackWMLDeckNotAccessible:
        case FrameLoadTypeForward:
        case FrameLoadTypeIndexedBackForward:
        case FrameLoadTypeRedirectWithLockedBackForwardList:
        case FrameLoadTypeStandard:
            itemToRestore = m_currentItem.get(); 
    }
    
    if (!itemToRestore)
        return;

    LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->name().string().utf8().data(), itemToRestore);
    doc->setStateForNewFormElements(itemToRestore->documentState());
}
Example #2
0
void HistoryController::saveDocumentState()
{
    // FIXME: Reading this bit of FrameLoader state here is unfortunate.  I need to study
    // this more to see if we can remove this dependency.
    if (m_frame->loader()->stateMachine()->creatingInitialEmptyDocument())
        return;

    // For a standard page load, we will have a previous item set, which will be used to
    // store the form state.  However, in some cases we will have no previous item, and
    // the current item is the right place to save the state.  One example is when we
    // detach a bunch of frames because we are navigating from a site with frames to
    // another site.  Another is when saving the frame state of a frame that is not the
    // target of the current navigation (if we even decide to save with that granularity).

    // Because of previousItem's "masking" of currentItem for this purpose, it's important
    // that previousItem be cleared at the end of a page transition.  We leverage the
    // checkLoadComplete recursion to achieve this goal.

    HistoryItem* item = m_previousItem ? m_previousItem.get() : m_currentItem.get();
    if (!item)
        return;

    Document* document = m_frame->document();
    ASSERT(document);
    
    if (item->isCurrentDocument(document)) {
        LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame->tree()->name().string().utf8().data(), item);
        item->setDocumentState(document->formElementsState());
    }
}
Example #3
0
void CachedFrameBase::restore()
{
    ASSERT(m_document->view() == m_view);

    if (m_isMainFrame)
        m_view->setParentVisible(true);

    Frame& frame = m_view->frame();
    m_cachedFrameScriptData->restore(frame);

    if (m_document->svgExtensions())
        m_document->accessSVGExtensions().unpauseAnimations();

    frame.animation().resumeAnimationsForDocument(m_document.get());
    m_document->resumeActiveDOMObjects(ActiveDOMObject::PageCache);
    m_document->resumeScriptedAnimationControllerCallbacks();

    // It is necessary to update any platform script objects after restoring the
    // cached page.
    frame.script().updatePlatformScriptObjects();

    if (m_isComposited)
        frame.view()->restoreBackingStores();

    frame.loader().client().didRestoreFromPageCache();

    // Reconstruct the FrameTree. And open the child CachedFrames in their respective FrameLoaders.
    for (unsigned i = 0; i < m_childFrames.size(); ++i) {
        frame.tree().appendChild(&m_childFrames[i]->view()->frame());
        m_childFrames[i]->open();
    }

#if PLATFORM(IOS)
    if (m_isMainFrame) {
        frame.loader().client().didRestoreFrameHierarchyForCachedFrame();

        if (DOMWindow* domWindow = m_document->domWindow()) {
            // FIXME: Add SCROLL_LISTENER to the list of event types on Document, and use m_document->hasListenerType(). See <rdar://problem/9615482>.
            // FIXME: Can use Document::hasListenerType() now.
            if (domWindow->scrollEventListenerCount() && frame.page())
                frame.page()->chrome().client().setNeedsScrollNotifications(&frame, true);
        }
    }
#endif

    // FIXME: update Page Visibility state here.
    // https://bugs.webkit.org/show_bug.cgi?id=116770
    m_document->enqueuePageshowEvent(PageshowEventPersisted);

    HistoryItem* historyItem = frame.loader().history().currentItem();
    m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue());

#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
    if (m_document->hasTouchEventHandlers())
        m_document->page()->chrome().client().needTouchEvents(true);
#endif

    m_document->resume();
}
void CachedFrameBase::restore()
{
    ASSERT(m_document->view() == m_view);

    if (m_isMainFrame)
        m_view->setParentVisible(true);

    Frame* frame = m_view->frame();
    m_cachedFrameScriptData->restore(frame);

#if ENABLE(SVG)
    if (m_document->svgExtensions())
        m_document->accessSVGExtensions()->unpauseAnimations();
#endif

    frame->animation()->resumeAnimationsForDocument(m_document.get());
    frame->eventHandler()->setMousePressNode(m_mousePressNode.get());
    m_document->resumeActiveDOMObjects();
    m_document->resumeScriptedAnimationControllerCallbacks();

    // It is necessary to update any platform script objects after restoring the
    // cached page.
    frame->script()->updatePlatformScriptObjects();

#if USE(ACCELERATED_COMPOSITING)
    if (m_isComposited)
        frame->view()->restoreBackingStores();
#endif

    frame->loader()->client()->didRestoreFromPageCache();

    // Reconstruct the FrameTree
    for (unsigned i = 0; i < m_childFrames.size(); ++i)
        frame->tree()->appendChild(m_childFrames[i]->view()->frame());

    // Open the child CachedFrames in their respective FrameLoaders.
    for (unsigned i = 0; i < m_childFrames.size(); ++i)
        m_childFrames[i]->open();

    if (m_isMainFrame) {
        frame->loader()->client()->didRestoreFrameHierarchyForCachedFrame();

        if (DOMWindow* domWindow = m_document->domWindow()) {
            // FIXME: add SCROLL_LISTENER to the list of event types on Document, and use m_document->hasListenerType() <rdar://problem/9615482>
            if (domWindow->scrollEventListenerCount() > 0 && frame->page())
                frame->page()->chrome()->client()->setNeedsScrollNotifications(frame, true);
        }
    }

    m_document->enqueuePageshowEvent(PageshowEventPersisted);
    
    HistoryItem* historyItem = frame->loader()->history()->currentItem();
    m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue());
    

    m_document->documentDidBecomeActive();
}
// entry.getTarget()
JNIEXPORT jstring JNICALL Java_com_sun_webkit_BackForwardList_bflItemGetTarget(JNIEnv* env, jclass z, jlong jitem)
{
    HistoryItem* item = getItem(jitem);
    String target = item->target();
    if (!target.isEmpty()) {
        return target.toJavaString(env).releaseLocal();
    } else {
        return NULL;
    }
}
Example #6
0
int HistoryModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0) {
        return 0;
    }

    HistoryItem* parentItem = itemFromIndex(parent);

    return parentItem->childCount();
}
Example #7
0
QModelIndex HistoryModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent)) {
        return QModelIndex();
    }

    HistoryItem* parentItem = itemFromIndex(parent);
    HistoryItem* childItem = parentItem->child(row);

    return childItem ? createIndex(row, column, childItem) : QModelIndex();
}
Example #8
0
void ApiWrap::gotWebPages(const MTPmessages_Messages &msgs, mtpRequestId req) {
	const QVector<MTPMessage> *v = 0;
	switch (msgs.type()) {
	case mtpc_messages_messages:
		App::feedUsers(msgs.c_messages_messages().vusers);
		App::feedChats(msgs.c_messages_messages().vchats);
		v = &msgs.c_messages_messages().vmessages.c_vector().v;
		break;

	case mtpc_messages_messagesSlice:
		App::feedUsers(msgs.c_messages_messagesSlice().vusers);
		App::feedChats(msgs.c_messages_messagesSlice().vchats);
		v = &msgs.c_messages_messagesSlice().vmessages.c_vector().v;
		break;
	}

	QMap<int32, int32> msgsIds; // copied from feedMsgs
	for (int32 i = 0, l = v->size(); i < l; ++i) {
		const MTPMessage &msg(v->at(i));
		switch (msg.type()) {
		case mtpc_message: msgsIds.insert(msg.c_message().vid.v, i); break;
		case mtpc_messageEmpty: msgsIds.insert(msg.c_messageEmpty().vid.v, i); break;
		case mtpc_messageService: msgsIds.insert(msg.c_messageService().vid.v, i); break;
		}
	}

	MainWidget *m = App::main();
	for (QMap<int32, int32>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
		HistoryItem *item = App::histories().addToBack(v->at(*i), -1);
		if (item) {
			item->initDimensions();
			if (m) m->itemResized(item);
		}
	}

	const WebPageItems &items(App::webPageItems());
	for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend();) {
		if (i.value() == req) {
			if (i.key()->pendingTill > 0) {
				i.key()->pendingTill = -1;
				WebPageItems::const_iterator j = items.constFind(i.key());
				if (j != items.cend()) {
					for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) {
						k.key()->initDimensions();
						if (m) m->itemResized(k.key());
					}
				}
			}
			i = _webPagesPending.erase(i);
		} else {
			++i;
		}
	}
}
bool HistoryItem::isAncestorOf(const HistoryItem* item) const
{
    for (size_t i = 0; i < m_children.size(); ++i) {
        HistoryItem* child = m_children[i].get();
        if (child == item)
            return true;
        if (child->isAncestorOf(item))
            return true;
    }
    return false;
}
Example #10
0
void CachedFrameBase::restore()
{
    ASSERT(m_document->view() == m_view);

    if (m_isMainFrame)
        m_view->setParentVisible(true);

    Frame& frame = m_view->frame();
    m_cachedFrameScriptData->restore(&frame);

#if ENABLE(SVG)
    if (m_document->svgExtensions())
        m_document->accessSVGExtensions()->unpauseAnimations();
#endif

    frame.animation()->resumeAnimationsForDocument(m_document.get());
    frame.eventHandler().setMousePressNode(m_mousePressNode.get());
    m_document->resumeActiveDOMObjects(ActiveDOMObject::DocumentWillBecomeInactive);
    m_document->resumeScriptedAnimationControllerCallbacks();

    // It is necessary to update any platform script objects after restoring the
    // cached page.
    frame.script().updatePlatformScriptObjects();

#if USE(ACCELERATED_COMPOSITING)
    if (m_isComposited)
        frame.view()->restoreBackingStores();
#endif

    frame.loader().client()->didRestoreFromPageCache();

    // Reconstruct the FrameTree
    for (unsigned i = 0; i < m_childFrames.size(); ++i)
        frame.tree()->appendChild(&m_childFrames[i]->view()->frame());

    // Open the child CachedFrames in their respective FrameLoaders.
    for (unsigned i = 0; i < m_childFrames.size(); ++i)
        m_childFrames[i]->open();

    // FIXME: update Page Visibility state here.
    // https://bugs.webkit.org/show_bug.cgi?id=116770

    m_document->enqueuePageshowEvent(PageshowEventPersisted);
    
    HistoryItem* historyItem = frame.loader().history()->currentItem();
    m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue());
    
#if ENABLE(TOUCH_EVENTS)
    if (m_document->hasTouchEventHandlers())
        m_document->page()->chrome().client().needTouchEvents(true);
#endif

    m_document->documentDidResumeFromPageCache();
}
// BackForwardList.get()
JNIEXPORT jobject JNICALL Java_com_sun_webkit_BackForwardList_bflGet(JNIEnv* env, jclass z, jlong jpage, jint index)
{
    BackForwardList* bfl = getBfl(jpage);
    HistoryItem* item = itemAtIndex(bfl, index);
    if (!item)
        return 0;
    JLObject host(item->hostObject());
    if (!host) {
        host = createEntry(item, jpage);
    }
    return host.releaseLocal();
}
void HistoryController::replaceState(PassRefPtr<SerializedScriptValue> stateObject, const String& title, const String& urlString)
{
    Page* page = m_frame->page();
    ASSERT(page);
    HistoryItem* current = page->backForwardList()->currentItem();
    ASSERT(current);

    if (!urlString.isEmpty())
        current->setURLString(urlString);
    current->setTitle(title);
    current->setStateObject(stateObject);
}
Example #13
0
void History::addEntry(const HistoryItem &item, int oldest)
{
    std::lock_guard<std::mutex> lock(historyItemsMutex_);
    if (item.hasPeerNumber() and item.youngerThan(oldest)) {
        items_.push_back(item);
        auto im = item.toMap();
        string name(im["display_name"]);
        string account(im["accountid"]);
        string number(im["peer_number"]);
        if (nameCache_[account][number].empty() and not name.empty() and not number.empty())
            nameCache_[account][number] = name;
    }
}
bool BackForwardList::clearAllPageCaches()
{
    bool didRemoveAtLeastOneItem = false;
    unsigned length = m_entries.size();
    for (unsigned i = 0; i < length; ++i) {
        HistoryItem* item = m_entries[i].get();
        if (item->isInPageCache()) {
            didRemoveAtLeastOneItem = true;
            pageCache()->remove(item);
        }
    }
    return didRemoveAtLeastOneItem;
}
void FrameLoaderClientAndroid::restoreViewState() {
    WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
    HistoryItem* item = m_frame->loader()->history()->currentItem();
    AndroidWebHistoryBridge* bridge = item->bridge();
    // restore the scale (only) for the top frame
    if (!m_frame->tree()->parent()) {
        int scale = bridge->scale();
        webViewCore->restoreScale(scale);
        int screenWidthScale = bridge->screenWidthScale();
        if (screenWidthScale != scale)
            webViewCore->restoreScreenWidthScale(screenWidthScale);
    }
}
Example #16
0
// We do same-document navigation if going to a different item and if either of the following is true:
// - The other item corresponds to the same document (for history entries created via pushState or fragment changes).
// - The other item corresponds to the same set of documents, including frames (for history entries created via regular navigation)
bool HistoryItem::shouldDoSameDocumentNavigationTo(HistoryItem& otherItem) const
{
    if (this == &otherItem)
        return false;

    if (stateObject() || otherItem.stateObject())
        return documentSequenceNumber() == otherItem.documentSequenceNumber();
    
    if ((url().hasFragmentIdentifier() || otherItem.url().hasFragmentIdentifier()) && equalIgnoringFragmentIdentifier(url(), otherItem.url()))
        return documentSequenceNumber() == otherItem.documentSequenceNumber();
    
    return hasSameDocumentTree(otherItem);
}
Example #17
0
void HistoryController::createNewBackForwardItem(LocalFrame* targetFrame, HistoryItem* item, bool clipAtTarget)
{
    RefPtr<HistoryItem> newItem = item;
    if (!m_currentEntry) {
        m_currentEntry = HistoryEntry::create(newItem.get(), targetFrame->frameID());
    } else {
        HistoryItem* oldItem = m_currentEntry->itemForFrame(targetFrame);
        if (!clipAtTarget && oldItem)
            newItem->setDocumentSequenceNumber(oldItem->documentSequenceNumber());
        m_previousEntry = m_currentEntry.release();
        m_currentEntry = m_previousEntry->cloneAndReplace(newItem.get(), clipAtTarget, targetFrame, m_page);
    }
}
QMap<QString, QWebHistoryItem> DumpRenderTreeSupportQt::getChildHistoryItems(const QWebHistoryItem& historyItem)
{
    QWebHistoryItem it = historyItem;
    HistoryItem* item = QWebHistoryItemPrivate::core(&it);
    const WebCore::HistoryItemVector& children = item->children();

    unsigned size = children.size();
    QMap<QString, QWebHistoryItem> kids;
    for (unsigned i = 0; i < size; ++i) {
        QWebHistoryItem kid(new QWebHistoryItemPrivate(children[i].get()));
        kids.insert(DumpRenderTreeSupportQt::historyItemTarget(kid), kid);
    }
    return kids;
}
Example #19
0
void Internals::setFormControlStateOfPreviousHistoryItem(PassRefPtr<DOMStringList> state, ExceptionCode& ec)
{
    HistoryItem* mainItem = frame()->loader()->history()->previousItem();
    if (!state || !mainItem) {
        ec = INVALID_ACCESS_ERR;
        return;
    }
    String uniqueName = frame()->tree()->uniqueName();
    if (mainItem->target() == uniqueName)
        mainItem->setDocumentState(*state.get());
    else if (HistoryItem* subItem = mainItem->childItemWithTarget(uniqueName))
        subItem->setDocumentState(*state.get());
    else
        ec = INVALID_ACCESS_ERR;
}
Example #20
0
// Does a non-recursive check that this item and its immediate children have the
// same frames as the other item.
bool HistoryItem::hasSameFrames(HistoryItem& otherItem) const
{
    if (target() != otherItem.target())
        return false;
        
    if (children().size() != otherItem.children().size())
        return false;

    for (size_t i = 0; i < children().size(); i++) {
        if (!otherItem.childItemWithTarget(children()[i]->target()))
            return false;
    }

    return true;
}
Example #21
0
void StackSelection::setFunction(TraceFunction* f)
{
  if (_function == f) return;
  _function = f;

  if (!_data || !_function) return;

  //qDebug() << "StackSelection::setFunction " << f->name();

  HistoryItem* item = _browser->current();
  if (!item || item->function() != f) {
    _browser->select(f);
    rebuildStackList();
  }
}
Example #22
0
QModelIndex HistoryModel::parent(const QModelIndex &index) const
{
    if (!index.isValid()) {
        return QModelIndex();
    }

    HistoryItem* childItem = itemFromIndex(index);
    HistoryItem* parentItem = childItem->parent();

    if (!parentItem || parentItem == m_rootItem) {
        return QModelIndex();
    }

    return createIndex(parentItem->row(), 0, parentItem);
}
// entry.getChildren()
JNIEXPORT jobjectArray JNICALL Java_com_sun_webkit_BackForwardList_bflItemGetChildren(JNIEnv* env, jclass z, jlong jitem, jlong jpage)
{
    HistoryItem* item = getItem(jitem);
    if (!item->hasChildren()) {
        return NULL;
    }
    jobjectArray children = env->NewObjectArray(item->children().size(), getJEntryClass(), NULL);
    int i = 0;
    for (HistoryItemVector::const_iterator it = item->children().begin();
	 it != item->children().end();
	 ++it)
    {
        env->SetObjectArrayElement(children, i++, (jobject)createEntry(&**it, jpage));
    }
    return children;
}
Example #24
0
void PageCache::addIfCacheable(HistoryItem& item, Page* page)
{
    if (item.isInPageCache())
        return;

    if (!page || !canCache(*page))
        return;

    // Make sure all the documents know they are being added to the PageCache.
    setInPageCache(*page, true);

    // Focus the main frame, defocusing a focused subframe (if we have one). We do this here,
    // before the page enters the page cache, while we still can dispatch DOM blur/focus events.
    if (page->focusController().focusedFrame())
        page->focusController().setFocusedFrame(&page->mainFrame());

    // Fire the pagehide event in all frames.
    firePageHideEventRecursively(page->mainFrame());

    // Check that the page is still page-cacheable after firing the pagehide event. The JS event handlers
    // could have altered the page in a way that could prevent caching.
    if (!canCache(*page)) {
        setInPageCache(*page, false);
        return;
    }

    // Make sure we no longer fire any JS events past this point.
    NoEventDispatchAssertion assertNoEventDispatch;

    item.m_cachedPage = std::make_unique<CachedPage>(*page);
    item.m_pruningReason = PruningReason::None;
    m_items.add(&item);
    
    prune(PruningReason::ReachedMaxSize);
}
Example #25
0
bool HistoryModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    HistoryItem* item = itemFromIndex(index);

    if (index.row() < 0 || !item || item->isTopLevel()) {
        return false;
    }

    if (role == IconRole) {
        item->setIcon(value.value<QIcon>());
        emit dataChanged(index, index);
        return true;
    }

    return false;
}
Example #26
0
// Does a recursive check that this item and its descendants have the same
// document sequence numbers as the other item.
bool HistoryItem::hasSameDocumentTree(HistoryItem* otherItem) const
{
    if (documentSequenceNumber() != otherItem->documentSequenceNumber())
        return false;
        
    if (children().size() != otherItem->children().size())
        return false;

    for (size_t i = 0; i < children().size(); i++) {
        HistoryItem* child = children()[i].get();
        HistoryItem* otherChild = otherItem->childItemWithDocumentSequenceNumber(child->documentSequenceNumber());
        if (!otherChild || !child->hasSameDocumentTree(otherChild))
            return false;
    }

    return true;
}
Example #27
0
void AnimatedGif::stop(bool onItemRemoved) {
	if (isNull()) return;

	delete reader;
	reader = 0;
	HistoryItem *row = msg;
	msg = 0;
	frames.clear();
	delays.clear();
	w = h = frame = framesCount = duration = 0;

	anim::stop(this);
	if (row && !onItemRemoved) {
		row->initDimensions();
		if (App::main()) App::main()->itemResized(row, true);
	}
}
Example #28
0
void CachedFrameBase::restore()
{
    ASSERT(m_document->view() == m_view);

    if (m_isMainFrame)
        m_view->setParentVisible(true);

    Frame* frame = m_view->frame();
    m_cachedFrameScriptData->restore(frame);

#if ENABLE(SVG)
    if (m_document->svgExtensions())
        m_document->accessSVGExtensions()->unpauseAnimations();
#endif

    frame->animation()->resumeAnimationsForDocument(m_document.get());
    frame->eventHandler()->setMousePressNode(m_mousePressNode.get());
    m_document->resumeActiveDOMObjects();
    m_document->resumeScriptedAnimationControllerCallbacks();

    // It is necessary to update any platform script objects after restoring the
    // cached page.
    frame->script()->updatePlatformScriptObjects();

    frame->loader()->client()->didRestoreFromPageCache();

    // Reconstruct the FrameTree
    for (unsigned i = 0; i < m_childFrames.size(); ++i)
        frame->tree()->appendChild(m_childFrames[i]->view()->frame());

    // Open the child CachedFrames in their respective FrameLoaders.
    for (unsigned i = 0; i < m_childFrames.size(); ++i)
        m_childFrames[i]->open();

    m_document->enqueuePageshowEvent(PageshowEventPersisted);
    
    HistoryItem* historyItem = frame->loader()->history()->currentItem();
    m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue());
    
#if ENABLE(TOUCH_EVENTS)
    if (m_document->hasListenerType(Document::TOUCH_LISTENER))
        m_document->page()->chrome()->client()->needTouchEvents(true);
#endif

    m_document->documentDidBecomeActive();
}
Example #29
0
// Does a recursive check that this item and its descendants have the same
// document sequence numbers as the other item.
bool HistoryItem::hasSameDocumentTree(HistoryItem& otherItem) const
{
    if (documentSequenceNumber() != otherItem.documentSequenceNumber())
        return false;
        
    if (children().size() != otherItem.children().size())
        return false;

    for (size_t i = 0; i < children().size(); i++) {
        auto& child = children()[i].get();
        auto* otherChild = otherItem.childItemWithDocumentSequenceNumber(child.documentSequenceNumber());
        if (!otherChild || !child.hasSameDocumentTree(*otherChild))
            return false;
    }

    return true;
}
Example #30
0
PassRefPtr<DOMStringList> Internals::formControlStateOfPreviousHistoryItem(ExceptionCode& ec)
{
    HistoryItem* mainItem = frame()->loader()->history()->previousItem();
    if (!mainItem) {
        ec = INVALID_ACCESS_ERR;
        return 0;
    }
    String uniqueName = frame()->tree()->uniqueName();
    if (mainItem->target() != uniqueName && !mainItem->childItemWithTarget(uniqueName)) {
        ec = INVALID_ACCESS_ERR;
        return 0;
    }
    const Vector<String>& state = mainItem->target() == uniqueName ? mainItem->documentState() : mainItem->childItemWithTarget(uniqueName)->documentState();
    RefPtr<DOMStringList> stringList = DOMStringList::create();
    for (unsigned i = 0; i < state.size(); ++i)
        stringList->append(state[i]);
    return stringList.release();
}