bool MediaPlayer::supportsType(const String& type) { HashSet<String> types; getSupportedTypes(types); return MIMETypeRegistry::isSupportedMediaMIMEType(type) && types.contains(type); }
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)); }
// 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); }
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; }
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; }
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); }
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); } } } }
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()); }
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; } }
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(¶mNames, ¶mValues); // 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; } }
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); }
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; }
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(¶mNames, ¶mValues); // 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; } }
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); }