void WebsiteDataStore::removeData(WebsiteDataTypes dataTypes, const Vector<WebsiteDataRecord>& dataRecords, std::function<void ()> completionHandler) { Vector<RefPtr<WebCore::SecurityOrigin>> origins; for (const auto& dataRecord : dataRecords) { for (auto& origin : dataRecord.origins) origins.append(origin); } struct CallbackAggregator : public RefCounted<CallbackAggregator> { explicit CallbackAggregator (std::function<void ()> completionHandler) : completionHandler(WTF::move(completionHandler)) { } void addPendingCallback() { pendingCallbacks++; } void removePendingCallback() { ASSERT(pendingCallbacks); --pendingCallbacks; callIfNeeded(); } void callIfNeeded() { if (!pendingCallbacks) RunLoop::main().dispatch(WTF::move(completionHandler)); } unsigned pendingCallbacks = 0; std::function<void ()> completionHandler; }; RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTF::move(completionHandler))); auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, isNonPersistent()); if (networkProcessAccessType != ProcessAccessType::None) { HashSet<WebProcessPool*> processPools; for (auto& process : processes()) processPools.add(&process->processPool()); for (auto& processPool : processPools) { switch (networkProcessAccessType) { case ProcessAccessType::OnlyIfLaunched: if (!processPool->networkProcess()) continue; break; case ProcessAccessType::Launch: processPool->ensureNetworkProcess(); break; case ProcessAccessType::None: ASSERT_NOT_REACHED(); } Vector<String> cookieHostNames; for (const auto& dataRecord : dataRecords) { for (auto& hostName : dataRecord.cookieHostNames) cookieHostNames.append(hostName); } callbackAggregator->addPendingCallback(); processPool->networkProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, cookieHostNames, [callbackAggregator] { callbackAggregator->removePendingCallback(); }); } } auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, isNonPersistent()); if (webProcessAccessType != ProcessAccessType::None) { for (auto& process : processes()) { switch (webProcessAccessType) { case ProcessAccessType::OnlyIfLaunched: if (!process->canSendMessage()) continue; break; case ProcessAccessType::Launch: // FIXME: Handle this. ASSERT_NOT_REACHED(); break; case ProcessAccessType::None: ASSERT_NOT_REACHED(); } callbackAggregator->addPendingCallback(); process->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator] { callbackAggregator->removePendingCallback(); }); } } if (dataTypes & WebsiteDataTypeLocalStorage && m_storageManager) { callbackAggregator->addPendingCallback(); m_storageManager->deleteEntriesForOrigins(origins, [callbackAggregator] { callbackAggregator->removePendingCallback(); }); } // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away. callbackAggregator->callIfNeeded(); }
static void addEncodingName(HashSet<const char*>& set, const char* name) { const char* atomicName = atomicCanonicalTextEncodingName(name); if (atomicName) set.add(atomicName); }
void SVGFitToViewBox::addSupportedAttributes(HashSet<QualifiedName>& supportedAttributes) { supportedAttributes.add(SVGNames::viewBoxAttr); supportedAttributes.add(SVGNames::preserveAspectRatioAttr); }
void MediaPlayerPrivateMediaFoundation::getSupportedTypes(HashSet<String>& types) { types.add(String("video/mp4")); }
void SimpleEditCommand::addNodeAndDescendants(Node* startNode, HashSet<Node*>& nodes) { for (Node* node = startNode; node; node = NodeTraversal::next(*node, startNode)) nodes.add(node); }
void SVGURIReference::addSupportedAttributes(HashSet<QualifiedName>& supportedAttributes) { supportedAttributes.add(XLinkNames::hrefAttr); }
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); }
void SharedCookieJarQt::getHostnamesWithCookies(HashSet<String>& hostnames) { QList<QNetworkCookie> cookies = allCookies(); foreach (const QNetworkCookie& networkCookie, cookies) hostnames.add(networkCookie.domain()); }
static void initializeDomainsList(HashSet<String>& googleDomains) { // Google search domains. googleDomains.add("biz"); googleDomains.add("com"); googleDomains.add("net"); googleDomains.add("org"); googleDomains.add("ae"); googleDomains.add("ag"); googleDomains.add("am"); googleDomains.add("at"); googleDomains.add("az"); googleDomains.add("be"); googleDomains.add("bi"); googleDomains.add("ca"); googleDomains.add("cc"); googleDomains.add("cd"); googleDomains.add("cg"); googleDomains.add("ch"); googleDomains.add("cl"); googleDomains.add("com.br"); googleDomains.add("co.uk"); googleDomains.add("co.kr"); googleDomains.add("co.jp"); googleDomains.add("de"); googleDomains.add("dj"); googleDomains.add("dk"); googleDomains.add("es"); googleDomains.add("fi"); googleDomains.add("fm"); googleDomains.add("fr"); googleDomains.add("gg"); googleDomains.add("gl"); googleDomains.add("gm"); googleDomains.add("gs"); googleDomains.add("hn"); googleDomains.add("hu"); googleDomains.add("ie"); googleDomains.add("it"); googleDomains.add("je"); googleDomains.add("kz"); googleDomains.add("li"); googleDomains.add("lt"); googleDomains.add("lu"); googleDomains.add("lv"); googleDomains.add("ma"); googleDomains.add("ms"); googleDomains.add("mu"); googleDomains.add("mw"); googleDomains.add("nl"); googleDomains.add("no"); googleDomains.add("nu"); googleDomains.add("pl"); googleDomains.add("pn"); googleDomains.add("pt"); googleDomains.add("ru"); googleDomains.add("rw"); googleDomains.add("sh"); googleDomains.add("sk"); googleDomains.add("sm"); googleDomains.add("st"); googleDomains.add("td"); googleDomains.add("tk"); googleDomains.add("tp"); googleDomains.add("tv"); googleDomains.add("us"); googleDomains.add("uz"); googleDomains.add("ws"); }
void PageGroup::clearDomStorage() { if (!pageGroups) return; PageGroupMap::iterator end = pageGroups->end(); for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) { String basePath = ""; // This is being called as a result of the user explicitly // asking to clear all stored data (e.g. through a settings // dialog. We need a page in the page group to fire a // StorageEvent. There isn't really a correct page to use // as the source (as the clear request hasn't come from a // particular page). One thing we should ensure though is that // we don't try to clear a private browsing mode page as that has no concept // of DOM storage.. HashSet<Page*> pages = it->second->pages(); HashSet<Page*>::iterator pagesEnd = pages.end(); Page* page = 0; for(HashSet<Page*>::iterator pit = pages.begin(); pit != pagesEnd; ++pit) { Page* p = *pit; // Grab the storage location from an arbitrary page. This is set // to the same value on all private browsing and "normal" pages, // so we can get it from anything. if (basePath.isEmpty()) basePath = p->settings()->localStorageDatabasePath(); // DOM storage is disabled in private browsing pages, so nothing to do if // this is such a page. if (p->settings()->privateBrowsingEnabled()) continue; // Clear session storage. StorageNamespace* sessionStorage = p->sessionStorage(false); if (sessionStorage) sessionStorage->clear(p); // Save this page so we can clear local storage. page = p; } // If page is still null at this point, then the only pages that are // open are private browsing pages. Hence no pages are currently using local // storage, so we don't need a page pointer to send any events and the // clear function will handle a 0 input. it->second->localStorage()->clear(page); it->second->localStorage()->close(); // Closing the storage areas will stop the background thread and so // we need to remove the local storage ref here so that next time // we come to a site that uses it the thread will get started again. it->second->removeLocalStorage(); // At this point, active local and session storage have been cleared and the // StorageAreas for this PageGroup closed. The final sync will have taken // place. All that is left is to purge the database files. if (!basePath.isEmpty()) { Vector<String> files = listDirectory(basePath, "*.localstorage"); Vector<String>::iterator filesEnd = files.end(); for (Vector<String>::iterator it = files.begin(); it != filesEnd; ++it) deleteFile(*it); } } }
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(); }
void LoadMesh(const String& inputFileName, bool generateTangents, bool splitSubMeshes, bool exportMorphs) { File meshFileSource(context_); meshFileSource.Open(inputFileName); if (!meshFile_->Load(meshFileSource)) ErrorExit("Could not load input file " + inputFileName); XMLElement root = meshFile_->GetRoot("mesh"); XMLElement subMeshes = root.GetChild("submeshes"); XMLElement skeletonLink = root.GetChild("skeletonlink"); if (root.IsNull()) ErrorExit("Could not load input file " + inputFileName); String skeletonName = skeletonLink.GetAttribute("name"); if (!skeletonName.Empty()) LoadSkeleton(GetPath(inputFileName) + GetFileName(skeletonName) + ".skeleton.xml"); // Check whether there's benefit of avoiding 32bit indices by splitting each submesh into own buffer XMLElement subMesh = subMeshes.GetChild("submesh"); unsigned totalVertices = 0; unsigned maxSubMeshVertices = 0; while (subMesh) { materialNames_.Push(subMesh.GetAttribute("material")); XMLElement geometry = subMesh.GetChild("geometry"); if (geometry) { unsigned vertices = geometry.GetInt("vertexcount"); totalVertices += vertices; if (maxSubMeshVertices < vertices) maxSubMeshVertices = vertices; } ++numSubMeshes_; subMesh = subMesh.GetNext("submesh"); } XMLElement sharedGeometry = root.GetChild("sharedgeometry"); if (sharedGeometry) { unsigned vertices = sharedGeometry.GetInt("vertexcount"); totalVertices += vertices; if (maxSubMeshVertices < vertices) maxSubMeshVertices = vertices; } if (!sharedGeometry && (splitSubMeshes || (totalVertices > 65535 && maxSubMeshVertices <= 65535))) { useOneBuffer_ = false; vertexBuffers_.Resize(numSubMeshes_); indexBuffers_.Resize(numSubMeshes_); } else { vertexBuffers_.Resize(1); indexBuffers_.Resize(1); } subMesh = subMeshes.GetChild("submesh"); unsigned indexStart = 0; unsigned vertexStart = 0; unsigned subMeshIndex = 0; PODVector<unsigned> vertexStarts; vertexStarts.Resize(numSubMeshes_); while (subMesh) { XMLElement geometry = subMesh.GetChild("geometry"); XMLElement faces = subMesh.GetChild("faces"); // If no submesh vertexbuffer, process the shared geometry, but do it only once unsigned vertices = 0; if (!geometry) { vertexStart = 0; if (!subMeshIndex) geometry = root.GetChild("sharedgeometry"); } if (geometry) vertices = geometry.GetInt("vertexcount"); ModelSubGeometryLodLevel subGeometryLodLevel; ModelVertexBuffer* vBuf; ModelIndexBuffer* iBuf; if (useOneBuffer_) { vBuf = &vertexBuffers_[0]; if (vertices) vBuf->vertices_.Resize(vertexStart + vertices); iBuf = &indexBuffers_[0]; subGeometryLodLevel.vertexBuffer_ = 0; subGeometryLodLevel.indexBuffer_ = 0; } else { vertexStart = 0; indexStart = 0; vBuf = &vertexBuffers_[subMeshIndex]; vBuf->vertices_.Resize(vertices); iBuf = &indexBuffers_[subMeshIndex]; subGeometryLodLevel.vertexBuffer_ = subMeshIndex; subGeometryLodLevel.indexBuffer_ = subMeshIndex; } // Store the start vertex for later use vertexStarts[subMeshIndex] = vertexStart; // Ogre may have multiple buffers in one submesh. These will be merged into one XMLElement bufferDef; if (geometry) bufferDef = geometry.GetChild("vertexbuffer"); while (bufferDef) { if (bufferDef.HasAttribute("positions")) vBuf->elementMask_ |= MASK_POSITION; if (bufferDef.HasAttribute("normals")) vBuf->elementMask_ |= MASK_NORMAL; if (bufferDef.HasAttribute("texture_coords")) { vBuf->elementMask_ |= MASK_TEXCOORD1; if (bufferDef.GetInt("texture_coords") > 1) vBuf->elementMask_ |= MASK_TEXCOORD2; } unsigned vertexNum = vertexStart; if (vertices) { XMLElement vertex = bufferDef.GetChild("vertex"); while (vertex) { XMLElement position = vertex.GetChild("position"); if (position) { // Convert from right- to left-handed float x = position.GetFloat("x"); float y = position.GetFloat("y"); float z = position.GetFloat("z"); Vector3 vec(x, y, -z); vBuf->vertices_[vertexNum].position_ = vec; boundingBox_.Merge(vec); } XMLElement normal = vertex.GetChild("normal"); if (normal) { // Convert from right- to left-handed float x = normal.GetFloat("x"); float y = normal.GetFloat("y"); float z = normal.GetFloat("z"); Vector3 vec(x, y, -z); vBuf->vertices_[vertexNum].normal_ = vec; } XMLElement uv = vertex.GetChild("texcoord"); if (uv) { float x = uv.GetFloat("u"); float y = uv.GetFloat("v"); Vector2 vec(x, y); vBuf->vertices_[vertexNum].texCoord1_ = vec; if (vBuf->elementMask_ & MASK_TEXCOORD2) { uv = uv.GetNext("texcoord"); if (uv) { float x = uv.GetFloat("u"); float y = uv.GetFloat("v"); Vector2 vec(x, y); vBuf->vertices_[vertexNum].texCoord2_ = vec; } } } vertexNum++; vertex = vertex.GetNext("vertex"); } } bufferDef = bufferDef.GetNext("vertexbuffer"); } unsigned triangles = faces.GetInt("count"); unsigned indices = triangles * 3; XMLElement triangle = faces.GetChild("face"); while (triangle) { unsigned v1 = triangle.GetInt("v1"); unsigned v2 = triangle.GetInt("v2"); unsigned v3 = triangle.GetInt("v3"); iBuf->indices_.Push(v3 + vertexStart); iBuf->indices_.Push(v2 + vertexStart); iBuf->indices_.Push(v1 + vertexStart); triangle = triangle.GetNext("face"); } subGeometryLodLevel.indexStart_ = indexStart; subGeometryLodLevel.indexCount_ = indices; if (vertexStart + vertices > 65535) iBuf->indexSize_ = sizeof(unsigned); XMLElement boneAssignments = subMesh.GetChild("boneassignments"); if (bones_.Size()) { if (boneAssignments) { XMLElement boneAssignment = boneAssignments.GetChild("vertexboneassignment"); while (boneAssignment) { unsigned vertex = boneAssignment.GetInt("vertexindex") + vertexStart; unsigned bone = boneAssignment.GetInt("boneindex"); float weight = boneAssignment.GetFloat("weight"); BoneWeightAssignment assign; assign.boneIndex_ = bone; assign.weight_ = weight; // Source data might have 0 weights. Disregard these if (assign.weight_ > 0.0f) { subGeometryLodLevel.boneWeights_[vertex].Push(assign); // Require skinning weight to be sufficiently large before vertex contributes to bone hitbox if (assign.weight_ > 0.33f) { // Check distance of vertex from bone to get bone max. radius information Vector3 bonePos = bones_[bone].derivedPosition_; Vector3 vertexPos = vBuf->vertices_[vertex].position_; float distance = (bonePos - vertexPos).Length(); if (distance > bones_[bone].radius_) { bones_[bone].collisionMask_ |= 1; bones_[bone].radius_ = distance; } // Build the hitbox for the bone bones_[bone].boundingBox_.Merge(bones_[bone].inverseWorldTransform_ * (vertexPos)); bones_[bone].collisionMask_ |= 2; } } boneAssignment = boneAssignment.GetNext("vertexboneassignment"); } } if ((subGeometryLodLevel.boneWeights_.Size()) && bones_.Size()) { vBuf->elementMask_ |= MASK_BLENDWEIGHTS | MASK_BLENDINDICES; bool sorted = false; // If amount of bones is larger than supported by HW skinning, must remap per submesh if (bones_.Size() > maxBones_) { HashMap<unsigned, unsigned> usedBoneMap; unsigned remapIndex = 0; for (HashMap<unsigned, PODVector<BoneWeightAssignment> >::Iterator i = subGeometryLodLevel.boneWeights_.Begin(); i != subGeometryLodLevel.boneWeights_.End(); ++i) { // Sort the bone assigns by weight Sort(i->second_.Begin(), i->second_.End(), CompareWeights); // Use only the first 4 weights for (unsigned j = 0; j < i->second_.Size() && j < 4; ++j) { unsigned originalIndex = i->second_[j].boneIndex_; if (!usedBoneMap.Contains(originalIndex)) { usedBoneMap[originalIndex] = remapIndex; remapIndex++; } i->second_[j].boneIndex_ = usedBoneMap[originalIndex]; } } // If still too many bones in one subgeometry, error if (usedBoneMap.Size() > maxBones_) ErrorExit("Too many bones (limit " + String(maxBones_) + ") in submesh " + String(subMeshIndex + 1)); // Write mapping of vertex buffer bone indices to original bone indices subGeometryLodLevel.boneMapping_.Resize(usedBoneMap.Size()); for (HashMap<unsigned, unsigned>::Iterator j = usedBoneMap.Begin(); j != usedBoneMap.End(); ++j) subGeometryLodLevel.boneMapping_[j->second_] = j->first_; sorted = true; } for (HashMap<unsigned, PODVector<BoneWeightAssignment> >::Iterator i = subGeometryLodLevel.boneWeights_.Begin(); i != subGeometryLodLevel.boneWeights_.End(); ++i) { // Sort the bone assigns by weight, if not sorted yet in bone remapping pass if (!sorted) Sort(i->second_.Begin(), i->second_.End(), CompareWeights); float totalWeight = 0.0f; float normalizationFactor = 0.0f; // Calculate normalization factor in case there are more than 4 blend weights, or they do not add up to 1 for (unsigned j = 0; j < i->second_.Size() && j < 4; ++j) totalWeight += i->second_[j].weight_; if (totalWeight > 0.0f) normalizationFactor = 1.0f / totalWeight; for (unsigned j = 0; j < i->second_.Size() && j < 4; ++j) { vBuf->vertices_[i->first_].blendIndices_[j] = i->second_[j].boneIndex_; vBuf->vertices_[i->first_].blendWeights_[j] = i->second_[j].weight_ * normalizationFactor; } // If there are less than 4 blend weights, fill rest with zero for (unsigned j = i->second_.Size(); j < 4; ++j) { vBuf->vertices_[i->first_].blendIndices_[j] = 0; vBuf->vertices_[i->first_].blendWeights_[j] = 0.0f; } vBuf->vertices_[i->first_].hasBlendWeights_ = true; } } } else if (boneAssignments) PrintLine("No skeleton loaded, skipping skinning information"); // Calculate center for the subgeometry Vector3 center = Vector3::ZERO; for (unsigned i = 0; i < iBuf->indices_.Size(); i += 3) { center += vBuf->vertices_[iBuf->indices_[i]].position_; center += vBuf->vertices_[iBuf->indices_[i + 1]].position_; center += vBuf->vertices_[iBuf->indices_[i + 2]].position_; } if (iBuf->indices_.Size()) center /= (float)iBuf->indices_.Size(); subGeometryCenters_.Push(center); indexStart += indices; vertexStart += vertices; OptimizeIndices(&subGeometryLodLevel, vBuf, iBuf); PrintLine("Processed submesh " + String(subMeshIndex + 1) + ": " + String(vertices) + " vertices " + String(triangles) + " triangles"); Vector<ModelSubGeometryLodLevel> thisSubGeometry; thisSubGeometry.Push(subGeometryLodLevel); subGeometries_.Push(thisSubGeometry); subMesh = subMesh.GetNext("submesh"); subMeshIndex++; } // Process LOD levels, if any XMLElement lods = root.GetChild("levelofdetail"); if (lods) { try { // For now, support only generated LODs, where the vertices are the same XMLElement lod = lods.GetChild("lodgenerated"); while (lod) { float distance = M_EPSILON; if (lod.HasAttribute("fromdepthsquared")) distance = sqrtf(lod.GetFloat("fromdepthsquared")); if (lod.HasAttribute("value")) distance = lod.GetFloat("value"); XMLElement lodSubMesh = lod.GetChild("lodfacelist"); while (lodSubMesh) { unsigned subMeshIndex = lodSubMesh.GetInt("submeshindex"); unsigned triangles = lodSubMesh.GetInt("numfaces"); ModelSubGeometryLodLevel newLodLevel; ModelSubGeometryLodLevel& originalLodLevel = subGeometries_[subMeshIndex][0]; // Copy all initial values newLodLevel = originalLodLevel; ModelVertexBuffer* vBuf; ModelIndexBuffer* iBuf; if (useOneBuffer_) { vBuf = &vertexBuffers_[0]; iBuf = &indexBuffers_[0]; } else { vBuf = &vertexBuffers_[subMeshIndex]; iBuf = &indexBuffers_[subMeshIndex]; } unsigned indexStart = iBuf->indices_.Size(); unsigned indexCount = triangles * 3; unsigned vertexStart = vertexStarts[subMeshIndex]; newLodLevel.distance_ = distance; newLodLevel.indexStart_ = indexStart; newLodLevel.indexCount_ = indexCount; // Append indices to the original index buffer XMLElement triangle = lodSubMesh.GetChild("face"); while (triangle) { unsigned v1 = triangle.GetInt("v1"); unsigned v2 = triangle.GetInt("v2"); unsigned v3 = triangle.GetInt("v3"); iBuf->indices_.Push(v3 + vertexStart); iBuf->indices_.Push(v2 + vertexStart); iBuf->indices_.Push(v1 + vertexStart); triangle = triangle.GetNext("face"); } OptimizeIndices(&newLodLevel, vBuf, iBuf); subGeometries_[subMeshIndex].Push(newLodLevel); PrintLine("Processed LOD level for submesh " + String(subMeshIndex + 1) + ": distance " + String(distance)); lodSubMesh = lodSubMesh.GetNext("lodfacelist"); } lod = lod.GetNext("lodgenerated"); } } catch (...) {} } // Process poses/morphs // First find out all pose definitions if (exportMorphs) { try { Vector<XMLElement> poses; XMLElement posesRoot = root.GetChild("poses"); if (posesRoot) { XMLElement pose = posesRoot.GetChild("pose"); while (pose) { poses.Push(pose); pose = pose.GetNext("pose"); } } // Then process animations using the poses XMLElement animsRoot = root.GetChild("animations"); if (animsRoot) { XMLElement anim = animsRoot.GetChild("animation"); while (anim) { String name = anim.GetAttribute("name"); float length = anim.GetFloat("length"); HashSet<unsigned> usedPoses; XMLElement tracks = anim.GetChild("tracks"); if (tracks) { XMLElement track = tracks.GetChild("track"); while (track) { XMLElement keyframes = track.GetChild("keyframes"); if (keyframes) { XMLElement keyframe = keyframes.GetChild("keyframe"); while (keyframe) { float time = keyframe.GetFloat("time"); XMLElement poseref = keyframe.GetChild("poseref"); // Get only the end pose if (poseref && time == length) usedPoses.Insert(poseref.GetInt("poseindex")); keyframe = keyframe.GetNext("keyframe"); } } track = track.GetNext("track"); } } if (usedPoses.Size()) { ModelMorph newMorph; newMorph.name_ = name; if (useOneBuffer_) newMorph.buffers_.Resize(1); else newMorph.buffers_.Resize(usedPoses.Size()); unsigned bufIndex = 0; for (HashSet<unsigned>::Iterator i = usedPoses.Begin(); i != usedPoses.End(); ++i) { XMLElement pose = poses[*i]; unsigned targetSubMesh = pose.GetInt("index"); XMLElement poseOffset = pose.GetChild("poseoffset"); if (useOneBuffer_) newMorph.buffers_[bufIndex].vertexBuffer_ = 0; else newMorph.buffers_[bufIndex].vertexBuffer_ = targetSubMesh; newMorph.buffers_[bufIndex].elementMask_ = MASK_POSITION; ModelVertexBuffer* vBuf = &vertexBuffers_[newMorph.buffers_[bufIndex].vertexBuffer_]; while (poseOffset) { // Convert from right- to left-handed unsigned vertexIndex = poseOffset.GetInt("index") + vertexStarts[targetSubMesh]; float x = poseOffset.GetFloat("x"); float y = poseOffset.GetFloat("y"); float z = poseOffset.GetFloat("z"); Vector3 vec(x, y, -z); if (vBuf->morphCount_ == 0) { vBuf->morphStart_ = vertexIndex; vBuf->morphCount_ = 1; } else { unsigned first = vBuf->morphStart_; unsigned last = first + vBuf->morphCount_ - 1; if (vertexIndex < first) first = vertexIndex; if (vertexIndex > last) last = vertexIndex; vBuf->morphStart_ = first; vBuf->morphCount_ = last - first + 1; } ModelVertex newVertex; newVertex.position_ = vec; newMorph.buffers_[bufIndex].vertices_.Push(MakePair(vertexIndex, newVertex)); poseOffset = poseOffset.GetNext("poseoffset"); } if (!useOneBuffer_) ++bufIndex; } morphs_.Push(newMorph); PrintLine("Processed morph " + name + " with " + String(usedPoses.Size()) + " sub-poses"); } anim = anim.GetNext("animation"); } } } catch (...) {} } // Check any of the buffers for vertices with missing blend weight assignments for (unsigned i = 0; i < vertexBuffers_.Size(); ++i) { if (vertexBuffers_[i].elementMask_ & MASK_BLENDWEIGHTS) { for (unsigned j = 0; j < vertexBuffers_[i].vertices_.Size(); ++j) if (!vertexBuffers_[i].vertices_[j].hasBlendWeights_) ErrorExit("Found a vertex with missing skinning information"); } } // Tangent generation if (generateTangents) { for (unsigned i = 0; i < subGeometries_.Size(); ++i) { for (unsigned j = 0; j < subGeometries_[i].Size(); ++j) { ModelVertexBuffer& vBuf = vertexBuffers_[subGeometries_[i][j].vertexBuffer_]; ModelIndexBuffer& iBuf = indexBuffers_[subGeometries_[i][j].indexBuffer_]; unsigned indexStart = subGeometries_[i][j].indexStart_; unsigned indexCount = subGeometries_[i][j].indexCount_; // If already has tangents, do not regenerate if (vBuf.elementMask_ & MASK_TANGENT || vBuf.vertices_.Empty() || iBuf.indices_.Empty()) continue; vBuf.elementMask_ |= MASK_TANGENT; if ((vBuf.elementMask_ & (MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1)) != (MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1)) ErrorExit("To generate tangents, positions normals and texcoords are required"); GenerateTangents(&vBuf.vertices_[0], sizeof(ModelVertex), &iBuf.indices_[0], sizeof(unsigned), indexStart, indexCount, offsetof(ModelVertex, normal_), offsetof(ModelVertex, texCoord1_), offsetof(ModelVertex, tangent_)); PrintLine("Generated tangents"); } } } }
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); } }
int main() { #ifdef _MSC_VER _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif printf("Size of String: %d\n", sizeof(String)); printf("Size of Vector: %d\n", sizeof(Vector<int>)); printf("Size of List: %d\n", sizeof(List<int>)); printf("Size of HashMap: %d\n", sizeof(HashMap<int, int>)); printf("Size of RefCounted: %d\n", sizeof(RefCounted)); { printf("\nTesting AutoPtr assignment\n"); AutoPtr<Test> ptr1(new Test); AutoPtr<Test> ptr2; ptr2 = ptr1; } { printf("\nTesting AutoPtr copy construction\n"); AutoPtr<Test> ptr1(new Test); AutoPtr<Test> ptr2(ptr1); } { printf("\nTesting AutoPtr detaching\n"); AutoPtr<Test> ptr1(new Test); // We would now have a memory leak if we don't manually delete the object Test* object = ptr1.Detach(); delete object; } { printf("\nTesting AutoPtr inside a vector\n"); Vector<AutoPtr<Test> > vec; printf("Filling vector\n"); for (size_t i = 0; i < 4; ++i) vec.Push(new Test()); printf("Clearing vector\n"); vec.Clear(); } { printf("\nTesting SharedPtr\n"); SharedPtr<TestRefCounted> ptr1(new TestRefCounted); SharedPtr<TestRefCounted> ptr2(ptr1); printf("Number of refs: %d\n", ptr1.Refs()); } { printf("\nTesting WeakPtr\n"); TestRefCounted* object = new TestRefCounted; WeakPtr<TestRefCounted> ptr1(object); WeakPtr<TestRefCounted> ptr2(ptr1); printf("Number of weak refs: %d expired: %d\n", ptr1.WeakRefs(), ptr1.IsExpired()); ptr2.Reset(); delete object; printf("Number of weak refs: %d expired: %d\n", ptr1.WeakRefs(), ptr1.IsExpired()); } { printf("\nTesting Vector\n"); HiresTimer t; Vector<int> vec; SetRandomSeed(0); for (size_t i = 0; i < NUM_ITEMS; ++i) vec.Push(Rand()); int sum = 0; int count = 0; for (auto it = vec.Begin(); it != vec.End(); ++it) { sum += *it; ++count; } int usec = (int)t.ElapsedUSec(); printf("Size: %d capacity: %d\n", vec.Size(), vec.Capacity()); printf("Counted vector items %d, sum: %d\n", count, sum); printf("Processing took %d usec\n", usec); } { printf("\nTesting List\n"); HiresTimer t; List<int> list; SetRandomSeed(0); for (size_t i = 0; i < NUM_ITEMS; ++i) list.Push(Rand()); int sum = 0; int count = 0; for (auto it = list.Begin(); it != list.End(); ++it) { sum += *it; ++count; } int usec = (int)t.ElapsedUSec(); printf("Size: %d\n", list.Size()); printf("Counted list items %d, sum: %d\n", count, sum); printf("Processing took %d usec\n", usec); printf("\nTesting List insertion\n"); List<int> list2; List<int> list3; for (int i = 0; i < 10; ++i) list3.Push(i); list2.Insert(list2.End(), list3); for (auto it = list2.Begin(); it != list2.End(); ++it) printf("%d ", *it); printf("\n"); } { printf("\nTesting String\n"); HiresTimer t; String test; for (size_t i = 0; i < NUM_ITEMS/4; ++i) test += "Test"; String test2; test2.AppendWithFormat("Size: %d capacity: %d\n", test.Length(), test.Capacity()); printf(test2.CString()); test2 = test2.ToUpper(); printf(test2.CString()); test2.Replace("SIZE:", "LENGTH:"); printf(test2.CString()); int usec = (int)t.ElapsedUSec(); printf("Processing took %d usec\n", usec); } { printf("\nTesting HashSet\n"); HiresTimer t; size_t found = 0; unsigned sum = 0; HashSet<int> testHashSet; srand(0); found = 0; sum = 0; printf("Insert, search and iteration, %d keys\n", NUM_ITEMS); for (size_t i = 0; i < NUM_ITEMS; ++i) { int number = (rand() & 32767); testHashSet.Insert(number); } for (int i = 0; i < 32768; ++i) { if (testHashSet.Find(i) != testHashSet.End()) ++found; } for (auto it = testHashSet.Begin(); it != testHashSet.End(); ++it) sum += *it; int usec = (int)t.ElapsedUSec(); printf("Set size and sum: %d %d\n", testHashSet.Size(), sum); printf("Processing took %d usec\n", usec); } { printf("\nTesting HashMap\n"); HashMap<int, int> testHashMap; for (int i = 0; i < 10; ++i) testHashMap.Insert(MakePair(i, rand() & 32767)); printf("Keys: "); Vector<int> keys = testHashMap.Keys(); for (size_t i = 0; i < keys.Size(); ++i) printf("%d ", keys[i]); printf("\n"); printf("Values: "); Vector<int> values = testHashMap.Values(); for (size_t i = 0; i < values.Size(); ++i) printf("%d ", values[i]); printf("\n"); } return 0; }
bool triSurface::readNAS(const fileName& fName) { IFstream is(fName); if (!is.good()) { FatalErrorIn("triSurface::readNAS(const fileName&)") << "Cannot read file " << fName << exit(FatalError); } // coordinates of point DynamicList<point> points; // Nastran index of point DynamicList<label> indices; // Faces in terms of Nastran point indices DynamicList<labelledTri> faces; // From face group to patch Map<label> groupToPatch; label nPatches = 0; // Name for face group Map<word> groupToName; // Ansa tags. Denoted by $ANSA_NAME. These will appear just before the // first use of a type. We read them and store the pshell types which // are used to name the patches. label ansaId = -1; word ansaType; string ansaName; // A single warning per unrecognized command HashSet<word> unhandledCmd; while (is.good()) { string line; is.getLine(line); // Ansa extension if (line.substr(0, 10) == "$ANSA_NAME") { string::size_type sem0 = line.find (';', 0); string::size_type sem1 = line.find (';', sem0+1); string::size_type sem2 = line.find (';', sem1+1); if ( sem0 != string::npos && sem1 != string::npos && sem2 != string::npos ) { ansaId = readLabel ( IStringStream(line.substr(sem0+1, sem1-sem0-1))() ); ansaType = line.substr(sem1+1, sem2-sem1-1); string nameString; is.getLine(ansaName); if (ansaName[ansaName.size()-1] == '\r') { ansaName = ansaName.substr(1, ansaName.size()-2); } else { ansaName = ansaName.substr(1, ansaName.size()-1); } // Info<< "ANSA tag for NastranID:" << ansaId // << " of type " << ansaType // << " name " << ansaName << endl; } } // Hypermesh extension // $HMNAME COMP 1"partName" if ( line.substr(0, 12) == "$HMNAME COMP" && line.find ('"') != string::npos ) { label groupId = readLabel ( IStringStream(line.substr(16, 16))() ); IStringStream lineStream(line.substr(32)); string rawName; lineStream >> rawName; groupToName.insert(groupId, string::validate<word>(rawName)); Info<< "group " << groupId << " => " << rawName << endl; } if (line.empty() || line[0] == '$') { // Skip empty or comment continue; } // Check if character 72 is continuation if (line.size() > 72 && line[72] == '+') { line = line.substr(0, 72); while (true) { string buf; is.getLine(buf); if (buf.size() > 72 && buf[72]=='+') { line += buf.substr(8, 64); } else { line += buf.substr(8, buf.size()-8); break; } } } // Read first word IStringStream lineStream(line); word cmd; lineStream >> cmd; if (cmd == "CTRIA3") { label groupId = readLabel(IStringStream(line.substr(16,8))()); label a = readLabel(IStringStream(line.substr(24,8))()); label b = readLabel(IStringStream(line.substr(32,8))()); label c = readLabel(IStringStream(line.substr(40,8))()); // Convert group into patch Map<label>::const_iterator iter = groupToPatch.find(groupId); label patchI; if (iter == groupToPatch.end()) { patchI = nPatches++; groupToPatch.insert(groupId, patchI); Info<< "patch " << patchI << " => group " << groupId << endl; } else { patchI = iter(); } faces.append(labelledTri(a, b, c, patchI)); } else if (cmd == "CQUAD4") { label groupId = readLabel(IStringStream(line.substr(16,8))()); label a = readLabel(IStringStream(line.substr(24,8))()); label b = readLabel(IStringStream(line.substr(32,8))()); label c = readLabel(IStringStream(line.substr(40,8))()); label d = readLabel(IStringStream(line.substr(48,8))()); // Convert group into patch Map<label>::const_iterator iter = groupToPatch.find(groupId); label patchI; if (iter == groupToPatch.end()) { patchI = nPatches++; groupToPatch.insert(groupId, patchI); Info<< "patch " << patchI << " => group " << groupId << endl; } else { patchI = iter(); } faces.append(labelledTri(a, b, c, patchI)); faces.append(labelledTri(c, d, a, patchI)); } else if (cmd == "PSHELL") { // Read shell type since group gives patchnames label groupId = readLabel(IStringStream(line.substr(8,8))()); if (groupId == ansaId && ansaType == "PSHELL") { groupToName.insert(groupId, string::validate<word>(ansaName)); Info<< "group " << groupId << " => " << ansaName << endl; } } else if (cmd == "GRID") { label index = readLabel(IStringStream(line.substr(8,8))()); scalar x = parseNASCoord(line.substr(24, 8)); scalar y = parseNASCoord(line.substr(32, 8)); scalar z = parseNASCoord(line.substr(40, 8)); indices.append(index); points.append(point(x, y, z)); } else if (cmd == "GRID*") { // Long format is on two lines with '*' continuation symbol // on start of second line. // Typical line (spaces compacted) // GRID* 126 0 -5.55999875E+02 -5.68730474E+02 // * 2.14897901E+02 label index = readLabel(IStringStream(line.substr(8,16))()); scalar x = parseNASCoord(line.substr(40, 16)); scalar y = parseNASCoord(line.substr(56, 16)); is.getLine(line); if (line[0] != '*') { FatalErrorIn("triSurface::readNAS(const fileName&)") << "Expected continuation symbol '*' when reading GRID*" << " (double precision coordinate) output" << nl << "Read:" << line << nl << "File:" << is.name() << " line:" << is.lineNumber() << exit(FatalError); } scalar z = parseNASCoord(line.substr(8, 16)); indices.append(index); points.append(point(x, y, z)); } else if (unhandledCmd.insert(cmd)) { Info<< "Unhandled Nastran command " << line << nl << "File:" << is.name() << " line:" << is.lineNumber() << endl; } }
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)); }
// 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 plug-in. if (url.isEmpty() && !urlParameter.isEmpty()) { KURL completedURL = document().completeURL(urlParameter); bool useFallback; if (shouldUsePlugin(completedURL, serviceType, false, useFallback)) url = urlParameter; } }
static void testU32Set() { HashSet<U32> set; enum { maxI = 1024 * 1024 }; for(Uptr i = 0;i < maxI;++i) { errorUnless(!set.contains(U32(i))); } errorUnless(set.size() == 0); for(Uptr i = 0;i < maxI;++i) { errorUnless(!set.contains(U32(i))); errorUnless(!set.get(U32(i))); errorUnless(set.add(U32(i))); errorUnless(set.contains(U32(i))); errorUnless(set.get(U32(i))); errorUnless(set.size() == i + 1); } for(Uptr i = 0;i < maxI;++i) { errorUnless(set.contains(U32(i))); errorUnless(set.remove(U32(i))); errorUnless(!set.contains(U32(i))); errorUnless(set.size() == maxI - i - 1); } for(Uptr i = 0;i < maxI;++i) { errorUnless(!set.contains(U32(i))); } }
static PassRefPtr<InspectorObject> buildObjectForElementInfo(Node* node) { if (!node->isElementNode() || !node->document().frame()) return nullptr; RefPtr<InspectorObject> elementInfo = InspectorObject::create(); Element* element = toElement(node); bool isXHTML = element->document().isXHTMLDocument(); elementInfo->setString("tagName", isXHTML ? element->nodeName() : element->nodeName().lower()); elementInfo->setString("idValue", element->getIdAttribute()); HashSet<AtomicString> usedClassNames; if (element->hasClass() && element->isStyledElement()) { StringBuilder classNames; const SpaceSplitString& classNamesString = toStyledElement(element)->classNames(); size_t classNameCount = classNamesString.size(); for (size_t i = 0; i < classNameCount; ++i) { const AtomicString& className = classNamesString[i]; if (usedClassNames.contains(className)) continue; usedClassNames.add(className); classNames.append('.'); classNames.append(className); } elementInfo->setString("className", classNames.toString()); } RenderElement* renderer = element->renderer(); Frame* containingFrame = node->document().frame(); FrameView* containingView = containingFrame->view(); IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect())); RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : nullptr; elementInfo->setString("nodeWidth", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), *modelObject) : boundingBox.width())); elementInfo->setString("nodeHeight", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), *modelObject) : boundingBox.height())); if (renderer->isRenderNamedFlowFragmentContainer()) { RenderNamedFlowFragment* region = toRenderBlockFlow(renderer)->renderNamedFlowFragment(); if (region->isValid()) { RenderFlowThread* flowThread = region->flowThread(); ASSERT(flowThread && flowThread->isRenderNamedFlowThread()); RefPtr<InspectorObject> regionFlowInfo = InspectorObject::create(); regionFlowInfo->setString("name", toRenderNamedFlowThread(flowThread)->flowThreadName()); regionFlowInfo->setArray("regions", buildObjectForCSSRegionsHighlight(region, flowThread)); elementInfo->setObject("regionFlowInfo", regionFlowInfo.release()); } } RenderFlowThread* containingFlowThread = renderer->flowThreadContainingBlock(); if (containingFlowThread && containingFlowThread->isRenderNamedFlowThread()) { RefPtr<InspectorObject> contentFlowInfo = InspectorObject::create(); contentFlowInfo->setString("name", toRenderNamedFlowThread(containingFlowThread)->flowThreadName()); elementInfo->setObject("contentFlowInfo", contentFlowInfo.release()); } #if ENABLE(CSS_SHAPES) if (renderer->isBox()) { RenderBox* renderBox = toRenderBox(renderer); if (RefPtr<InspectorObject> shapeObject = buildObjectForShapeOutside(containingFrame, renderBox)) elementInfo->setObject("shapeOutsideInfo", shapeObject.release()); } #endif // Need to enable AX to get the computed role. if (!WebCore::AXObjectCache::accessibilityEnabled()) WebCore::AXObjectCache::enableAccessibility(); if (AXObjectCache* axObjectCache = node->document().axObjectCache()) { if (AccessibilityObject* axObject = axObjectCache->getOrCreate(node)) elementInfo->setString("role", axObject->computedRoleString()); } return elementInfo.release(); }
bool PluginDatabase::refresh() { #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) if (!m_persistentMetadataCacheIsLoaded) loadPersistentMetadataCache(); #endif bool pluginSetChanged = false; if (!m_plugins.isEmpty()) { PluginSet pluginsToUnload; getDeletedPlugins(pluginsToUnload); // Unload plugins PluginSet::const_iterator end = pluginsToUnload.end(); for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it) remove(it->get()); pluginSetChanged = !pluginsToUnload.isEmpty(); } HashSet<String> paths; getPluginPathsInDirectories(paths); HashMap<String, time_t> pathsWithTimes; // We should only skip unchanged files if we didn't remove any plugins above. If we did remove // any plugins, we need to look at every plugin file so that, e.g., if the user has two versions // of RealPlayer installed and just removed the newer one, we'll pick up the older one. bool shouldSkipUnchangedFiles = !pluginSetChanged; HashSet<String>::const_iterator pathsEnd = paths.end(); for (HashSet<String>::const_iterator it = paths.begin(); it != pathsEnd; ++it) { time_t lastModified; if (!getFileModificationTime(*it, lastModified)) continue; pathsWithTimes.add(*it, lastModified); // If the path's timestamp hasn't changed since the last time we ran refresh(), we don't have to do anything. if (shouldSkipUnchangedFiles && m_pluginPathsWithTimes.get(*it) == lastModified) continue; if (RefPtr<PluginPackage> oldPackage = m_pluginsByPath.get(*it)) { ASSERT(!shouldSkipUnchangedFiles || oldPackage->lastModified() != lastModified); remove(oldPackage.get()); } RefPtr<PluginPackage> package = PluginPackage::createPackage(*it, lastModified); if (package && add(package.release())) pluginSetChanged = true; } // Cache all the paths we found with their timestamps for next time. pathsWithTimes.swap(m_pluginPathsWithTimes); if (!pluginSetChanged) return false; #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) updatePersistentMetadataCache(); #endif m_registeredMIMETypes.clear(); // Register plug-in MIME types PluginSet::const_iterator end = m_plugins.end(); for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { // Get MIME types MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end(); for (; map_it != map_end; ++map_it) m_registeredMIMETypes.add(map_it->first); } return true; }
void Object::SendEvent(StringHash eventType, VariantMap& eventData) { if (!Thread::IsMainThread()) { LOGERROR("Sending events is only supported from the main thread"); return; } // Make a weak pointer to self to check for destruction during event handling WeakPtr<Object> self(this); Context* context = context_; HashSet<Object*> processed; context->BeginSendEvent(this); // Check first the specific event receivers const HashSet<Object*>* group = context->GetEventReceivers(this, eventType); if (group) { for (HashSet<Object*>::ConstIterator i = group->Begin(); i != group->End();) { HashSet<Object*>::ConstIterator current = i++; Object* receiver = *current; Object* next = 0; if (i != group->End()) next = *i; unsigned oldSize = group->Size(); receiver->OnEvent(this, eventType, eventData); // If self has been destroyed as a result of event handling, exit if (self.Expired()) { context->EndSendEvent(); return; } // If group has changed size during iteration (removed/added subscribers) try to recover /// \todo This is not entirely foolproof, as a subscriber could have been added to make up for the removed one if (group->Size() != oldSize) i = group->Find(next); processed.Insert(receiver); } } // Then the non-specific receivers group = context->GetEventReceivers(eventType); if (group) { if (processed.Empty()) { for (HashSet<Object*>::ConstIterator i = group->Begin(); i != group->End();) { HashSet<Object*>::ConstIterator current = i++; Object* receiver = *current; Object* next = 0; if (i != group->End()) next = *i; unsigned oldSize = group->Size(); receiver->OnEvent(this, eventType, eventData); if (self.Expired()) { context->EndSendEvent(); return; } if (group->Size() != oldSize) i = group->Find(next); } } else { // If there were specific receivers, check that the event is not sent doubly to them for (HashSet<Object*>::ConstIterator i = group->Begin(); i != group->End();) { HashSet<Object*>::ConstIterator current = i++; Object* receiver = *current; Object* next = 0; if (i != group->End()) next = *i; if (!processed.Contains(receiver)) { unsigned oldSize = group->Size(); receiver->OnEvent(this, eventType, eventData); if (self.Expired()) { context->EndSendEvent(); return; } if (group->Size() != oldSize) i = group->Find(next); } } } } context->EndSendEvent(); }
void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) { bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start); bool transformChanged = transformToRootChanged(start); bool hasSVGShadow = rendererHasSVGShadow(start); bool needsBoundariesUpdate = start->needsBoundariesUpdate(); HashSet<RenderObject*> notlayoutedObjects; for (RenderObject* child = start->firstChildSlow(); child; child = child->nextSibling()) { bool needsLayout = selfNeedsLayout; bool childEverHadLayout = child->everHadLayout(); if (needsBoundariesUpdate && hasSVGShadow) { // If we have a shadow, our shadow is baked into our children's cached boundaries, // so they need to update. child->setNeedsBoundariesUpdate(); needsLayout = true; } if (transformChanged) { // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true). if (child->isSVGText()) toRenderSVGText(child)->setNeedsTextMetricsUpdate(); needsLayout = true; } if (layoutSizeChanged) { // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) { if (element->hasRelativeLengths()) { // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object if (child->isSVGShape()) toRenderSVGShape(child)->setNeedsShapeUpdate(); else if (child->isSVGText()) { toRenderSVGText(child)->setNeedsTextMetricsUpdate(); toRenderSVGText(child)->setNeedsPositioningValuesUpdate(); } needsLayout = true; } } } if (needsLayout) child->setNeedsLayout(MarkOnlyThis); if (child->needsLayout()) { toRenderElement(child)->layout(); // Renderers are responsible for repainting themselves when changing, except // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds. // We could handle this in the individual objects, but for now it's easier to have // parent containers call repaint(). (RenderBlock::layout* has similar logic.) if (!childEverHadLayout) child->repaint(); } else if (layoutSizeChanged) notlayoutedObjects.add(child); ASSERT(!child->needsLayout()); } if (!layoutSizeChanged) { ASSERT(notlayoutedObjects.isEmpty()); return; } // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path. HashSet<RenderObject*>::iterator end = notlayoutedObjects.end(); for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it) invalidateResourcesOfChildren(*it); }
// 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. if (hasAttributes()) { for (unsigned i = 0; i < attributeCount(); ++i) { Attribute* it = 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 SharedWorkerProxy::postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL) { MutexLocker lock(m_workerDocumentsLock); for (HashSet<Document*>::iterator iter = m_workerDocuments.begin(); iter != m_workerDocuments.end(); ++iter) (*iter)->postTask(createCallbackTask(&postExceptionTask, errorMessage, lineNumber, sourceURL)); }
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()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Invalid url for WebSocket " + m_url.string(), 0, scriptExecutionContext()->securityOrigin()->toString(), 0); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) { scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong url scheme for WebSocket " + m_url.string(), 0, scriptExecutionContext()->securityOrigin()->toString(), 0); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (m_url.hasFragmentIdentifier()) { scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "URL has fragment component " + m_url.string(), 0, scriptExecutionContext()->securityOrigin()->toString(), 0); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!portAllowed(m_url)) { scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "WebSocket port " + String::number(m_url.port()) + " blocked", 0, scriptExecutionContext()->securityOrigin()->toString(), 0); m_state = CLOSED; ec = SECURITY_ERR; return; } if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectFromSource(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()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(protocolString) + "'", 0, scriptExecutionContext()->securityOrigin()->toString(), 0); 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()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(protocols[i]) + "'", 0, scriptExecutionContext()->securityOrigin()->toString(), 0); 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()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "WebSocket protocols contain duplicates: '" + encodeProtocolString(protocols[i]) + "'", 0, scriptExecutionContext()->securityOrigin()->toString(), 0); m_state = CLOSED; ec = SYNTAX_ERR; return; } visited.add(protocols[i]); } if (!protocols.isEmpty()) protocolString = joinStrings(protocols, ", "); } m_channel->connect(m_url, protocolString); ActiveDOMObject::setPendingActivity(this); }
void SharedWorkerProxy::postConsoleMessageToWorkerObject(MessageDestination destination, MessageSource source, MessageType type, MessageLevel level, const String& message, int lineNumber, const String& sourceURL) { MutexLocker lock(m_workerDocumentsLock); for (HashSet<Document*>::iterator iter = m_workerDocuments.begin(); iter != m_workerDocuments.end(); ++iter) (*iter)->postTask(createCallbackTask(&postConsoleMessageTask, destination, source, type, level, message, lineNumber, sourceURL)); }
void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) { bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start); bool transformChanged = transformToRootChanged(start); HashSet<RenderObject*> notlayoutedObjects; for (RenderObject* child = start->slowFirstChild(); child; child = child->nextSibling()) { bool needsLayout = selfNeedsLayout; bool childEverHadLayout = child->everHadLayout(); if (transformChanged) { // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true). if (child->isSVGText()) toRenderSVGText(child)->setNeedsTextMetricsUpdate(); needsLayout = true; } if (layoutSizeChanged) { // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) { if (element->hasRelativeLengths()) { // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object if (child->isSVGShape()) { toRenderSVGShape(child)->setNeedsShapeUpdate(); } else if (child->isSVGText()) { toRenderSVGText(child)->setNeedsTextMetricsUpdate(); toRenderSVGText(child)->setNeedsPositioningValuesUpdate(); } needsLayout = true; } } } SubtreeLayoutScope layoutScope(*child); // Resource containers are nasty: they can invalidate clients outside the current SubtreeLayoutScope. // Since they only care about viewport size changes (to resolve their relative lengths), we trigger // their invalidation directly from SVGSVGElement::svgAttributeChange() or at a higher // SubtreeLayoutScope (in RenderView::layout()). if (needsLayout && !child->isSVGResourceContainer()) layoutScope.setNeedsLayout(child); layoutResourcesIfNeeded(child); if (child->needsLayout()) { child->layout(); // Renderers are responsible for repainting themselves when changing, except // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds. // We could handle this in the individual objects, but for now it's easier to have // parent containers call repaint(). (RenderBlock::layout* has similar logic.) if (!childEverHadLayout && !RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) child->paintInvalidationForWholeRenderer(); } else if (layoutSizeChanged) { notlayoutedObjects.add(child); } } if (!layoutSizeChanged) { ASSERT(notlayoutedObjects.isEmpty()); return; } // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path. HashSet<RenderObject*>::iterator end = notlayoutedObjects.end(); for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it) invalidateResourcesOfChildren(*it); }
// 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); } }
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 = URL(URL(), url); if (!m_url.isValid()) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Invalid url for WebSocket " + m_url.stringCenterEllipsizedToLength()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Wrong url scheme for WebSocket " + m_url.stringCenterEllipsizedToLength()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (m_url.hasFragmentIdentifier()) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "URL has fragment component " + m_url.stringCenterEllipsizedToLength()); m_state = CLOSED; ec = SYNTAX_ERR; return; } if (!portAllowed(m_url)) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "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 (is<Document>(*scriptExecutionContext())) { Document& document = downcast<Document>(*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 = ThreadableWebSocketChannel::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 (auto& protocol : protocols) { if (!isValidProtocolString(protocol)) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "Wrong protocol for WebSocket '" + encodeProtocolString(protocol) + "'"); m_state = CLOSED; ec = SYNTAX_ERR; return; } } HashSet<String> visited; for (auto& protocol : protocols) { if (!visited.add(protocol).isNewEntry) { scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, "WebSocket protocols contain duplicates: '" + encodeProtocolString(protocol) + "'"); m_state = CLOSED; ec = SYNTAX_ERR; return; } } if (is<Document>(*scriptExecutionContext())) { Document& document = downcast<Document>(*scriptExecutionContext()); if (!document.frame()->loader().mixedContentChecker().canRunInsecureContent(document.securityOrigin(), m_url)) { // Balanced by the call to ActiveDOMObject::unsetPendingActivity() in WebSocket::stop(). ActiveDOMObject::setPendingActivity(this); // We must block this connection. Instead of throwing an exception, we indicate this // using the error event. But since this code executes as part of the WebSocket's // constructor, we have to wait until the constructor has completed before firing the // event; otherwise, users can't connect to the event. RunLoop::main().dispatch([this]() { dispatchEvent(Event::create(eventNames().errorEvent, false, false)); stop(); }); return; } } String protocolString; if (!protocols.isEmpty()) protocolString = joinStrings(protocols, subProtocolSeperator()); m_channel->connect(m_url, protocolString); ActiveDOMObject::setPendingActivity(this); }
void WebsiteDataStore::removeData(WebsiteDataTypes dataTypes, std::chrono::system_clock::time_point modifiedSince, std::function<void ()> completionHandler) { struct CallbackAggregator : public RefCounted<CallbackAggregator> { explicit CallbackAggregator (std::function<void ()> completionHandler) : completionHandler(WTF::move(completionHandler)) { } void addPendingCallback() { pendingCallbacks++; } void removePendingCallback() { ASSERT(pendingCallbacks); --pendingCallbacks; callIfNeeded(); } void callIfNeeded() { if (!pendingCallbacks) RunLoop::main().dispatch(WTF::move(completionHandler)); } unsigned pendingCallbacks = 0; std::function<void ()> completionHandler; }; RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTF::move(completionHandler))); auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, isNonPersistent()); if (networkProcessAccessType != ProcessAccessType::None) { HashSet<WebProcessPool*> processPools; for (auto& process : processes()) processPools.add(&process->processPool()); for (auto& processPool : processPools) { switch (networkProcessAccessType) { case ProcessAccessType::OnlyIfLaunched: if (!processPool->networkProcess()) continue; break; case ProcessAccessType::Launch: processPool->ensureNetworkProcess(); break; case ProcessAccessType::None: ASSERT_NOT_REACHED(); } callbackAggregator->addPendingCallback(); processPool->networkProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] { callbackAggregator->removePendingCallback(); }); } } auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, isNonPersistent()); if (webProcessAccessType != ProcessAccessType::None) { for (auto& process : processes()) { switch (webProcessAccessType) { case ProcessAccessType::OnlyIfLaunched: if (!process->canSendMessage()) continue; break; case ProcessAccessType::Launch: // FIXME: Handle this. ASSERT_NOT_REACHED(); break; case ProcessAccessType::None: ASSERT_NOT_REACHED(); } callbackAggregator->addPendingCallback(); process->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] { callbackAggregator->removePendingCallback(); }); } } if (dataTypes & WebsiteDataTypeLocalStorage && m_storageManager) { callbackAggregator->addPendingCallback(); m_storageManager->deleteLocalStorageOriginsModifiedSince(modifiedSince, [callbackAggregator] { callbackAggregator->removePendingCallback(); }); } // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away. callbackAggregator->callIfNeeded(); }