Beispiel #1
0
bool MediaPlayer::supportsType(const String& type)
{
    HashSet<String> types;
    getSupportedTypes(types);
    return MIMETypeRegistry::isSupportedMediaMIMEType(type) && types.contains(type);
}
Beispiel #2
0
static void testSetCopy()
{
	// Add 1000..1999 to a HashSet.
	HashSet<Uptr> a;
	for(Uptr i = 0;i < 1000;++i)
	{
		a.add(i + 1000);
	}

	// Copy the set to a new HashSet.
	HashSet<Uptr> b {a};

	// Test that both the new and old HashSet contain the expected numbers.
	for(Uptr i = 0;i < 1000;++i)
	{
		errorUnless(!a.contains(i));
		errorUnless(a.contains(i + 1000));
		errorUnless(!a.contains(i + 2000));
		
		errorUnless(!b.contains(i));
		errorUnless(b.contains(i + 1000));
		errorUnless(!b.contains(i + 2000));
	}
	
	// Test copying a set from itself.
	b = b;
	
	// Test that the set wasn't changed by the copy-to-self.
	for(Uptr i = 0;i < 1000;++i)
	{
		errorUnless(!b.contains(i));
		errorUnless(b.contains(i + 1000));
		errorUnless(!b.contains(i + 2000));
	}

	// Test removing an element from the set.
	b.remove(1000);
	errorUnless(a.contains(1000));
	errorUnless(!b.contains(1000));
}
Beispiel #3
0
// Compiles a list of subtargets of all the relevant target nodes.
void compileSubtargetList(const NodeList& intersectedNodes, SubtargetGeometryList& subtargets, NodeFilter nodeFilter, AppendSubtargetsForNode appendSubtargetsForNode)
{
    // Find candidates responding to tap gesture events in O(n) time.
    HashMap<Node*, Node*> responderMap;
    HashSet<Node*> ancestorsToRespondersSet;
    Vector<Node*> candidates;
    HashSet<Node*> editableAncestors;

    // A node matching the NodeFilter is called a responder. Candidate nodes must either be a
    // responder or have an ancestor that is a responder.
    // This iteration tests all ancestors at most once by caching earlier results.
    unsigned length = intersectedNodes.length();
    for (unsigned i = 0; i < length; ++i) {
        Node* const node = intersectedNodes.item(i);
        Vector<Node*> visitedNodes;
        Node* respondingNode = 0;
        for (Node* visitedNode = node; visitedNode; visitedNode = visitedNode->parentOrShadowHostNode()) {
            // Check if we already have a result for a common ancestor from another candidate.
            respondingNode = responderMap.get(visitedNode);
            if (respondingNode)
                break;
            visitedNodes.append(visitedNode);
            // Check if the node filter applies, which would mean we have found a responding node.
            if (nodeFilter(visitedNode)) {
                respondingNode = visitedNode;
                // Continue the iteration to collect the ancestors of the responder, which we will need later.
                for (visitedNode = visitedNode->parentOrShadowHostNode(); visitedNode; visitedNode = visitedNode->parentOrShadowHostNode()) {
                    HashSet<Node*>::AddResult addResult = ancestorsToRespondersSet.add(visitedNode);
                    if (!addResult.isNewEntry)
                        break;
                }
                break;
            }
        }
        // Insert the detected responder for all the visited nodes.
        for (unsigned j = 0; j < visitedNodes.size(); j++)
            responderMap.add(visitedNodes[j], respondingNode);

        if (respondingNode)
            candidates.append(node);
    }

    // We compile the list of component absolute quads instead of using the bounding rect
    // to be able to perform better hit-testing on inline links on line-breaks.
    length = candidates.size();
    for (unsigned i = 0; i < length; i++) {
        Node* candidate = candidates[i];
        // Skip nodes who's responders are ancestors of other responders. This gives preference to
        // the inner-most event-handlers. So that a link is always preferred even when contained
        // in an element that monitors all click-events.
        Node* respondingNode = responderMap.get(candidate);
        ASSERT(respondingNode);
        if (ancestorsToRespondersSet.contains(respondingNode))
            continue;
        // Consolidate bounds for editable content.
        if (editableAncestors.contains(candidate))
            continue;
        if (candidate->isContentEditable()) {
            Node* replacement = candidate;
            Node* parent = candidate->parentOrShadowHostNode();
            while (parent && parent->isContentEditable()) {
                replacement = parent;
                if (editableAncestors.contains(replacement)) {
                    replacement = 0;
                    break;
                }
                editableAncestors.add(replacement);
                parent = parent->parentOrShadowHostNode();
            }
            candidate = replacement;
        }
        if (candidate)
            appendSubtargetsForNode(candidate, subtargets);
    }
}
PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame* frame, const Vector<Node*>& nodes)
{
    ASSERT(frame);
    
    const ResourceResponse& response = frame->loader()->documentLoader()->response();
    KURL responseURL = response.url();
    
    // it's possible to have a response without a URL here
    // <rdar://problem/5454935>
    if (responseURL.isNull())
        responseURL = KURL(ParsedURLString, "");
        
    PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->uniqueName());

    Vector<PassRefPtr<LegacyWebArchive> > subframeArchives;
    Vector<PassRefPtr<ArchiveResource> > subresources;
    HashSet<KURL> uniqueSubresources;

    size_t nodesSize = nodes.size();    
    for (size_t i = 0; i < nodesSize; ++i) {
        Node* node = nodes[i];
        Frame* childFrame;
        if ((node->hasTagName(HTMLNames::frameTag) || node->hasTagName(HTMLNames::iframeTag) || node->hasTagName(HTMLNames::objectTag)) &&
             (childFrame = static_cast<HTMLFrameOwnerElement*>(node)->contentFrame())) {
            RefPtr<LegacyWebArchive> subframeArchive = create(childFrame->document());
            
            if (subframeArchive)
                subframeArchives.append(subframeArchive);
            else
                LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->uniqueName().string().utf8().data());
        } else {
            ListHashSet<KURL> subresourceURLs;
            node->getSubresourceURLs(subresourceURLs);
            
            DocumentLoader* documentLoader = frame->loader()->documentLoader();
            ListHashSet<KURL>::iterator iterEnd = subresourceURLs.end();
            for (ListHashSet<KURL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) {
                const KURL& subresourceURL = *iter;
                if (uniqueSubresources.contains(subresourceURL))
                    continue;

                uniqueSubresources.add(subresourceURL);

                RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL);
                if (resource) {
                    subresources.append(resource.release());
                    continue;
                }

                CachedResource* cachedResource = memoryCache()->resourceForURL(subresourceURL);
                if (cachedResource) {
                    resource = ArchiveResource::create(cachedResource->data(), subresourceURL, cachedResource->response());
                    if (resource) {
                        subresources.append(resource.release());
                        continue;
                    }
                }

                // FIXME: should do something better than spew to console here
                LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data());
            }
        }
    }

    // Add favicon if one exists for this page, if we are archiving the entire page.
    if (nodesSize && nodes[0]->isDocumentNode() && iconDatabase().isEnabled()) {
        const String& iconURL = iconDatabase().synchronousIconURLForPageURL(responseURL);
        if (!iconURL.isEmpty() && iconDatabase().synchronousIconDataKnownForIconURL(iconURL)) {
            if (Image* iconImage = iconDatabase().synchronousIconForPageURL(responseURL, IntSize(16, 16))) {
                if (RefPtr<ArchiveResource> resource = ArchiveResource::create(iconImage->data(), KURL(ParsedURLString, iconURL), "image/x-icon", "", ""))
                    subresources.append(resource.release());
            }
        }
    }

    return create(mainResource, subresources, subframeArchives);
}
Beispiel #5
0
void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
{
  String url;
  String serviceType;
  Vector<String> paramNames;
  Vector<String> paramValues;
  Frame* frame = m_view->frame();
  
  if (element()->hasTagName(objectTag)) {

      HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element());

      o->setNeedWidgetUpdate(false);
      if (!o->isFinishedParsingChildren())
        return;
      // Check for a child EMBED tag.
      HTMLEmbedElement* embed = 0;
      for (Node* child = o->firstChild(); child;) {
          if (child->hasTagName(embedTag)) {
              embed = static_cast<HTMLEmbedElement*>(child);
              break;
          } else if (child->hasTagName(objectTag))
              child = child->nextSibling();         // Don't descend into nested OBJECT tags
          else
              child = child->traverseNextNode(o);   // Otherwise descend (EMBEDs may be inside COMMENT tags)
      }
      
      // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
      HTMLElement *embedOrObject;
      if (embed) {
          embedOrObject = (HTMLElement *)embed;
          url = embed->url();
          serviceType = embed->serviceType();
      } else
          embedOrObject = (HTMLElement *)o;
      
      // If there was no URL or type defined in EMBED, try the OBJECT tag.
      if (url.isEmpty())
          url = o->m_url;
      if (serviceType.isEmpty())
          serviceType = o->m_serviceType;
      
      HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
      
      // Scan the PARAM children.
      // Get the URL and type from the params if we don't already have them.
      // Get the attributes from the params if there is no EMBED tag.
      Node *child = o->firstChild();
      while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
          if (child->hasTagName(paramTag)) {
              HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
              String name = p->name().lower();
              if (url.isEmpty() && (name == "src" || name == "movie" || name == "code" || name == "url"))
                  url = p->value();
              if (serviceType.isEmpty() && name == "type") {
                  serviceType = p->value();
                  int pos = serviceType.find(";");
                  if (pos != -1)
                      serviceType = serviceType.left(pos);
              }
              if (!embed && !name.isEmpty()) {
                  uniqueParamNames.add(p->name().impl());
                  paramNames.append(p->name());
                  paramValues.append(p->value());
              }
          }
          child = child->nextSibling();
      }
      
      // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
      // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
      // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
      // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
      // else our Java plugin will misinterpret it. [4004531]
      String codebase;
      if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
          codebase = "codebase";
          uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
      }
      
      // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
      NamedAttrMap* attributes = embedOrObject->attributes();
      if (attributes) {
          for (unsigned i = 0; i < attributes->length(); ++i) {
              Attribute* it = attributes->attributeItem(i);
              const AtomicString& name = it->name().localName();
              if (embed || !uniqueParamNames.contains(name.impl())) {
                  paramNames.append(name.string());
                  paramValues.append(it->value().string());
              }
          }
      }
      
      // If we still don't have a type, try to map from a specific CLASSID to a type.
      if (serviceType.isEmpty() && !o->m_classId.isEmpty())
          mapClassIdToServiceType(o->m_classId, serviceType);
      
      if (!isURLAllowed(document(), url))
          return;

      // Find out if we support fallback content.
      m_hasFallbackContent = false;
      for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) {
          if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param>
              (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace()))
              m_hasFallbackContent = true;
      }
      
      if (onlyCreateNonNetscapePlugins) {
          KURL completedURL;
          if (!url.isEmpty())
              completedURL = frame->loader()->completeURL(url);
        
          if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
              return;
      }
      
      bool success = frame->loader()->requestObject(this, url, AtomicString(o->name()), serviceType, paramNames, paramValues);
      if (!success && m_hasFallbackContent)
          o->renderFallbackContent();
  } else if (element()->hasTagName(embedTag)) {
      HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element());
      o->setNeedWidgetUpdate(false);
      url = o->url();
      serviceType = o->serviceType();

      if (url.isEmpty() && serviceType.isEmpty())
          return;
      if (!isURLAllowed(document(), url))
          return;
      
      // add all attributes set on the embed object
      NamedAttrMap* a = o->attributes();
      if (a) {
          for (unsigned i = 0; i < a->length(); ++i) {
              Attribute* it = a->attributeItem(i);
              paramNames.append(it->name().localName().string());
              paramValues.append(it->value().string());
          }
      }
      
      if (onlyCreateNonNetscapePlugins) {
          KURL completedURL;
          if (!url.isEmpty())
              completedURL = frame->loader()->completeURL(url);
          
          if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
              return;
          
      }
      
      frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues);
  }
}
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
{
    SMILTime earliersFireTime = SMILTime::unresolved();

    Vector<SVGSMILElement*> toAnimate;
    copyToVector(m_scheduledAnimations, toAnimate);

    // Sort according to priority. Elements with later begin time have higher priority.
    // In case of a tie, document order decides. 
    // FIXME: This should also consider timing relationships between the elements. Dependents
    // have higher priority.
    sortByPriority(toAnimate, elapsed);
    
    // Calculate animation contributions.
    typedef pair<SVGElement*, QualifiedName> ElementAttributePair;
    typedef HashMap<ElementAttributePair, RefPtr<SVGSMILElement> > ResultElementMap;
    ResultElementMap resultsElements;
    HashSet<SVGSMILElement*> contributingElements;
    for (unsigned n = 0; n < toAnimate.size(); ++n) {
        SVGSMILElement* animation = toAnimate[n];
        ASSERT(animation->timeContainer() == this);

        SVGElement* targetElement = animation->targetElement();
        if (!targetElement)
            continue;
        
        QualifiedName attributeName = animation->attributeName();
        if (attributeName == anyQName()) {
            if (animation->hasTagName(SVGNames::animateMotionTag))
                attributeName = SVGNames::animateMotionTag;
            else
                continue;
        }
        
        // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair.
        ElementAttributePair key(targetElement, attributeName); 
        SVGSMILElement* resultElement = resultsElements.get(key).get();
        bool accumulatedResultElement = false;
        if (!resultElement) {
            if (!animation->hasValidAttributeType())
                continue;
            resultElement = animation;
            resultsElements.add(key, resultElement);
            accumulatedResultElement = true;
        }

        // This will calculate the contribution from the animation and add it to the resultsElement.
        if (animation->progress(elapsed, resultElement, seekToTime))
            contributingElements.add(resultElement);
        else if (accumulatedResultElement)
            resultsElements.remove(key);

        SMILTime nextFireTime = animation->nextProgressTime();
        if (nextFireTime.isFinite())
            earliersFireTime = min(nextFireTime, earliersFireTime);
    }
    
    Vector<SVGSMILElement*> animationsToApply;
    ResultElementMap::iterator end = resultsElements.end();
    for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it) {
        SVGSMILElement* animation = it->second.get();
        if (contributingElements.contains(animation))
            animationsToApply.append(animation);
    }

    unsigned animationsToApplySize = animationsToApply.size();
    if (!animationsToApplySize) {
        startTimer(earliersFireTime, animationFrameDelay);
        return;
    }

    // Sort <animateTranform> to be the last one to be applied. <animate> may change transform attribute as
    // well (directly or indirectly by modifying <use> x/y) and this way transforms combine properly.
    sortByApplyOrder(animationsToApply);

    // Apply results to target elements.
    for (unsigned i = 0; i < animationsToApplySize; ++i)
        animationsToApply[i]->applyResultsToTarget();

    startTimer(earliersFireTime, animationFrameDelay);
    Document::updateStyleForAllDocuments();
}
void HTMLFormCollection::updateNameCache() const
{
    if (info()->hasNameCache)
        return;

    HashSet<AtomicStringImpl*> foundInputElements;

    HTMLFormElement* f = static_cast<HTMLFormElement*>(base());

    for (unsigned i = 0; i < f->formElements.size(); ++i) {
        HTMLFormControlElement* e = f->formElements[i];
        if (e->isEnumeratable()) {
            const AtomicString& idAttrVal = e->getAttribute(e->idAttributeName());
            const AtomicString& nameAttrVal = e->getAttribute(nameAttr);
            if (!idAttrVal.isEmpty()) {
                // add to id cache
                Vector<Element*>* idVector = info()->idCache.get(idAttrVal.impl());
                if (!idVector) {
                    idVector = new Vector<Element*>;
                    info()->idCache.add(idAttrVal.impl(), idVector);
                }
                idVector->append(e);
                foundInputElements.add(idAttrVal.impl());
            }
            if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal) {
                // add to name cache
                Vector<Element*>* nameVector = info()->nameCache.get(nameAttrVal.impl());
                if (!nameVector) {
                    nameVector = new Vector<Element*>;
                    info()->nameCache.add(nameAttrVal.impl(), nameVector);
                }
                nameVector->append(e);
                foundInputElements.add(nameAttrVal.impl());
            }
        }
    }

    for (unsigned i = 0; i < f->imgElements.size(); ++i) {
        HTMLImageElement* e = f->imgElements[i];
        const AtomicString& idAttrVal = e->getAttribute(e->idAttributeName());
        const AtomicString& nameAttrVal = e->getAttribute(nameAttr);
        if (!idAttrVal.isEmpty() && !foundInputElements.contains(idAttrVal.impl())) {
            // add to id cache
            Vector<Element*>* idVector = info()->idCache.get(idAttrVal.impl());
            if (!idVector) {
                idVector = new Vector<Element*>;
                info()->idCache.add(idAttrVal.impl(), idVector);
            }
            idVector->append(e);
        }
        if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && !foundInputElements.contains(nameAttrVal.impl())) {
            // add to name cache
            Vector<Element*>* nameVector = info()->nameCache.get(nameAttrVal.impl());
            if (!nameVector) {
                nameVector = new Vector<Element*>;
                info()->nameCache.add(nameAttrVal.impl(), nameVector);
            }
            nameVector->append(e);
        }
    }

    info()->hasNameCache = true;
}
Beispiel #8
0
PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame* frame, Vector<Node*>& nodes)
{
    ASSERT(frame);
    
    const ResourceResponse& response = frame->loader()->documentLoader()->response();
    KURL responseURL = response.url();
    
    // it's possible to have a response without a URL here
    // <rdar://problem/5454935>
    if (responseURL.isNull())
        responseURL = KURL("");
        
    PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->name());

    Vector<PassRefPtr<LegacyWebArchive> > subframeArchives;
    Vector<PassRefPtr<ArchiveResource> > subresources;
    HashSet<KURL> uniqueSubresources;
    
    Vector<Node*>::iterator it = nodes.begin();
    Vector<Node*>::iterator end = nodes.end();
    
    for (; it != end; ++it) {
        Frame* childFrame;
        if (((*it)->hasTagName(HTMLNames::frameTag) || (*it)->hasTagName(HTMLNames::iframeTag) || (*it)->hasTagName(HTMLNames::objectTag)) &&
             (childFrame = static_cast<HTMLFrameOwnerElement*>(*it)->contentFrame())) {
            RefPtr<LegacyWebArchive> subframeArchive;
            if (Document* document = childFrame->document())
                subframeArchive = LegacyWebArchive::create(document);
            else
                subframeArchive = create(childFrame);
            
            if (subframeArchive)
                subframeArchives.append(subframeArchive);
            else
                LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->name().string().utf8().data());
        } else {
            ListHashSet<KURL> subresourceURLs;
            (*it)->getSubresourceURLs(subresourceURLs);
            
            DocumentLoader* documentLoader = frame->loader()->documentLoader();
            ListHashSet<KURL>::iterator iterEnd = subresourceURLs.end();
            for (ListHashSet<KURL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) {
                const KURL& subresourceURL = *iter;
                if (uniqueSubresources.contains(subresourceURL))
                    continue;

                uniqueSubresources.add(subresourceURL);

                RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL);
                if (resource) {
                    subresources.append(resource.release());
                    continue;
                }

                CachedResource *cachedResource = cache()->resourceForURL(subresourceURL);
                if (cachedResource) {
                    resource = ArchiveResource::create(cachedResource->data(), subresourceURL, cachedResource->response());
                    if (resource) {
                        subresources.append(resource.release());
                        continue;
                    }
                }

                // FIXME: should do something better than spew to console here
                LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data());
            }
        }
    }
    
    return create(mainResource, subresources, subframeArchives);
}
bool DOMPatchSupport::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionState& exceptionState)
{
    pair<ResultMap, ResultMap> resultMaps = diff(oldList, newList);
    ResultMap& oldMap = resultMaps.first;
    ResultMap& newMap = resultMaps.second;

    Digest* oldHead = 0;
    Digest* oldBody = 0;

    // 1. First strip everything except for the nodes that retain. Collect pending merges.
    HashMap<Digest*, Digest*> merges;
    HashSet<size_t, WTF::IntHash<size_t>, WTF::UnsignedWithZeroKeyHashTraits<size_t> > usedNewOrdinals;
    for (size_t i = 0; i < oldList.size(); ++i) {
        if (oldMap[i].first) {
            if (usedNewOrdinals.add(oldMap[i].second).isNewEntry)
                continue;
            oldMap[i].first = 0;
            oldMap[i].second = 0;
        }

        // Always match <head> and <body> tags with each other - we can't remove them from the DOM
        // upon patching.
        if (isHTMLHeadElement(*oldList[i]->m_node)) {
            oldHead = oldList[i].get();
            continue;
        }
        if (isHTMLBodyElement(*oldList[i]->m_node)) {
            oldBody = oldList[i].get();
            continue;
        }

        // Check if this change is between stable nodes. If it is, consider it as "modified".
        if (!m_unusedNodesMap.contains(oldList[i]->m_sha1) && (!i || oldMap[i - 1].first) && (i == oldMap.size() - 1 || oldMap[i + 1].first)) {
            size_t anchorCandidate = i ? oldMap[i - 1].second + 1 : 0;
            size_t anchorAfter = (i == oldMap.size() - 1) ? anchorCandidate + 1 : oldMap[i + 1].second;
            if (anchorAfter - anchorCandidate == 1 && anchorCandidate < newList.size())
                merges.set(newList[anchorCandidate].get(), oldList[i].get());
            else {
                if (!removeChildAndMoveToNew(oldList[i].get(), exceptionState))
                    return false;
            }
        } else {
            if (!removeChildAndMoveToNew(oldList[i].get(), exceptionState))
                return false;
        }
    }

    // Mark retained nodes as used, do not reuse node more than once.
    HashSet<size_t, WTF::IntHash<size_t>, WTF::UnsignedWithZeroKeyHashTraits<size_t> >  usedOldOrdinals;
    for (size_t i = 0; i < newList.size(); ++i) {
        if (!newMap[i].first)
            continue;
        size_t oldOrdinal = newMap[i].second;
        if (usedOldOrdinals.contains(oldOrdinal)) {
            // Do not map node more than once
            newMap[i].first = 0;
            newMap[i].second = 0;
            continue;
        }
        usedOldOrdinals.add(oldOrdinal);
        markNodeAsUsed(newMap[i].first);
    }

    // Mark <head> and <body> nodes for merge.
    if (oldHead || oldBody) {
        for (size_t i = 0; i < newList.size(); ++i) {
            if (oldHead && isHTMLHeadElement(*newList[i]->m_node))
                merges.set(newList[i].get(), oldHead);
            if (oldBody && isHTMLBodyElement(*newList[i]->m_node))
                merges.set(newList[i].get(), oldBody);
        }
    }

    // 2. Patch nodes marked for merge.
    for (HashMap<Digest*, Digest*>::iterator it = merges.begin(); it != merges.end(); ++it) {
        if (!innerPatchNode(it->value, it->key, exceptionState))
            return false;
    }

    // 3. Insert missing nodes.
    for (size_t i = 0; i < newMap.size(); ++i) {
        if (newMap[i].first || merges.contains(newList[i].get()))
            continue;
        if (!insertBeforeAndMarkAsUsed(parentNode, newList[i].get(), parentNode->traverseToChildAt(i), exceptionState))
            return false;
    }

    // 4. Then put all nodes that retained into their slots (sort by new index).
    for (size_t i = 0; i < oldMap.size(); ++i) {
        if (!oldMap[i].first)
            continue;
        RefPtrWillBeRawPtr<Node> node = oldMap[i].first->m_node;
        Node* anchorNode = parentNode->traverseToChildAt(oldMap[i].second);
        if (node == anchorNode)
            continue;
        if (isHTMLBodyElement(*node) || isHTMLHeadElement(*node))
            continue; // Never move head or body, move the rest of the nodes around them.

        if (!m_domEditor->insertBefore(parentNode, node.release(), anchorNode, exceptionState))
            return false;
    }
    return true;
}
Beispiel #10
0
PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame* frame, const Vector<Node*>& nodes, FrameFilter* frameFilter)
{
    ASSERT(frame);
    
    const ResourceResponse& response = frame->loader().documentLoader()->response();
    URL responseURL = response.url();
    
    // it's possible to have a response without a URL here
    // <rdar://problem/5454935>
    if (responseURL.isNull())
        responseURL = URL(ParsedURLString, emptyString());
        
    RefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree().uniqueName());

    Vector<PassRefPtr<LegacyWebArchive>> subframeArchives;
    Vector<PassRefPtr<ArchiveResource>> subresources;
    HashSet<URL> uniqueSubresources;

    size_t nodesSize = nodes.size();    
    for (size_t i = 0; i < nodesSize; ++i) {
        Node& node = *nodes[i];
        Frame* childFrame;
        if ((isHTMLFrameElement(node) || isHTMLIFrameElement(node) || isHTMLObjectElement(node))
            && (childFrame = toHTMLFrameOwnerElement(node).contentFrame())) {
            if (frameFilter && !frameFilter->shouldIncludeSubframe(childFrame))
                continue;
                
            RefPtr<LegacyWebArchive> subframeArchive = create(childFrame->document(), frameFilter);
            
            if (subframeArchive)
                subframeArchives.append(subframeArchive);
            else
                LOG_ERROR("Unabled to archive subframe %s", childFrame->tree().uniqueName().string().utf8().data());
        } else {
            ListHashSet<URL> subresourceURLs;
            node.getSubresourceURLs(subresourceURLs);
            
            DocumentLoader* documentLoader = frame->loader().documentLoader();
            ListHashSet<URL>::iterator iterEnd = subresourceURLs.end();
            for (ListHashSet<URL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) {
                const URL& subresourceURL = *iter;
                if (uniqueSubresources.contains(subresourceURL))
                    continue;

                uniqueSubresources.add(subresourceURL);

                RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL);
                if (resource) {
                    subresources.append(resource.release());
                    continue;
                }

                ResourceRequest request(subresourceURL);
#if ENABLE(CACHE_PARTITIONING)
                request.setCachePartition(frame->document()->topOrigin()->cachePartition());
#endif
                CachedResource* cachedResource = memoryCache()->resourceForRequest(request);
                if (cachedResource) {
                    ResourceBuffer* data = cachedResource->resourceBuffer();
                    resource = ArchiveResource::create(data ? data->sharedBuffer() : 0, subresourceURL, cachedResource->response());
                    if (resource) {
                        subresources.append(resource.release());
                        continue;
                    }
                }

                // FIXME: should do something better than spew to console here
                LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data());
            }
        }
    }

    // Add favicon if one exists for this page, if we are archiving the entire page.
    if (nodesSize && nodes[0]->isDocumentNode() && iconDatabase().isEnabled()) {
        const String& iconURL = iconDatabase().synchronousIconURLForPageURL(responseURL);
        if (!iconURL.isEmpty() && iconDatabase().synchronousIconDataKnownForIconURL(iconURL)) {
            if (Image* iconImage = iconDatabase().synchronousIconForPageURL(responseURL, IntSize(16, 16))) {
                if (RefPtr<ArchiveResource> resource = ArchiveResource::create(iconImage->data(), URL(ParsedURLString, iconURL), "image/x-icon", "", ""))
                    subresources.append(resource.release());
            }
        }
    }

    return create(mainResource.release(), subresources, subframeArchives);
}
Beispiel #11
0
    void validate()
    {
        // NB. This code is not written for performance, since it is not intended to run
        // in release builds.
        
        // Validate that all local variables at the head of the root block are dead.
        BasicBlock* root = m_graph.m_blocks[0].get();
        for (unsigned i = 0; i < root->variablesAtHead.numberOfLocals(); ++i)
            V_EQUAL((static_cast<VirtualRegister>(i), 0), static_cast<Node*>(0), root->variablesAtHead.local(i));
        
        // Validate ref counts and uses.
        HashMap<Node*, unsigned> myRefCounts;
        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
            if (!block || !block->isReachable)
                continue;
            for (size_t i = 0; i < block->numNodes(); ++i)
                myRefCounts.add(block->node(i), 0);
        }
        HashSet<Node*> acceptableNodes;
        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
            if (!block || !block->isReachable)
                continue;
            for (size_t i = 0; i < block->numNodes(); ++i) {
                Node* node = block->node(i);
                acceptableNodes.add(node);
                if (!node->shouldGenerate())
                    continue;
                for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
                    // Phi children in LoadStore form are invalid.
                    if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
                        continue;
                    
                    Edge edge = m_graph.child(node, j);
                    if (!edge)
                        continue;
                    
                    myRefCounts.find(edge.node())->value++;
                    
                    // Unless I'm a Flush, Phantom, GetLocal, or Phi, my children should hasResult().
                    switch (node->op()) {
                    case Flush:
                    case GetLocal:
                    case PhantomLocal:
                        VALIDATE((node, edge), edge->hasVariableAccessData());
                        VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
                        break;
                    case Phi:
                        VALIDATE((node, edge), edge->hasVariableAccessData());
                        if (m_graph.m_unificationState == LocallyUnified)
                            break;
                        VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
                        break;
                    case Phantom:
                        if (m_graph.m_form == LoadStore && !j)
                            break;
                    default:
                        VALIDATE((node, edge), edge->hasResult());
                        break;
                    }
                }
            }
        }
        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
            if (!block || !block->isReachable)
                continue;
            
            HashSet<Node*> phisInThisBlock;
            HashSet<Node*> nodesInThisBlock;
            
            for (size_t i = 0; i < block->numNodes(); ++i) {
                Node* node = block->node(i);
                nodesInThisBlock.add(node);
                if (block->isPhiIndex(i))
                    phisInThisBlock.add(node);
                if (m_graph.m_form == ThreadedCPS || !node->hasVariableAccessData())
                    V_EQUAL((node), myRefCounts.get(node), node->adjustedRefCount());
                else
                    VALIDATE((node), myRefCounts.get(node) ? node->adjustedRefCount() : true);
                for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
                    Edge edge = m_graph.child(node, j);
                    if (!edge)
                        continue;
                    VALIDATE((node, edge), acceptableNodes.contains(edge.node()));
                }
            }
            
            for (size_t i = 0; i < block->phis.size(); ++i) {
                Node* node = block->phis[i];
                ASSERT(phisInThisBlock.contains(node));
                VALIDATE((node), node->op() == Phi);
                VirtualRegister local = node->local();
                for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
                    // Phi children in LoadStore form are invalid.
                    if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
                        continue;
                    
                    Edge edge = m_graph.child(node, j);
                    if (!edge)
                        continue;
                    
                    VALIDATE(
                        (node, edge),
                        edge->op() == SetLocal
                        || edge->op() == SetArgument
                        || edge->op() == Flush
                        || edge->op() == Phi);
                    
                    if (phisInThisBlock.contains(edge.node()))
                        continue;
                    
                    if (nodesInThisBlock.contains(edge.node())) {
                        VALIDATE(
                            (node, edge),
                            edge->op() == SetLocal
                            || edge->op() == SetArgument
                            || edge->op() == Flush);
                        
                        continue;
                    }
                    
                    // There must exist a predecessor block that has this node index in
                    // its tail variables.
                    bool found = false;
                    for (unsigned k = 0; k < block->m_predecessors.size(); ++k) {
                        BasicBlock* prevBlock = m_graph.m_blocks[block->m_predecessors[k]].get();
                        VALIDATE((Block, block->m_predecessors[k]), prevBlock);
                        VALIDATE((Block, block->m_predecessors[k]), prevBlock->isReachable);
                        Node* prevNode = prevBlock->variablesAtTail.operand(local);
                        // If we have a Phi that is not referring to *this* block then all predecessors
                        // must have that local available.
                        VALIDATE((local, blockIndex, Block, block->m_predecessors[k]), prevNode);
                        switch (prevNode->op()) {
                        case GetLocal:
                        case Flush:
                        case PhantomLocal:
                            prevNode = prevNode->child1().node();
                            break;
                        default:
                            break;
                        }
                        if (node->shouldGenerate()) {
                            VALIDATE((local, block->m_predecessors[k], prevNode),
                                     prevNode->shouldGenerate());
                        }
                        VALIDATE(
                            (local, block->m_predecessors[k], prevNode),
                            prevNode->op() == SetLocal
                            || prevNode->op() == SetArgument
                            || prevNode->op() == Phi);
                        if (prevNode == edge.node()) {
                            found = true;
                            break;
                        }
                        // At this point it cannot refer into this block.
                        VALIDATE((local, block->m_predecessors[k], prevNode), !prevBlock->isInBlock(edge.node()));
                    }
                    
                    VALIDATE((node, edge), found);
                }
            }
            
            Operands<size_t> getLocalPositions(
                block->variablesAtHead.numberOfArguments(),
                block->variablesAtHead.numberOfLocals());
            Operands<size_t> setLocalPositions(
                block->variablesAtHead.numberOfArguments(),
                block->variablesAtHead.numberOfLocals());
            
            for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
                VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), blockIndex), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->hasVariableAccessData());
                if (m_graph.m_form == ThreadedCPS)
                    VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), blockIndex), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->hasVariableAccessData());
                
                getLocalPositions.argument(i) = notSet;
                setLocalPositions.argument(i) = notSet;
            }
            for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
                VALIDATE((static_cast<VirtualRegister>(i), blockIndex), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->hasVariableAccessData());
                if (m_graph.m_form == ThreadedCPS)
                    VALIDATE((static_cast<VirtualRegister>(i), blockIndex), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->hasVariableAccessData());

                getLocalPositions.local(i) = notSet;
                setLocalPositions.local(i) = notSet;
            }
            
            for (size_t i = 0; i < block->size(); ++i) {
                Node* node = block->at(i);
                ASSERT(nodesInThisBlock.contains(node));
                VALIDATE((node), node->op() != Phi);
                for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
                    Edge edge = m_graph.child(node, j);
                    if (!edge)
                        continue;
                    VALIDATE((node, edge), nodesInThisBlock.contains(edge.node()));
                    switch (node->op()) {
                    case PhantomLocal:
                    case GetLocal:
                    case Flush:
                        break;
                    case Phantom:
                        if (m_graph.m_form == LoadStore && !j)
                            break;
                    default:
                        VALIDATE((node, edge), !phisInThisBlock.contains(edge.node()));
                        break;
                    }
                }
                
                if (!node->shouldGenerate())
                    continue;
                switch (node->op()) {
                case GetLocal:
                    if (node->variableAccessData()->isCaptured())
                        break;
                    if (m_graph.m_form == ThreadedCPS)
                        VALIDATE((node, blockIndex), getLocalPositions.operand(node->local()) == notSet);
                    getLocalPositions.operand(node->local()) = i;
                    break;
                case SetLocal:
                    if (node->variableAccessData()->isCaptured())
                        break;
                    // Only record the first SetLocal. There may be multiple SetLocals
                    // because of flushing.
                    if (setLocalPositions.operand(node->local()) != notSet)
                        break;
                    setLocalPositions.operand(node->local()) = i;
                    break;
                default:
                    break;
                }
            }
            
            if (m_graph.m_form == LoadStore)
                continue;
            
            for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
                checkOperand(
                    blockIndex, getLocalPositions, setLocalPositions, argumentToOperand(i));
            }
            for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
                checkOperand(
                    blockIndex, getLocalPositions, setLocalPositions, i);
            }
        }
    }
    bool run()
    {
        RELEASE_ASSERT(m_graph.m_plan.mode == DFGMode);
        
        if (!Options::useFTLJIT())
            return false;
        
        if (m_graph.m_profiledBlock->m_didFailFTLCompilation)
            return false;

        if (!Options::bytecodeRangeToFTLCompile().isInRange(m_graph.m_profiledBlock->instructionCount()))
            return false;

#if ENABLE(FTL_JIT)
        FTL::CapabilityLevel level = FTL::canCompile(m_graph);
        if (level == FTL::CannotCompile)
            return false;
        
        if (!Options::useOSREntryToFTL())
            level = FTL::CanCompile;

        // First we find all the loops that contain a LoopHint for which we cannot OSR enter.
        // We use that information to decide if we need CheckTierUpAndOSREnter or CheckTierUpWithNestedTriggerAndOSREnter.
        m_graph.ensureNaturalLoops();
        NaturalLoops& naturalLoops = *m_graph.m_naturalLoops;

        HashSet<const NaturalLoop*> loopsContainingLoopHintWithoutOSREnter = findLoopsContainingLoopHintWithoutOSREnter(naturalLoops, level);

        bool canTierUpAndOSREnter = false;
        
        InsertionSet insertionSet(m_graph);
        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
            BasicBlock* block = m_graph.block(blockIndex);
            if (!block)
                continue;
            
            for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
                Node* node = block->at(nodeIndex);
                if (node->op() != LoopHint)
                    continue;

                NodeOrigin origin = node->origin;
                if (canOSREnterAtLoopHint(level, block, nodeIndex)) {
                    canTierUpAndOSREnter = true;
                    const NaturalLoop* loop = naturalLoops.innerMostLoopOf(block);
                    if (loop && loopsContainingLoopHintWithoutOSREnter.contains(loop))
                        insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpWithNestedTriggerAndOSREnter, origin);
                    else
                        insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpAndOSREnter, origin);
                } else
                    insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpInLoop, origin);
                break;
            }
            
            NodeAndIndex terminal = block->findTerminal();
            if (terminal.node->isFunctionTerminal()) {
                insertionSet.insertNode(
                    terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin);
            }
            
            insertionSet.execute(block);
        }

        m_graph.m_plan.canTierUpAndOSREnter = canTierUpAndOSREnter;
        m_graph.m_plan.willTryToTierUp = true;
        return true;
#else // ENABLE(FTL_JIT)
        RELEASE_ASSERT_NOT_REACHED();
        return false;
#endif // ENABLE(FTL_JIT)
    }
void AccessibilityTable::addChildren()
{
    if (!isDataTable()) {
        AccessibilityRenderObject::addChildren();
        return;
    }
    
    ASSERT(!m_haveChildren); 
    
    m_haveChildren = true;
    if (!m_renderer)
        return;
    
    RenderTable* table = static_cast<RenderTable*>(m_renderer);
    AXObjectCache* axCache = m_renderer->document()->axObjectCache();

    // go through all the available sections to pull out the rows
    // and add them as children
    RenderTableSection* tableSection = table->header();
    if (!tableSection)
        tableSection = table->firstBody();
    
    if (!tableSection)
        return;
    
    RenderTableSection* initialTableSection = tableSection;
    
    while (tableSection) {
        
        HashSet<AccessibilityObject*> appendedRows;

        unsigned numRows = tableSection->numRows();
        unsigned numCols = tableSection->numColumns();
        for (unsigned rowIndex = 0; rowIndex < numRows; ++rowIndex) {
            for (unsigned colIndex = 0; colIndex < numCols; ++colIndex) {
                
                RenderTableCell* cell = tableSection->cellAt(rowIndex, colIndex).cell;
                if (!cell)
                    continue;
                
                AccessibilityObject* rowObject = axCache->get(cell->parent());
                if (!rowObject->isTableRow())
                    continue;
                
                AccessibilityTableRow* row = static_cast<AccessibilityTableRow*>(rowObject);
                // we need to check every cell for a new row, because cell spans
                // can cause us to mess rows if we just check the first column
                if (appendedRows.contains(row))
                    continue;
                
                row->setRowIndex((int)m_rows.size());        
                m_rows.append(row);
                m_children.append(row);
                appendedRows.add(row);
            }
        }
        
        tableSection = table->sectionBelow(tableSection, true);
    }
    
    // make the columns based on the number of columns in the first body
    unsigned length = initialTableSection->numColumns();
    for (unsigned i = 0; i < length; ++i) {
        AccessibilityTableColumn* column = static_cast<AccessibilityTableColumn*>(axCache->get(ColumnRole));
        column->setColumnIndex((int)i);
        column->setParentTable(this);
        m_columns.append(column);
        m_children.append(column);
    }
    
    AccessibilityObject* headerContainerObject = headerContainer();
    if (headerContainerObject)
        m_children.append(headerContainerObject);
}
static bool isSVG11Feature(const String &feature)
{
    static bool initialized = false;
    static HashSet<String, CaseFoldingHash> svgFeatures;
    if (!initialized) {
        // Sadly, we cannot claim to implement any of the SVG 1.1 generic feature sets
        // lack of Font and Filter support.
        // http://bugs.webkit.org/show_bug.cgi?id=15480
#if ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT) && ENABLE(SVG_FILTER) && ENABLE(SVG_FONTS)
        addString(svgFeatures, "SVG");
        addString(svgFeatures, "SVGDOM");
        addString(svgFeatures, "SVG-static");
        addString(svgFeatures, "SVGDOM-static");
#endif
#if ENABLE(SVG_ANIMATION)
        addString(svgFeatures, "SVG-animation");
        addString(svgFeatures, "SVGDOM-animation");
#endif
//      addString(svgFeatures, "SVG-dynamic);
//      addString(svgFeatures, "SVGDOM-dynamic);
        addString(svgFeatures, "CoreAttribute");
#if ENABLE(SVG_USE)
        addString(svgFeatures, "Structure");
        addString(svgFeatures, "BasicStructure");
#endif
        addString(svgFeatures, "ContainerAttribute");
        addString(svgFeatures, "ConditionalProcessing");
        addString(svgFeatures, "Image");
        addString(svgFeatures, "Style");
        addString(svgFeatures, "ViewportAttribute");
        addString(svgFeatures, "Shape");
//      addString(svgFeatures, "Text"); // requires altGlyph, bug 6426
        addString(svgFeatures, "BasicText");
        addString(svgFeatures, "PaintAttribute");
        addString(svgFeatures, "BasicPaintAttribute");
        addString(svgFeatures, "OpacityAttribute");
        addString(svgFeatures, "GraphicsAttribute");
        addString(svgFeatures, "BaseGraphicsAttribute");
        addString(svgFeatures, "Marker");
//      addString(svgFeatures, "ColorProfile"); // requires color-profile, bug 6037
        addString(svgFeatures, "Gradient");
        addString(svgFeatures, "Pattern");
        addString(svgFeatures, "Clip");
        addString(svgFeatures, "BasicClip");
        addString(svgFeatures, "Mask");
#if ENABLE(SVG_FILTER)
//      addString(svgFeatures, "Filter");
        addString(svgFeatures, "BasicFilter");
#endif
        addString(svgFeatures, "DocumentEventsAttribute");
        addString(svgFeatures, "GraphicalEventsAttribute");
//      addString(svgFeatures, "AnimationEventsAttribute");
        addString(svgFeatures, "Cursor");
        addString(svgFeatures, "Hyperlinking");
        addString(svgFeatures, "XlinkAttribute");
        addString(svgFeatures, "ExternalResourcesRequired");
//      addString(svgFeatures, "View"); // buggy <view> support, bug 16962
        addString(svgFeatures, "Script");
#if ENABLE(SVG_ANIMATION)
        addString(svgFeatures, "Animation"); 
#endif
#if ENABLE(SVG_FONTS)
        addString(svgFeatures, "Font");
        addString(svgFeatures, "BasicFont");
#endif
#if ENABLE(SVG_FOREIGN_OBJECT)
        addString(svgFeatures, "Extensibility");
#endif
        initialized = true;
    }
    return svgFeatures.contains(feature);
}
void InspectorResourceContentLoader::start()
{
    m_started = true;
    Vector<Document*> documents;
    for (Frame* frame = m_inspectedFrame; frame; frame = frame->tree().traverseNext(m_inspectedFrame)) {
        if (!frame->isLocalFrame())
            continue;
        LocalFrame* localFrame = toLocalFrame(frame);
        documents.append(localFrame->document());
        documents.appendVector(InspectorPageAgent::importsForFrame(localFrame));
    }
    for (Document* document : documents) {
        HashSet<String> urlsToFetch;

        ResourceRequest resourceRequest;
        HistoryItem* item = document->frame() ? document->frame()->loader().currentItem() : nullptr;
        if (item) {
            resourceRequest = FrameLoader::requestFromHistoryItem(item, ReturnCacheDataDontLoad);
        } else {
            resourceRequest = document->url();
            resourceRequest.setCachePolicy(ReturnCacheDataDontLoad);
        }
        resourceRequest.setRequestContext(blink::WebURLRequest::RequestContextInternal);

        if (!resourceRequest.url().string().isEmpty()) {
            urlsToFetch.add(resourceRequest.url().string());
            FetchRequest request(resourceRequest, FetchInitiatorTypeNames::internal);
            ResourcePtr<Resource> resource = document->fetcher()->fetchRawResource(request);
            if (resource) {
                // Prevent garbage collection by holding a reference to this resource.
                m_resources.append(resource.get());
                ResourceClient* resourceClient = new ResourceClient(this);
                m_pendingResourceClients.add(resourceClient);
                resourceClient->waitForResource(resource.get());
            }
        }

        WillBeHeapVector<RawPtrWillBeMember<CSSStyleSheet> > styleSheets;
        InspectorCSSAgent::collectAllDocumentStyleSheets(document, styleSheets);
        for (CSSStyleSheet* styleSheet : styleSheets) {
            if (styleSheet->isInline() || !styleSheet->contents()->loadCompleted())
                continue;
            String url = styleSheet->baseURL().string();
            if (url.isEmpty() || urlsToFetch.contains(url))
                continue;
            urlsToFetch.add(url);
            FetchRequest request(ResourceRequest(url), FetchInitiatorTypeNames::internal);
            request.mutableResourceRequest().setRequestContext(blink::WebURLRequest::RequestContextInternal);
            ResourcePtr<Resource> resource = document->fetcher()->fetchCSSStyleSheet(request);
            if (!resource)
                continue;
            // Prevent garbage collection by holding a reference to this resource.
            m_resources.append(resource.get());
            ResourceClient* resourceClient = new ResourceClient(this);
            m_pendingResourceClients.add(resourceClient);
            resourceClient->waitForResource(resource.get());
        }
    }

    m_allRequestsStarted = true;
    checkDone();
}
static HashSet<String> mimeTypeCache()
{

    do_gst_init();

    static HashSet<String> cache;
    static bool typeListInitialized = false;

    if (!typeListInitialized) {
        // These subtypes are already beeing supported by WebKit itself
        HashSet<String> ignoredApplicationSubtypes;
        ignoredApplicationSubtypes.add(String("javascript"));
        ignoredApplicationSubtypes.add(String("ecmascript"));
        ignoredApplicationSubtypes.add(String("x-javascript"));
        ignoredApplicationSubtypes.add(String("xml"));
        ignoredApplicationSubtypes.add(String("xhtml+xml"));
        ignoredApplicationSubtypes.add(String("rss+xml"));
        ignoredApplicationSubtypes.add(String("atom+xml"));
        ignoredApplicationSubtypes.add(String("x-ftp-directory"));
        ignoredApplicationSubtypes.add(String("x-java-applet"));
        ignoredApplicationSubtypes.add(String("x-java-bean"));
        ignoredApplicationSubtypes.add(String("x-java-vm"));
        ignoredApplicationSubtypes.add(String("x-shockwave-flash"));

        GList* factories = gst_type_find_factory_get_list();
        for (GList* iterator = factories; iterator; iterator = iterator->next) {
            GstTypeFindFactory* factory = GST_TYPE_FIND_FACTORY(iterator->data);
            GstCaps* caps = gst_type_find_factory_get_caps(factory);

            // Splitting the capability by comma and taking the first part
            // as capability can be something like "audio/x-wavpack, framed=(boolean)false"
            GOwnPtr<gchar> capabilityString(gst_caps_to_string(caps));
            gchar** capability = g_strsplit(capabilityString.get(), ",", 2);
            gchar** mimetype = g_strsplit(capability[0], "/", 2);

            // GStreamer plugins can be capable of supporting types which WebKit supports
            // by default. In that case, we should not consider these types supportable by GStreamer.
            // Examples of what GStreamer can support but should not be added:
            // text/plain, text/html, image/jpeg, application/xml
            if (g_str_equal(mimetype[0], "audio") ||
                    g_str_equal(mimetype[0], "video") ||
                    (g_str_equal(mimetype[0], "application") &&
                        !ignoredApplicationSubtypes.contains(String(mimetype[1])))) {
                cache.add(String(capability[0]));

                // These formats are supported by GStreamer, but not correctly advertised
                if (g_str_equal(capability[0], "video/x-h264") ||
                    g_str_equal(capability[0], "audio/x-m4a")) {
                    cache.add(String("video/mp4"));
                    cache.add(String("audio/aac"));
                }

                if (g_str_equal(capability[0], "video/x-theora"))
                    cache.add(String("video/ogg"));

                if (g_str_equal(capability[0], "audio/x-wav"))
                    cache.add(String("audio/wav"));

                if (g_str_equal(capability[0], "audio/mpeg")) {
                    // This is what we are handling: mpegversion=(int)1, layer=(int)[ 1, 3 ]
                    gchar** versionAndLayer = g_strsplit(capability[1], ",", 2);

                    if (g_str_has_suffix (versionAndLayer[0], "(int)1")) {
                        for (int i = 0; versionAndLayer[1][i] != '\0'; i++) {
                            if (versionAndLayer[1][i] == '1')
                                cache.add(String("audio/mp1"));
                            else if (versionAndLayer[1][i] == '2')
                                cache.add(String("audio/mp2"));
                            else if (versionAndLayer[1][i] == '3')
                                cache.add(String("audio/mp3"));
                        }
                    }

                    g_strfreev(versionAndLayer);
                }
            }

            g_strfreev(capability);
            g_strfreev(mimetype);
        }

        gst_plugin_feature_list_free(factories);
        typeListInitialized = true;
    }

    return cache;
}
void TableSectionPainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    LayoutRect localPaintInvalidationRect = LayoutRect(paintInfo.rect);
    localPaintInvalidationRect.moveBy(-paintOffset);

    LayoutRect tableAlignedRect = m_layoutTableSection.logicalRectForWritingModeAndDirection(localPaintInvalidationRect);

    CellSpan dirtiedRows = m_layoutTableSection.dirtiedRows(tableAlignedRect);
    CellSpan dirtiedColumns = m_layoutTableSection.dirtiedColumns(tableAlignedRect);

    HashSet<LayoutTableCell*> overflowingCells = m_layoutTableSection.overflowingCells();
    if (dirtiedColumns.start() < dirtiedColumns.end()) {
        if (!m_layoutTableSection.hasMultipleCellLevels() && !overflowingCells.size()) {
            if (paintInfo.phase == PaintPhaseCollapsedTableBorders) {
                // Collapsed borders are painted from the bottom right to the top left so that precedence
                // due to cell position is respected.
                for (unsigned r = dirtiedRows.end(); r > dirtiedRows.start(); r--) {
                    unsigned row = r - 1;
                    for (unsigned c = dirtiedColumns.end(); c > dirtiedColumns.start(); c--) {
                        unsigned col = c - 1;
                        LayoutTableSection::CellStruct& current = m_layoutTableSection.cellAt(row, col);
                        LayoutTableCell* cell = current.primaryCell();
                        if (!cell || (row > dirtiedRows.start() && m_layoutTableSection.primaryCellAt(row - 1, col) == cell) || (col > dirtiedColumns.start() && m_layoutTableSection.primaryCellAt(row, col - 1) == cell))
                            continue;
                        LayoutPoint cellPoint = m_layoutTableSection.flipForWritingModeForChild(cell, paintOffset);
                        TableCellPainter(*cell).paintCollapsedBorders(paintInfo, cellPoint);
                    }
                }
            } else {
                // Draw the dirty cells in the order that they appear.
                for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) {
                    LayoutTableRow* row = m_layoutTableSection.rowLayoutObjectAt(r);
                    if (row && !row->hasSelfPaintingLayer())
                        TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo, paintOffset);
                    for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) {
                        LayoutTableSection::CellStruct& current = m_layoutTableSection.cellAt(r, c);
                        LayoutTableCell* cell = current.primaryCell();
                        if (!cell || (r > dirtiedRows.start() && m_layoutTableSection.primaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start() && m_layoutTableSection.primaryCellAt(r, c - 1) == cell))
                            continue;
                        paintCell(cell, paintInfo, paintOffset);
                    }
                }
            }
        } else {
            // The overflowing cells should be scarce to avoid adding a lot of cells to the HashSet.
#if ENABLE(ASSERT)
            unsigned totalRows = m_layoutTableSection.numRows();
            unsigned totalCols = m_layoutTableSection.table()->columns().size();
            ASSERT(overflowingCells.size() < totalRows * totalCols * gMaxAllowedOverflowingCellRatioForFastPaintPath);
#endif

            // To make sure we properly paint invalidate the section, we paint invalidated all the overflowing cells that we collected.
            Vector<LayoutTableCell*> cells;
            copyToVector(overflowingCells, cells);

            HashSet<LayoutTableCell*> spanningCells;

            for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) {
                LayoutTableRow* row = m_layoutTableSection.rowLayoutObjectAt(r);
                if (row && !row->hasSelfPaintingLayer())
                    TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo, paintOffset);
                for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) {
                    LayoutTableSection::CellStruct& current = m_layoutTableSection.cellAt(r, c);
                    if (!current.hasCells())
                        continue;
                    for (unsigned i = 0; i < current.cells.size(); ++i) {
                        if (overflowingCells.contains(current.cells[i]))
                            continue;

                        if (current.cells[i]->rowSpan() > 1 || current.cells[i]->colSpan() > 1) {
                            if (!spanningCells.add(current.cells[i]).isNewEntry)
                                continue;
                        }

                        cells.append(current.cells[i]);
                    }
                }
            }

            // Sort the dirty cells by paint order.
            if (!overflowingCells.size())
                std::stable_sort(cells.begin(), cells.end(), compareCellPositions);
            else
                std::sort(cells.begin(), cells.end(), compareCellPositionsWithOverflowingCells);

            if (paintInfo.phase == PaintPhaseCollapsedTableBorders) {
                for (unsigned i = cells.size(); i > 0; --i) {
                    LayoutPoint cellPoint = m_layoutTableSection.flipForWritingModeForChild(cells[i - 1], paintOffset);
                    TableCellPainter(*cells[i - 1]).paintCollapsedBorders(paintInfo, cellPoint);
                }
            } else {
                for (unsigned i = 0; i < cells.size(); ++i)
                    paintCell(cells[i], paintInfo, paintOffset);
            }
        }
    }
}
Beispiel #18
0
static void sortBlock(unsigned from, unsigned to, Vector<Vector<Node*> >& parentMatrix, bool mayContainAttributeNodes)
{
    ASSERT(from + 1 < to); // Should not call this function with less that two nodes to sort.
    unsigned minDepth = UINT_MAX;
    for (unsigned i = from; i < to; ++i) {
        unsigned depth = parentMatrix[i].size() - 1;
        if (minDepth > depth)
            minDepth = depth;
    }

    // Find the common ancestor.
    unsigned commonAncestorDepth = minDepth;
    Node* commonAncestor;
    while (true) {
        commonAncestor = parentWithDepth(commonAncestorDepth, parentMatrix[from]);
        if (commonAncestorDepth == 0)
            break;

        bool allEqual = true;
        for (unsigned i = from + 1; i < to; ++i) {
            if (commonAncestor != parentWithDepth(commonAncestorDepth, parentMatrix[i])) {
                allEqual = false;
                break;
            }
        }
        if (allEqual)
            break;

        --commonAncestorDepth;
    }

    if (commonAncestorDepth == minDepth) {
        // One of the nodes is the common ancestor => it is the first in document order.
        // Find it and move it to the beginning.
        for (unsigned i = from; i < to; ++i)
            if (commonAncestor == parentMatrix[i][0]) {
                parentMatrix[i].swap(parentMatrix[from]);
                if (from + 2 < to)
                    sortBlock(from + 1, to, parentMatrix, mayContainAttributeNodes);
                return;
            }
    }

    if (mayContainAttributeNodes && commonAncestor->isElementNode()) {
        // The attribute nodes and namespace nodes of an element occur before the children of the element.
        // The namespace nodes are defined to occur before the attribute nodes.
        // The relative order of namespace nodes is implementation-dependent.
        // The relative order of attribute nodes is implementation-dependent.
        unsigned sortedEnd = from;
        // FIXME: namespace nodes are not implemented.
        for (unsigned i = sortedEnd; i < to; ++i) {
            Node* n = parentMatrix[i][0];
            if (n->isAttributeNode() && static_cast<Attr*>(n)->ownerElement() == commonAncestor)
                parentMatrix[i].swap(parentMatrix[sortedEnd++]);
        }
        if (sortedEnd != from) {
            if (to - sortedEnd > 1)
                sortBlock(sortedEnd, to, parentMatrix, mayContainAttributeNodes);
            return;
        }
    }

    // Children nodes of the common ancestor induce a subdivision of our node-set.
    // Sort it according to this subdivision, and recursively sort each group.
    HashSet<Node*> parentNodes;
    for (unsigned i = from; i < to; ++i)
        parentNodes.add(parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]));

    unsigned previousGroupEnd = from;
    unsigned groupEnd = from;
    for (Node* n = commonAncestor->firstChild(); n; n = n->nextSibling()) {
        // If parentNodes contains the node, perform a linear search to move its children in the node-set to the beginning.
        if (parentNodes.contains(n)) {
            for (unsigned i = groupEnd; i < to; ++i)
                if (parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]) == n)
                    parentMatrix[i].swap(parentMatrix[groupEnd++]);

            if (groupEnd - previousGroupEnd > 1)
                sortBlock(previousGroupEnd, groupEnd, parentMatrix, mayContainAttributeNodes);

            ASSERT(previousGroupEnd != groupEnd);
            previousGroupEnd = groupEnd;
#ifndef NDEBUG
            parentNodes.remove(n);
#endif
        }
    }

    ASSERT(parentNodes.isEmpty());
}
Beispiel #19
0
void AccessibilityTable::addChildren()
{
    if (!isAccessibilityTable()) {
        AccessibilityRenderObject::addChildren();
        return;
    }
    
    ASSERT(!m_haveChildren); 
    
    m_haveChildren = true;
    if (!m_renderer || !m_renderer->isTable())
        return;
    
    RenderTable* table = toRenderTable(m_renderer);
    AXObjectCache* axCache = m_renderer->document().axObjectCache();

    // Go through all the available sections to pull out the rows and add them as children.
    table->recalcSectionsIfNeeded();
    RenderTableSection* tableSection = table->topSection();
    if (!tableSection)
        return;
    
    unsigned maxColumnCount = 0;
    while (tableSection) {
        
        HashSet<AccessibilityObject*> appendedRows;
        unsigned numRows = tableSection->numRows();
        for (unsigned rowIndex = 0; rowIndex < numRows; ++rowIndex) {
            
            RenderTableRow* renderRow = tableSection->rowRendererAt(rowIndex);
            if (!renderRow)
                continue;
            
            AccessibilityObject* rowObject = axCache->getOrCreate(renderRow);
            if (!rowObject->isTableRow())
                continue;
            
            AccessibilityTableRow* row = toAccessibilityTableRow(rowObject);
            // We need to check every cell for a new row, because cell spans
            // can cause us to miss rows if we just check the first column.
            if (appendedRows.contains(row))
                continue;
            
            row->setRowIndex(static_cast<int>(m_rows.size()));
            m_rows.append(row);
            if (!row->accessibilityIsIgnored())
                m_children.append(row);
#if PLATFORM(GTK) || PLATFORM(EFL)
            else
                m_children.appendVector(row->children());
#endif
            appendedRows.add(row);
        }
    
        maxColumnCount = std::max(tableSection->numColumns(), maxColumnCount);
        tableSection = table->sectionBelow(tableSection, SkipEmptySections);
    }
    
    // make the columns based on the number of columns in the first body
    unsigned length = maxColumnCount;
    for (unsigned i = 0; i < length; ++i) {
        AccessibilityTableColumn* column = toAccessibilityTableColumn(axCache->getOrCreate(ColumnRole));
        column->setColumnIndex((int)i);
        column->setParent(this);
        m_columns.append(column);
        if (!column->accessibilityIsIgnored())
            m_children.append(column);
    }
    
    AccessibilityObject* headerContainerObject = headerContainer();
    if (headerContainerObject && !headerContainerObject->accessibilityIsIgnored())
        m_children.append(headerContainerObject);
}
// FIXME: This function should not deal with url or serviceType!
void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType)
{
    HashSet<StringImpl*, ASCIICaseInsensitiveHash> uniqueParamNames;
    String urlParameter;
    
    // Scan the PARAM children and store their name/value pairs.
    // Get the URL and type from the params if we don't already have them.
    for (auto& param : childrenOfType<HTMLParamElement>(*this)) {
        String name = param.name();
        if (name.isEmpty())
            continue;

        uniqueParamNames.add(name.impl());
        paramNames.append(param.name());
        paramValues.append(param.value());

        // FIXME: url adjustment does not belong in this function.
        if (url.isEmpty() && urlParameter.isEmpty() && (equalLettersIgnoringASCIICase(name, "src") || equalLettersIgnoringASCIICase(name, "movie") || equalLettersIgnoringASCIICase(name, "code") || equalLettersIgnoringASCIICase(name, "url")))
            urlParameter = stripLeadingAndTrailingHTMLSpaces(param.value());
        // FIXME: serviceType calculation does not belong in this function.
        if (serviceType.isEmpty() && equalLettersIgnoringASCIICase(name, "type")) {
            serviceType = param.value();
            size_t pos = serviceType.find(';');
            if (pos != notFound)
                serviceType = serviceType.left(pos);
        }
    }
    
    // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
    // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
    // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
    // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
    // else our Java plugin will misinterpret it. [4004531]
    String codebase;
    if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
        codebase = "codebase";
        uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
    }
    
    // Turn the attributes of the <object> element into arrays, but don't override <param> values.
    if (hasAttributes()) {
        for (const Attribute& attribute : attributesIterator()) {
            const AtomicString& name = attribute.name().localName();
            if (!uniqueParamNames.contains(name.impl())) {
                paramNames.append(name.string());
                paramValues.append(attribute.value().string());
            }
        }
    }
    
    mapDataParamToSrc(paramNames, paramValues);
    
    // HTML5 says that an object resource's URL is specified by the object's data
    // attribute, not by a param element. However, for compatibility, allow the
    // resource's URL to be given by a param named "src", "movie", "code" or "url"
    // if we know that resource points to a plug-in.
#if PLATFORM(IOS)
    if (shouldNotPerformURLAdjustment())
        return;
#endif

    if (url.isEmpty() && !urlParameter.isEmpty()) {
        SubframeLoader& loader = document().frame()->loader().subframeLoader();
        if (loader.resourceWillUsePlugin(urlParameter, serviceType))
            url = urlParameter;
    }
}
Beispiel #21
0
bool RadioButtonGroup::contains(HTMLInputElement* button) const
{
    return m_members.contains(button);
}
// FIXME: This function should not deal with url or serviceType!
void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType)
{
    HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
    String urlParameter;

    // Scan the PARAM children and store their name/value pairs.
    // Get the URL and type from the params if we don't already have them.
    for (HTMLParamElement* p = Traversal<HTMLParamElement>::firstChild(*this); p; p = Traversal<HTMLParamElement>::nextSibling(*p)) {
        String name = p->name();
        if (name.isEmpty())
            continue;

        uniqueParamNames.add(name.impl());
        paramNames.append(p->name());
        paramValues.append(p->value());

        // FIXME: url adjustment does not belong in this function.
        if (url.isEmpty() && urlParameter.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
            urlParameter = stripLeadingAndTrailingHTMLSpaces(p->value());
        // FIXME: serviceType calculation does not belong in this function.
        if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
            serviceType = p->value();
            size_t pos = serviceType.find(";");
            if (pos != kNotFound)
                serviceType = serviceType.left(pos);
        }
    }

    // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
    // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
    // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
    // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
    // else our Java plugin will misinterpret it. [4004531]
    String codebase;
    if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
        codebase = "codebase";
        uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
    }

    // Turn the attributes of the <object> element into arrays, but don't override <param> values.
    AttributeCollection attributes = this->attributes();
    for (const Attribute& attribute : attributes) {
        const AtomicString& name = attribute.name().localName();
        if (!uniqueParamNames.contains(name.impl())) {
            paramNames.append(name.string());
            paramValues.append(attribute.value().string());
        }
    }

    mapDataParamToSrc(&paramNames, &paramValues);

    // HTML5 says that an object resource's URL is specified by the object's data
    // attribute, not by a param element. However, for compatibility, allow the
    // resource's URL to be given by a param named "src", "movie", "code" or "url"
    // if we know that resource points to a plugin.
    if (url.isEmpty() && !urlParameter.isEmpty()) {
        KURL completedURL = document().completeURL(urlParameter);
        bool useFallback;
        if (shouldUsePlugin(completedURL, serviceType, false, useFallback))
            url = urlParameter;
    }
}
Beispiel #23
0
void WebSocket::connect(const String& url, const Vector<String>& protocols, ExceptionCode& ec)
{
    LOG(Network, "WebSocket %p connect() url='%s'", this, url.utf8().data());
    m_url = KURL(KURL(), url);

    if (!m_url.isValid()) {
        scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Invalid url for WebSocket " + m_url.elidedString());
        m_state = CLOSED;
        ec = SYNTAX_ERR;
        return;
    }

    if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) {
        scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Wrong url scheme for WebSocket " + m_url.elidedString());
        m_state = CLOSED;
        ec = SYNTAX_ERR;
        return;
    }
    if (m_url.hasFragmentIdentifier()) {
        scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "URL has fragment component " + m_url.elidedString());
        m_state = CLOSED;
        ec = SYNTAX_ERR;
        return;
    }
    if (!portAllowed(m_url)) {
        scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "WebSocket port " + String::number(m_url.port()) + " blocked");
        m_state = CLOSED;
        ec = SECURITY_ERR;
        return;
    }

    // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
    bool shouldBypassMainWorldContentSecurityPolicy = false;
    if (scriptExecutionContext()->isDocument()) {
        Document* document = toDocument(scriptExecutionContext());
        shouldBypassMainWorldContentSecurityPolicy = document->frame()->script()->shouldBypassMainWorldContentSecurityPolicy();
    }
    if (!shouldBypassMainWorldContentSecurityPolicy && !scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url)) {
        m_state = CLOSED;

        // FIXME: Should this be throwing an exception?
        ec = SECURITY_ERR;
        return;
    }

    m_channel = WebSocketChannel::create(scriptExecutionContext(), this);

    // FIXME: There is a disagreement about restriction of subprotocols between WebSocket API and hybi-10 protocol
    // draft. The former simply says "only characters in the range U+0021 to U+007E are allowed," while the latter
    // imposes a stricter rule: "the elements MUST be non-empty strings with characters as defined in [RFC2616],
    // and MUST all be unique strings."
    //
    // Here, we throw SYNTAX_ERR if the given protocols do not meet the latter criteria. This behavior does not
    // comply with WebSocket API specification, but it seems to be the only reasonable way to handle this conflict.
    for (size_t i = 0; i < protocols.size(); ++i) {
        if (!isValidProtocolString(protocols[i])) {
            scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(protocols[i]) + "'");
            m_state = CLOSED;
            ec = SYNTAX_ERR;
            return;
        }
    }
    HashSet<String> visited;
    for (size_t i = 0; i < protocols.size(); ++i) {
        if (visited.contains(protocols[i])) {
            scriptExecutionContext()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "WebSocket protocols contain duplicates: '" + encodeProtocolString(protocols[i]) + "'");
            m_state = CLOSED;
            ec = SYNTAX_ERR;
            return;
        }
        visited.add(protocols[i]);
    }

    String protocolString;
    if (!protocols.isEmpty())
        protocolString = joinStrings(protocols, subProtocolSeperator());

    m_channel->connect(m_url, protocolString);
    ActiveDOMObject::setPendingActivity(this);
}
Beispiel #24
0
static const CommandMap& createCommandMap()
{
    // If you add new commands, you should assign new Id to each idForUserMetrics and update MappedEditingCommands
    // in chrome/trunk/src/tools/metrics/histograms/histograms.xml.
    static const CommandEntry commands[] = {
        { "Copy", {7, executeCopy, supportedCopyCut, enabledCopy, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
        { "Cut", {9, executeCut, supportedCopyCut, enabledCut, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
        { "DeleteBackward", {12, executeDeleteBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "DeleteForward", {14, executeDeleteForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "DeleteWordBackward", {20, executeDeleteWordBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "DeleteWordForward", {21, executeDeleteWordForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "InsertNewline", {37, executeInsertNewline, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveDown", {55, executeMoveDown, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveDownAndModifySelection", {56, executeMoveDownAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveLeft", {59, executeMoveLeft, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveLeftAndModifySelection", {60, executeMoveLeftAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MovePageDown", {61, executeMovePageDown, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MovePageDownAndModifySelection", {62, executeMovePageDownAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MovePageUp", {63, executeMovePageUp, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MovePageUpAndModifySelection", {64, executeMovePageUpAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveParagraphBackward", {65, executeMoveParagraphBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveParagraphBackwardAndModifySelection", {66, executeMoveParagraphBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveParagraphForward", {67, executeMoveParagraphForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveParagraphForwardAndModifySelection", {68, executeMoveParagraphForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveRight", {69, executeMoveRight, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveRightAndModifySelection", {70, executeMoveRightAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToBeginningOfDocument", {71, executeMoveToBeginningOfDocument, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToBeginningOfDocumentAndModifySelection", {72, executeMoveToBeginningOfDocumentAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToBeginningOfLine", {73, executeMoveToBeginningOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToBeginningOfLineAndModifySelection", {74, executeMoveToBeginningOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToEndOfDocument", {79, executeMoveToEndOfDocument, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToEndOfDocumentAndModifySelection", {80, executeMoveToEndOfDocumentAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToEndOfLine", {81, executeMoveToEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToEndOfLineAndModifySelection", {82, executeMoveToEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToLeftEndOfLine", {87, executeMoveToLeftEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveToLeftEndOfLineAndModifySelection", {88, executeMoveToLeftEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveUp", {91, executeMoveUp, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveUpAndModifySelection", {92, executeMoveUpAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveWordLeft", {97, executeMoveWordLeft, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveWordLeftAndModifySelection", {98, executeMoveWordLeftAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveWordRight", {99, executeMoveWordRight, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "MoveWordRightAndModifySelection", {100, executeMoveWordRightAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "OverWrite", {102, executeToggleOverwrite, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
        { "Paste", {103, executePaste, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
        { "PasteAndMatchStyle", {104, executePasteAndMatchStyle, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
        { "SelectAll", {115, executeSelectAll, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
    };

    CommandMap& commandMap = *new CommandMap;
#if ENABLE(ASSERT)
    HashSet<int> idSet;
#endif
    for (size_t i = 0; i < WTF_ARRAY_LENGTH(commands); ++i) {
        const CommandEntry& command = commands[i];
        ASSERT(!commandMap.get(command.name));
        commandMap.set(command.name, &command.command);
#if ENABLE(ASSERT)
        ASSERT(!idSet.contains(command.command.idForUserMetrics));
        idSet.add(command.command.idForUserMetrics);
#endif
    }

    return commandMap;
}
void SVGResourcesCycleSolver::resolveCycles()
{
    ASSERT(m_allResources.isEmpty());

#if DEBUG_CYCLE_DETECTION
    LOG_DEBUG_CYCLE("\nBefore cycle detection:\n");
    m_resources.dump(&m_renderer);
#endif

    // Stash all resources into a HashSet for the ease of traversing.
    HashSet<RenderSVGResourceContainer*> localResources;
    m_resources.buildSetOfResources(localResources);
    ASSERT(!localResources.isEmpty());

    // Add all parent resource containers to the HashSet.
    HashSet<RenderSVGResourceContainer*> ancestorResources;
    for (auto& resource : ancestorsOfType<RenderSVGResourceContainer>(m_renderer))
        ancestorResources.add(&resource);

#if DEBUG_CYCLE_DETECTION
    LOG_DEBUG_CYCLE("\nDetecting whether any resources references any of following objects:\n");
    {
        LOG_DEBUG_CYCLE("Local resources:\n");
        for (RenderObject* resource : localResources)
            LOG_DEBUG_CYCLE("|> %s : %p (node %p)\n", resource->renderName(), resource, resource->node());

        fprintf(stderr, "Parent resources:\n");
        for (RenderObject* resource : ancestorResources)
            LOG_DEBUG_CYCLE("|> %s : %p (node %p)\n", resource->renderName(), resource, resource->node());
    }
#endif

    // Build combined set of local and parent resources.
    m_allResources = localResources;
    for (auto* resource : ancestorResources)
        m_allResources.add(resource);

    // If we're a resource, add ourselves to the HashSet.
    if (is<RenderSVGResourceContainer>(m_renderer))
        m_allResources.add(&downcast<RenderSVGResourceContainer>(m_renderer));

    ASSERT(!m_allResources.isEmpty());

#if DEBUG_CYCLE_DETECTION
    LOG_DEBUG_CYCLE("\nAll resources:\n");
    for (auto* resource : m_allResources)
        LOG_DEBUG_CYCLE("- %p\n", resource);
#endif

    // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer'
    // references us (or whether any of its kids references us) -> that's a cycle, we need to find and break it.
    for (auto* resource : localResources) {
        if (ancestorResources.contains(resource) || resourceContainsCycles(*resource)) {
            LOG_DEBUG_CYCLE("\n**** Detected a cycle (see the last test in the output above) ****\n");
            breakCycle(*resource);
        }
    }

#if DEBUG_CYCLE_DETECTION
    LOG_DEBUG_CYCLE("\nAfter cycle detection:\n");
    m_resources.dump(&m_renderer);
#endif

    m_allResources.clear();
}
RadialGradientAttributes SVGRadialGradientElement::collectGradientProperties() const
{
    RadialGradientAttributes attributes;
    HashSet<const SVGGradientElement*> processedGradients;

    bool isRadial = true;
    const SVGGradientElement* current = this;

    while (current) {
        if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr))
            attributes.setSpreadMethod((GradientSpreadMethod) current->spreadMethod());

        if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr))
            attributes.setBoundingBoxMode(current->gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);

        if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr))
            attributes.setGradientTransform(current->gradientTransform()->consolidate().matrix());

        if (!attributes.hasStops()) {
            const Vector<SVGGradientStop>& stops(current->buildStops());
            if (!stops.isEmpty())
                attributes.setStops(stops);
        }

        if (isRadial) {
            const SVGRadialGradientElement* radial = static_cast<const SVGRadialGradientElement*>(current);

            if (!attributes.hasCx() && current->hasAttribute(SVGNames::cxAttr))
                attributes.setCx(radial->cx().valueAsPercentage());

            if (!attributes.hasCy() && current->hasAttribute(SVGNames::cyAttr))
                attributes.setCy(radial->cy().valueAsPercentage());

            if (!attributes.hasR() && current->hasAttribute(SVGNames::rAttr))
                attributes.setR(radial->r().valueAsPercentage());

            if (!attributes.hasFx() && current->hasAttribute(SVGNames::fxAttr))
                attributes.setFx(radial->fx().valueAsPercentage());

            if (!attributes.hasFy() && current->hasAttribute(SVGNames::fyAttr))
                attributes.setFy(radial->fy().valueAsPercentage());
        }

        processedGradients.add(current);

        // Respect xlink:href, take attributes from referenced element
        Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
        if (refNode && (refNode->hasTagName(SVGNames::radialGradientTag) || refNode->hasTagName(SVGNames::linearGradientTag))) {
            current = static_cast<const SVGGradientElement*>(const_cast<const Node*>(refNode));

            // Cycle detection
            if (processedGradients.contains(current))
                return RadialGradientAttributes();

            isRadial = current->gradientType() == RadialGradientPaintServer;
        } else
            current = 0;
    }

    // Handle default values for fx/fy
    if (!attributes.hasFx())
        attributes.setFx(attributes.cx());

    if (!attributes.hasFy())
        attributes.setFy(attributes.cy());

    return attributes;
}
Beispiel #27
0
void WebSocket::connect(const String& url, const Vector<String>& protocols, ExceptionCode& ec)
{
    LOG(Network, "WebSocket %p connect to %s", this, url.utf8().data());
    m_url = KURL(KURL(), url);

    if (!m_url.isValid()) {
        scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Invalid url for WebSocket " + m_url.string(), scriptExecutionContext()->securityOrigin()->toString());
        m_state = CLOSED;
        ec = SYNTAX_ERR;
        return;
    }

    if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) {
        scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong url scheme for WebSocket " + m_url.string(), scriptExecutionContext()->securityOrigin()->toString());
        m_state = CLOSED;
        ec = SYNTAX_ERR;
        return;
    }
    if (m_url.hasFragmentIdentifier()) {
        scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "URL has fragment component " + m_url.string(), scriptExecutionContext()->securityOrigin()->toString());
        m_state = CLOSED;
        ec = SYNTAX_ERR;
        return;
    }
    if (!portAllowed(m_url)) {
        scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "WebSocket port " + String::number(m_url.port()) + " blocked", scriptExecutionContext()->securityOrigin()->toString());
        m_state = CLOSED;
        ec = SECURITY_ERR;
        return;
    }

    if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url)) {
        m_state = CLOSED;

        // FIXME: Should this be throwing an exception?
        ec = SECURITY_ERR;
        return;
    }

    m_channel = ThreadableWebSocketChannel::create(scriptExecutionContext(), this);
    m_useHixie76Protocol = m_channel->useHixie76Protocol();

    String protocolString;
    if (m_useHixie76Protocol) {
        if (!protocols.isEmpty()) {
            // Emulate JavaScript's Array.toString() behavior.
            protocolString = joinStrings(protocols, ",");
        }
        if (!isValidProtocolStringHixie76(protocolString)) {
            scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(protocolString) + "'", scriptExecutionContext()->securityOrigin()->toString());
            m_state = CLOSED;
            ec = SYNTAX_ERR;
            return;
        }
    } else {
        // FIXME: There is a disagreement about restriction of subprotocols between WebSocket API and hybi-10 protocol
        // draft. The former simply says "only characters in the range U+0021 to U+007E are allowed," while the latter
        // imposes a stricter rule: "the elements MUST be non-empty strings with characters as defined in [RFC2616],
        // and MUST all be unique strings."
        //
        // Here, we throw SYNTAX_ERR if the given protocols do not meet the latter criteria. This behavior does not
        // comply with WebSocket API specification, but it seems to be the only reasonable way to handle this conflict.
        for (size_t i = 0; i < protocols.size(); ++i) {
            if (!isValidProtocolString(protocols[i])) {
                scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(protocols[i]) + "'", scriptExecutionContext()->securityOrigin()->toString());
                m_state = CLOSED;
                ec = SYNTAX_ERR;
                return;
            }
        }
        HashSet<String> visited;
        for (size_t i = 0; i < protocols.size(); ++i) {
            if (visited.contains(protocols[i])) {
                scriptExecutionContext()->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "WebSocket protocols contain duplicates: '" + encodeProtocolString(protocols[i]) + "'", scriptExecutionContext()->securityOrigin()->toString());
                m_state = CLOSED;
                ec = SYNTAX_ERR;
                return;
            }
            visited.add(protocols[i]);
        }

        if (!protocols.isEmpty())
            protocolString = joinStrings(protocols, subProtocolSeperator());
    }

    m_channel->connect(m_url, protocolString);
    ActiveDOMObject::setPendingActivity(this);
}
 bool shouldBeElided(HashSet<Node*>& dontNeedBarriers, Node* node)
 {
     ASSERT(node->isStoreBarrier());
     return dontNeedBarriers.contains(node->child1().node());
 }
// FIXME: This function should not deal with url or serviceType!
void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType)
{
    HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
    String urlParameter;
    
    // Scan the PARAM children and store their name/value pairs.
    // Get the URL and type from the params if we don't already have them.
    for (Node* child = firstChild(); child; child = child->nextSibling()) {
        if (!child->hasTagName(paramTag))
            continue;

        HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
        String name = p->name();
        if (name.isEmpty())
            continue;

        uniqueParamNames.add(name.impl());
        paramNames.append(p->name());
        paramValues.append(p->value());

        // FIXME: url adjustment does not belong in this function.
        if (url.isEmpty() && urlParameter.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
            urlParameter = stripLeadingAndTrailingHTMLSpaces(p->value());
        // FIXME: serviceType calculation does not belong in this function.
        if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
            serviceType = p->value();
            size_t pos = serviceType.find(";");
            if (pos != notFound)
                serviceType = serviceType.left(pos);
        }
    }
    
    // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
    // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
    // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
    // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
    // else our Java plugin will misinterpret it. [4004531]
    String codebase;
    if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
        codebase = "codebase";
        uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
    }
    
    // Turn the attributes of the <object> element into arrays, but don't override <param> values.
    NamedNodeMap* attributes = this->attributes(true);
    if (attributes) {
        for (unsigned i = 0; i < attributes->length(); ++i) {
            Attribute* it = attributes->attributeItem(i);
            const AtomicString& name = it->name().localName();
            if (!uniqueParamNames.contains(name.impl())) {
                paramNames.append(name.string());
                paramValues.append(it->value().string());
            }
        }
    }
    
    mapDataParamToSrc(&paramNames, &paramValues);
    
    // HTML5 says that an object resource's URL is specified by the object's data
    // attribute, not by a param element. However, for compatibility, allow the
    // resource's URL to be given by a param named "src", "movie", "code" or "url"
    // if we know that resource points to a plug-in.
    if (url.isEmpty() && !urlParameter.isEmpty()) {
        SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
        if (loader->resourceWillUsePlugin(urlParameter, serviceType, shouldPreferPlugInsForImages()))
            url = urlParameter;
    }
}
Beispiel #30
0
void AccessibilityTable::addChildren()
{
    if (!isAccessibilityTable()) {
        AccessibilityRenderObject::addChildren();
        return;
    }
    
    ASSERT(!m_haveChildren); 
    
    m_haveChildren = true;
    if (!m_renderer || !m_renderer->isTable())
        return;
    
    RenderTable* table = toRenderTable(m_renderer);
    AXObjectCache* axCache = m_renderer->document()->axObjectCache();

    // go through all the available sections to pull out the rows
    // and add them as children
    // FIXME: This will skip a table with just a tfoot. Should fix by using RenderTable::topSection.
    RenderTableSection* tableSection = table->header();
    if (!tableSection)
        tableSection = table->firstBody();
    
    if (!tableSection)
        return;
    
    RenderTableSection* initialTableSection = tableSection;
    
    while (tableSection) {
        
        HashSet<AccessibilityObject*> appendedRows;

        unsigned numRows = tableSection->numRows();
        unsigned numCols = tableSection->numColumns();
        for (unsigned rowIndex = 0; rowIndex < numRows; ++rowIndex) {
            for (unsigned colIndex = 0; colIndex < numCols; ++colIndex) {
                
                RenderTableCell* cell = tableSection->primaryCellAt(rowIndex, colIndex);
                if (!cell)
                    continue;
                
                AccessibilityObject* rowObject = axCache->getOrCreate(cell->parent());
                if (!rowObject->isTableRow())
                    continue;
                
                AccessibilityTableRow* row = static_cast<AccessibilityTableRow*>(rowObject);
                // we need to check every cell for a new row, because cell spans
                // can cause us to mess rows if we just check the first column
                if (appendedRows.contains(row))
                    continue;
                
                row->setRowIndex((int)m_rows.size());        
                m_rows.append(row);
                if (!row->accessibilityIsIgnored())
                    m_children.append(row);
#if PLATFORM(GTK)
                else
                    m_children.append(row->children());
#endif
                appendedRows.add(row);
            }
        }
        
        tableSection = table->sectionBelow(tableSection, SkipEmptySections);
    }
    
    // make the columns based on the number of columns in the first body
    unsigned length = initialTableSection->numColumns();
    for (unsigned i = 0; i < length; ++i) {
        AccessibilityTableColumn* column = static_cast<AccessibilityTableColumn*>(axCache->getOrCreate(ColumnRole));
        column->setColumnIndex((int)i);
        column->setParent(this);
        m_columns.append(column);
        if (!column->accessibilityIsIgnored())
            m_children.append(column);
    }
    
    AccessibilityObject* headerContainerObject = headerContainer();
    if (headerContainerObject && !headerContainerObject->accessibilityIsIgnored())
        m_children.append(headerContainerObject);
}