TEST(InvalidationSetTest, SubtreeInvalid_AddCustomPseudoBefore) { RefPtr<InvalidationSet> set = DescendantInvalidationSet::create(); set->setCustomPseudoInvalid(); ASSERT_FALSE(set->isEmpty()); set->setWholeSubtreeInvalid(); ASSERT_TRUE(set->isEmpty()); }
void ResourceRequest::doUpdatePlatformHTTPBody() { CFMutableURLRequestRef cfRequest; RetainPtr<CFURLRef> url(AdoptCF, ResourceRequest::url().createCFURL()); RetainPtr<CFURLRef> firstPartyForCookies(AdoptCF, ResourceRequest::firstPartyForCookies().createCFURL()); if (m_cfRequest) { cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get()); CFURLRequestSetURL(cfRequest, url.get()); CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get()); CFURLRequestSetCachePolicy(cfRequest, (CFURLRequestCachePolicy)cachePolicy()); CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval()); } else cfRequest = CFURLRequestCreateMutable(0, url.get(), (CFURLRequestCachePolicy)cachePolicy(), timeoutInterval(), firstPartyForCookies.get()); RefPtr<FormData> formData = httpBody(); if (formData && !formData->isEmpty()) WebCore::setHTTPBody(cfRequest, formData); if (RetainPtr<CFReadStreamRef> bodyStream = adoptCF(CFURLRequestCopyHTTPRequestBodyStream(cfRequest))) { // For streams, provide a Content-Length to avoid using chunked encoding, and to get accurate total length in callbacks. RetainPtr<CFStringRef> lengthString = adoptCF(static_cast<CFStringRef>(CFReadStreamCopyProperty(bodyStream.get(), formDataStreamLengthPropertyName()))); if (lengthString) { CFURLRequestSetHTTPHeaderFieldValue(cfRequest, CFSTR("Content-Length"), lengthString.get()); // Since resource request is already marked updated, we need to keep it up to date too. ASSERT(m_resourceRequestUpdated); m_httpHeaderFields.set("Content-Length", lengthString.get()); } } m_cfRequest.adoptCF(cfRequest); #if PLATFORM(MAC) updateNSURLRequest(); #endif }
void SVGRenderSupport::applyStrokeStyleToStrokeData(StrokeData* strokeData, const RenderStyle* style, const RenderObject* object) { ASSERT(strokeData); ASSERT(style); ASSERT(object); ASSERT(object->node()); ASSERT(object->node()->isSVGElement()); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); strokeData->setThickness(svgStyle->strokeWidth()->value(lengthContext)); strokeData->setLineCap(svgStyle->capStyle()); strokeData->setLineJoin(svgStyle->joinStyle()); strokeData->setMiterLimit(svgStyle->strokeMiterLimit()); RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); if (dashes->isEmpty()) return; DashArray dashArray; size_t length = dashes->length(); for (size_t i = 0; i < length; ++i) dashArray.append(dashes->at(i)->value(lengthContext)); strokeData->setLineDash(dashArray, svgStyle->strokeDashOffset()->value(lengthContext)); }
void SVGTransformList::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtr<SVGPropertyBase> fromValue, PassRefPtr<SVGPropertyBase> toValue, PassRefPtr<SVGPropertyBase> toAtEndOfDurationValue, SVGElement* contextElement) { ASSERT(animationElement); bool isToAnimation = animationElement->animationMode() == ToAnimation; // Spec: To animations provide specific functionality to get a smooth change from the underlying value to the // ‘to’ attribute value, which conflicts mathematically with the requirement for additive transform animations // to be post-multiplied. As a consequence, in SVG 1.1 the behavior of to animations for ‘animateTransform’ is undefined // FIXME: This is not taken into account yet. RefPtr<SVGTransformList> fromList = isToAnimation ? this : toSVGTransformList(fromValue); RefPtr<SVGTransformList> toList = toSVGTransformList(toValue); RefPtr<SVGTransformList> toAtEndOfDurationList = toSVGTransformList(toAtEndOfDurationValue); size_t fromListSize = fromList->length(); size_t toListSize = toList->length(); if (!toListSize) return; // Never resize the animatedTransformList to the toList size, instead either clear the list or append to it. if (!isEmpty() && !animationElement->isAdditive()) clear(); RefPtr<SVGTransform> toTransform = toList->at(0); RefPtr<SVGTransform> effectiveFrom = fromListSize ? fromList->at(0) : SVGTransform::create(toTransform->transformType(), SVGTransform::ConstructZeroTransform); RefPtr<SVGTransform> currentTransform = SVGTransformDistance(effectiveFrom, toTransform).scaledDistance(percentage).addToSVGTransform(effectiveFrom); if (animationElement->isAccumulated() && repeatCount) { RefPtr<SVGTransform> effectiveToAtEnd = !toAtEndOfDurationList->isEmpty() ? toAtEndOfDurationList->at(0) : SVGTransform::create(toTransform->transformType(), SVGTransform::ConstructZeroTransform); append(SVGTransformDistance::addSVGTransforms(currentTransform, effectiveToAtEnd, repeatCount)); } else { append(currentTransform); } }
void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object) { ASSERT(context); ASSERT(style); ASSERT(object); ASSERT(object->node()); ASSERT(object->node()->isSVGElement()); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); context->setStrokeThickness(svgStyle->strokeWidth()->value(lengthContext)); context->setLineCap(svgStyle->capStyle()); context->setLineJoin(svgStyle->joinStyle()); context->setMiterLimit(svgStyle->strokeMiterLimit()); RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); if (dashes->isEmpty()) return; DashArray dashArray; SVGLengthList::ConstIterator it = dashes->begin(); SVGLengthList::ConstIterator itEnd = dashes->end(); for (; it != itEnd; ++it) dashArray.append(it->value(lengthContext)); context->setLineDash(dashArray, svgStyle->strokeDashOffset()->value(lengthContext)); }
PassRefPtr<IDBTransaction> IDBDatabase::transaction(ScriptExecutionContext* context, PassRefPtr<DOMStringList> prpStoreNames, const String& modeString, ExceptionCode& ec) { RefPtr<DOMStringList> storeNames = prpStoreNames; ASSERT(storeNames.get()); if (storeNames->isEmpty()) { ec = IDBDatabaseException::IDB_INVALID_ACCESS_ERR; return 0; } IDBTransaction::Mode mode = IDBTransaction::stringToMode(modeString, ec); if (ec) return 0; if (m_versionChangeTransaction || m_closePending) { ec = IDBDatabaseException::IDB_INVALID_STATE_ERR; return 0; } // We need to create a new transaction synchronously. Locks are acquired asynchronously. Operations // can be queued against the transaction at any point. They will start executing as soon as the // appropriate locks have been acquired. // Also note that each backend object corresponds to exactly one IDBTransaction object. RefPtr<IDBTransactionBackendInterface> transactionBackend = m_backend->transaction(storeNames.get(), mode, ec); if (!transactionBackend) { ASSERT(ec); return 0; } RefPtr<IDBTransaction> transaction = IDBTransaction::create(context, transactionBackend, mode, this); transactionBackend->setCallbacks(transaction.get()); return transaction.release(); }
void InspectorLayerTreeAgent::loadSnapshot( ErrorString* errorString, std::unique_ptr<Array<protocol::LayerTree::PictureTile>> tiles, String* snapshotId) { if (!tiles->length()) { *errorString = "Invalid argument, no tiles provided"; return; } Vector<RefPtr<PictureSnapshot::TilePictureStream>> decodedTiles; decodedTiles.grow(tiles->length()); for (size_t i = 0; i < tiles->length(); ++i) { protocol::LayerTree::PictureTile* tile = tiles->get(i); decodedTiles[i] = adoptRef(new PictureSnapshot::TilePictureStream()); decodedTiles[i]->layerOffset.set(tile->getX(), tile->getY()); if (!base64Decode(tile->getPicture(), decodedTiles[i]->data)) { *errorString = "Invalid base64 encoding"; return; } } RefPtr<PictureSnapshot> snapshot = PictureSnapshot::load(decodedTiles); if (!snapshot) { *errorString = "Invalid snapshot format"; return; } if (snapshot->isEmpty()) { *errorString = "Empty snapshot"; return; } *snapshotId = String::number(++s_lastSnapshotId); bool newEntry = m_snapshotById.add(*snapshotId, snapshot).isNewEntry; DCHECK(newEntry); }
void InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets(ErrorString& errorString, const Inspector::InspectorArray& locations, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::TypeDescription>>& typeDescriptions) { static const bool verbose = false; typeDescriptions = Inspector::Protocol::Array<Inspector::Protocol::Runtime::TypeDescription>::create(); if (!m_vm.typeProfiler()) { errorString = ASCIILiteral("The VM does not currently have Type Information."); return; } double start = currentTimeMS(); m_vm.typeProfilerLog()->processLogEntries(ASCIILiteral("User Query")); for (size_t i = 0; i < locations.length(); i++) { RefPtr<Inspector::InspectorValue> value = locations.get(i); RefPtr<InspectorObject> location; if (!value->asObject(location)) { errorString = ASCIILiteral("Array of TypeLocation objects has an object that does not have type of TypeLocation."); return; } int descriptor; String sourceIDAsString; int divot; location->getInteger(ASCIILiteral("typeInformationDescriptor"), descriptor); location->getString(ASCIILiteral("sourceID"), sourceIDAsString); location->getInteger(ASCIILiteral("divot"), divot); bool okay; TypeLocation* typeLocation = m_vm.typeProfiler()->findLocation(divot, sourceIDAsString.toIntPtrStrict(&okay), static_cast<TypeProfilerSearchDescriptor>(descriptor), m_vm); ASSERT(okay); RefPtr<TypeSet> typeSet; if (typeLocation) { if (typeLocation->m_globalTypeSet && typeLocation->m_globalVariableID != TypeProfilerNoGlobalIDExists) typeSet = typeLocation->m_globalTypeSet; else typeSet = typeLocation->m_instructionTypeSet; } bool isValid = typeLocation && typeSet && !typeSet->isEmpty(); auto description = Inspector::Protocol::Runtime::TypeDescription::create() .setIsValid(isValid) .release(); if (isValid) { description->setLeastCommonAncestor(typeSet->leastCommonAncestor()); description->setStructures(typeSet->allStructureRepresentations()); description->setTypeSet(typeSet->inspectorTypeSet()); description->setIsTruncated(typeSet->isOverflown()); } typeDescriptions->addItem(WTFMove(description)); } double end = currentTimeMS(); if (verbose) dataLogF("Inspector::getRuntimeTypesForVariablesAtOffsets took %lfms\n", end - start); }
// Don't (re)create HashSets if we've already setWholeSubtreeInvalid. TEST(InvalidationSetTest, SubtreeInvalid_AddAfter) { RefPtr<InvalidationSet> set = DescendantInvalidationSet::create(); set->setWholeSubtreeInvalid(); set->addTagName("a"); ASSERT_TRUE(set->isEmpty()); }
// Once we setWholeSubtreeInvalid, we should not keep the HashSets. TEST(InvalidationSetTest, SubtreeInvalid_AddBefore) { RefPtr<InvalidationSet> set = DescendantInvalidationSet::create(); set->addClass("a"); set->setWholeSubtreeInvalid(); ASSERT_TRUE(set->isEmpty()); }
void StyledMarkupAccumulator::appendElement(StringBuilder& out, const Element& element, bool addDisplayInline, RangeFullySelectsNode rangeFullySelectsNode) { const bool documentIsHTML = element.document().isHTMLDocument(); appendOpenTag(out, element, 0); appendCustomAttributes(out, element, nullptr); const bool shouldAnnotateOrForceInline = element.isHTMLElement() && (shouldAnnotate() || addDisplayInline); const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element); if (element.hasAttributes()) { for (const Attribute& attribute : element.attributesIterator()) { // We'll handle the style attribute separately, below. if (attribute.name() == styleAttr && shouldOverrideStyleAttr) continue; appendAttribute(out, element, attribute, 0); } } if (shouldOverrideStyleAttr) { RefPtr<EditingStyle> newInlineStyle; if (shouldApplyWrappingStyle(element)) { newInlineStyle = m_wrappingStyle->copy(); newInlineStyle->removePropertiesInElementDefaultStyle(const_cast<Element*>(&element)); newInlineStyle->removeStyleConflictingWithStyleOfNode(const_cast<Element*>(&element)); } else newInlineStyle = EditingStyle::create(); if (is<StyledElement>(element) && downcast<StyledElement>(element).inlineStyle()) newInlineStyle->overrideWithStyle(downcast<StyledElement>(element).inlineStyle()); if (shouldAnnotateOrForceInline) { if (shouldAnnotate()) newInlineStyle->mergeStyleFromRulesForSerialization(downcast<HTMLElement>(const_cast<Element*>(&element))); if (addDisplayInline) newInlineStyle->forceInline(); if (m_needsPositionStyleConversion) { m_needRelativeStyleWrapper |= newInlineStyle->convertPositionStyle(); m_needClearingDiv |= newInlineStyle->isFloating(); } // If the node is not fully selected by the range, then we don't want to keep styles that affect its relationship to the nodes around it // only the ones that affect it and the nodes within it. if (rangeFullySelectsNode == DoesNotFullySelectNode && newInlineStyle->style()) newInlineStyle->style()->removeProperty(CSSPropertyFloat); } if (!newInlineStyle->isEmpty()) { out.appendLiteral(" style=\""); appendAttributeValue(out, newInlineStyle->style()->asText(), documentIsHTML); out.append('\"'); } } appendCloseTag(out, element); }
// Make sure the arena frees all allocated regions during destruction. TEST_F(PODFreeListArenaTest, FreesAllAllocatedRegions) { RefPtr<TrackedAllocator> allocator = TrackedAllocator::create(); { RefPtr<PODFreeListArena<TestClass1>> arena = PODFreeListArena<TestClass1>::create(allocator); for (int i = 0; i < 3; i++) arena->allocateObject(); EXPECT_GT(allocator->numRegions(), 0); } EXPECT_TRUE(allocator->isEmpty()); }
/** * Evaluates this Expr based on the given context node and processor state * @param context the context node for evaluation of this Expr * @param ps the ContextState containing the stack information needed * for evaluation * @return the result of the evaluation * @see FunctionCall.h **/ nsresult GenerateIdFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) { *aResult = nullptr; if (!requireParams(0, 1, aContext)) return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; txExecutionState* es = static_cast<txExecutionState*>(aContext->getPrivateContext()); if (!es) { NS_ERROR( "called xslt extension function \"generate-id\" with wrong context"); return NS_ERROR_UNEXPECTED; } nsresult rv = NS_OK; if (mParams.IsEmpty()) { StringResult* strRes; rv = aContext->recycler()->getStringResult(&strRes); NS_ENSURE_SUCCESS(rv, rv); txXPathNodeUtils::getXSLTId(aContext->getContextNode(), es->getSourceDocument(), strRes->mValue); *aResult = strRes; return NS_OK; } RefPtr<txNodeSet> nodes; rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes)); NS_ENSURE_SUCCESS(rv, rv); if (nodes->isEmpty()) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } StringResult* strRes; rv = aContext->recycler()->getStringResult(&strRes); NS_ENSURE_SUCCESS(rv, rv); txXPathNodeUtils::getXSLTId(nodes->get(0), es->getSourceDocument(), strRes->mValue); *aResult = strRes; return NS_OK; }
void ResourceRequest::doUpdatePlatformRequest() { CFMutableURLRequestRef cfRequest; RetainPtr<CFURLRef> url(AdoptCF, ResourceRequest::url().createCFURL()); RetainPtr<CFURLRef> firstPartyForCookies(AdoptCF, ResourceRequest::firstPartyForCookies().createCFURL()); if (m_cfRequest) { cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get()); CFURLRequestSetURL(cfRequest, url.get()); CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get()); CFURLRequestSetCachePolicy(cfRequest, (CFURLRequestCachePolicy)cachePolicy()); CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval()); } else cfRequest = CFURLRequestCreateMutable(0, url.get(), (CFURLRequestCachePolicy)cachePolicy(), timeoutInterval(), firstPartyForCookies.get()); CFURLRequestSetHTTPRequestMethod(cfRequest, httpMethod().createCFString().get()); if (httpPipeliningEnabled()) wkSetHTTPPipeliningPriority(cfRequest, toHTTPPipeliningPriority(m_priority)); #if !PLATFORM(WIN) wkCFURLRequestAllowAllPostCaching(cfRequest); #endif setHeaderFields(cfRequest, httpHeaderFields()); RefPtr<FormData> formData = httpBody(); if (formData && !formData->isEmpty()) WebCore::setHTTPBody(cfRequest, formData); CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies()); unsigned fallbackCount = m_responseContentDispositionEncodingFallbackArray.size(); RetainPtr<CFMutableArrayRef> encodingFallbacks(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, fallbackCount, 0)); for (unsigned i = 0; i != fallbackCount; ++i) { RetainPtr<CFStringRef> encodingName = m_responseContentDispositionEncodingFallbackArray[i].createCFString(); CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding(encodingName.get()); if (encoding != kCFStringEncodingInvalidId) CFArrayAppendValue(encodingFallbacks.get(), reinterpret_cast<const void*>(encoding)); } setContentDispositionEncodingFallbackArray(cfRequest, encodingFallbacks.get()); if (m_cfRequest) { RetainPtr<CFHTTPCookieStorageRef> cookieStorage(AdoptCF, CFURLRequestCopyHTTPCookieStorage(m_cfRequest.get())); if (cookieStorage) CFURLRequestSetHTTPCookieStorage(cfRequest, cookieStorage.get()); CFURLRequestSetHTTPCookieStorageAcceptPolicy(cfRequest, CFURLRequestGetHTTPCookieStorageAcceptPolicy(m_cfRequest.get())); CFURLRequestSetSSLProperties(cfRequest, CFURLRequestGetSSLProperties(m_cfRequest.get())); } m_cfRequest.adoptCF(cfRequest); #if PLATFORM(MAC) updateNSURLRequest(); #endif }
void StyledMarkupAccumulator::appendElement(StringBuilder& out, Element* element, bool addDisplayInline, RangeFullySelectsNode rangeFullySelectsNode) { const bool documentIsHTML = element->document()->isHTMLDocument(); appendOpenTag(out, element, 0); const unsigned length = element->hasAttributes() ? element->attributeCount() : 0; const bool shouldAnnotateOrForceInline = element->isHTMLElement() && (shouldAnnotate() || addDisplayInline); const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element); for (unsigned i = 0; i < length; ++i) { const Attribute* attribute = element->attributeItem(i); // We'll handle the style attribute separately, below. if (attribute->name() == styleAttr && shouldOverrideStyleAttr) continue; appendAttribute(out, element, *attribute, 0); } if (shouldOverrideStyleAttr) { RefPtr<EditingStyle> newInlineStyle; if (shouldApplyWrappingStyle(element)) { newInlineStyle = m_wrappingStyle->copy(); newInlineStyle->removePropertiesInElementDefaultStyle(element); newInlineStyle->removeStyleConflictingWithStyleOfNode(element); } else newInlineStyle = EditingStyle::create(); if (element->isStyledElement() && static_cast<StyledElement*>(element)->inlineStyle()) newInlineStyle->overrideWithStyle(static_cast<StyledElement*>(element)->inlineStyle()); if (shouldAnnotateOrForceInline) { if (shouldAnnotate()) newInlineStyle->mergeStyleFromRulesForSerialization(toHTMLElement(element)); if (addDisplayInline) newInlineStyle->forceInline(); // If the node is not fully selected by the range, then we don't want to keep styles that affect its relationship to the nodes around it // only the ones that affect it and the nodes within it. if (rangeFullySelectsNode == DoesNotFullySelectNode && newInlineStyle->style()) newInlineStyle->style()->removeProperty(CSSPropertyFloat); } if (!newInlineStyle->isEmpty()) { out.appendLiteral(" style=\""); appendAttributeValue(out, newInlineStyle->style()->asText(), documentIsHTML); out.append('\"'); } } appendCloseTag(out, element); }
void StyledMarkupAccumulator::appendElement(StringBuilder& out, Element& element, bool addDisplayInline) { const bool documentIsHTML = element.document().isHTMLDocument(); appendOpenTag(out, element, 0); const bool shouldAnnotateOrForceInline = element.isHTMLElement() && (shouldAnnotate() || addDisplayInline); const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element); AttributeCollection attributes = element.attributes(); AttributeCollection::iterator end = attributes.end(); for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) { // We'll handle the style attribute separately, below. if (it->name() == HTMLNames::styleAttr && shouldOverrideStyleAttr) continue; appendAttribute(out, element, *it, 0); } if (shouldOverrideStyleAttr) { RefPtr<EditingStyle> newInlineStyle = nullptr; if (shouldApplyWrappingStyle(element)) { newInlineStyle = m_wrappingStyle->copy(); newInlineStyle->removePropertiesInElementDefaultStyle(&element); newInlineStyle->removeStyleConflictingWithStyleOfElement(&element); } else newInlineStyle = EditingStyle::create(); if (element.isStyledElement() && element.inlineStyle()) newInlineStyle->overrideWithStyle(element.inlineStyle()); if (shouldAnnotateOrForceInline) { if (shouldAnnotate()) newInlineStyle->mergeStyleFromRulesForSerialization(&toHTMLElement(element)); if (&element == m_highestNodeToBeSerialized && m_shouldAnnotate == AnnotateForNavigationTransition) newInlineStyle->addAbsolutePositioningFromElement(element); if (addDisplayInline) newInlineStyle->forceInline(); } if (!newInlineStyle->isEmpty()) { out.appendLiteral(" style=\""); appendAttributeValue(out, newInlineStyle->style()->asText(), documentIsHTML); out.append('\"'); } } appendCloseTag(out, element); }
bool Clipboard::hasFileOfType(const String& type) const { if (m_policy != ClipboardReadable && m_policy != ClipboardTypesReadable) return false; RefPtr<FileList> fileList = files(); if (fileList->isEmpty()) return false; for (unsigned int f = 0; f < fileList->length(); f++) { if (equalIgnoringCase(fileList->item(f)->type(), type)) return true; } return false; }
void StyledElement::updateAttributeStyle() { RefPtr<StylePropertySet> style = StylePropertySet::create(); for (unsigned i = 0; i < attributeCount(); ++i) { Attribute* attribute = attributeItem(i); collectStyleForAttribute(attribute, style.get()); } clearAttributeStyleDirty(); if (style->isEmpty()) attributeData()->setAttributeStyle(0); else { style->shrinkToFit(); attributeData()->setAttributeStyle(style.release()); } }
bool FontFaceSet::resolveFontStyle(const String& fontString, Font& font) { if (fontString.isEmpty()) return false; // Interpret fontString in the same way as the 'font' attribute of CanvasRenderingContext2D. RefPtr<MutableStylePropertySet> parsedStyle = MutableStylePropertySet::create(); BisonCSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, HTMLStandardMode, 0); if (parsedStyle->isEmpty()) return false; String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont); if (fontValue == "inherit" || fontValue == "initial") return false; RefPtr<RenderStyle> style = RenderStyle::create(); FontFamily fontFamily; fontFamily.setFamily(defaultFontFamily); FontDescription defaultFontDescription; defaultFontDescription.setFamily(fontFamily); defaultFontDescription.setSpecifiedSize(defaultFontSize); defaultFontDescription.setComputedSize(defaultFontSize); style->setFontDescription(defaultFontDescription); style->font().update(style->font().fontSelector()); // Now map the font property longhands into the style. CSSPropertyValue properties[] = { CSSPropertyValue(CSSPropertyFontFamily, *parsedStyle), CSSPropertyValue(CSSPropertyFontStretch, *parsedStyle), CSSPropertyValue(CSSPropertyFontStyle, *parsedStyle), CSSPropertyValue(CSSPropertyFontVariant, *parsedStyle), CSSPropertyValue(CSSPropertyFontWeight, *parsedStyle), CSSPropertyValue(CSSPropertyFontSize, *parsedStyle), CSSPropertyValue(CSSPropertyLineHeight, *parsedStyle), }; StyleResolver& styleResolver = document()->styleResolver(); styleResolver.applyPropertiesToStyle(properties, WTF_ARRAY_LENGTH(properties), style.get()); font = style->font(); font.update(document()->styleEngine()->fontSelector()); return true; }
void StyledElement::rebuildPresentationAttributeStyle() { PresentationAttributeCacheKey cacheKey; makePresentationAttributeCacheKey(cacheKey); unsigned cacheHash = computePresentationAttributeCacheHash(cacheKey); PresentationAttributeCache::iterator cacheIterator; if (cacheHash) { cacheIterator = presentationAttributeCache().add(cacheHash, nullptr).iterator; if (cacheIterator->value && cacheIterator->value->key != cacheKey) cacheHash = 0; } else cacheIterator = presentationAttributeCache().end(); RefPtr<StyleProperties> style; if (cacheHash && cacheIterator->value) { style = cacheIterator->value->value; presentationAttributeCacheCleaner().didHitPresentationAttributeCache(); } else { style = MutableStyleProperties::create(isSVGElement() ? SVGAttributeMode : CSSQuirksMode); for (const Attribute& attribute : attributesIterator()) collectStyleForPresentationAttribute(attribute.name(), attribute.value(), static_cast<MutableStyleProperties&>(*style)); } // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData. UniqueElementData& elementData = ensureUniqueElementData(); elementData.setPresentationAttributeStyleIsDirty(false); elementData.m_presentationAttributeStyle = style->isEmpty() ? 0 : style; if (!cacheHash || cacheIterator->value) return; std::unique_ptr<PresentationAttributeCacheEntry> newEntry = std::make_unique<PresentationAttributeCacheEntry>(); newEntry->key = cacheKey; newEntry->value = style.release(); static const int presentationAttributeCacheMaximumSize = 4096; if (presentationAttributeCache().size() > presentationAttributeCacheMaximumSize) { // Start building from scratch if the cache ever gets big. presentationAttributeCache().clear(); presentationAttributeCache().set(cacheHash, WTF::move(newEntry)); } else cacheIterator->value = WTF::move(newEntry); }
static v8::Handle<v8::Value> getNamedProperty(HTMLDocument* htmlDocument, const AtomicString& key, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) { if (!htmlDocument->hasNamedItem(key) && !htmlDocument->hasExtraNamedItem(key)) return v8Undefined(); RefPtr<HTMLCollection> items = htmlDocument->documentNamedItems(key); if (items->isEmpty()) return v8Undefined(); if (items->hasExactlyOneItem()) { Node* node = items->item(0); Frame* frame = 0; if (node->hasTagName(HTMLNames::iframeTag) && (frame = toHTMLIFrameElement(node)->contentFrame())) return toV8(frame->domWindow(), creationContext, isolate); return toV8(node, creationContext, isolate); } return toV8(items.release(), creationContext, isolate); }
bool FontLoader::resolveFontStyle(const String& fontString, FontCascade& font) { // Interpret fontString in the same way as the 'font' attribute of CanvasRenderingContext2D. RefPtr<MutableStyleProperties> parsedStyle = MutableStyleProperties::create(); CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, fontString, true, CSSStrictMode, 0); if (parsedStyle->isEmpty()) return false; String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont); if (fontValue == "inherit" || fontValue == "initial") return false; RefPtr<RenderStyle> style = RenderStyle::create(); FontDescription defaultFontDescription; defaultFontDescription.setOneFamily(defaultFontFamily); defaultFontDescription.setSpecifiedSize(defaultFontSize); defaultFontDescription.setComputedSize(defaultFontSize); style->setFontDescription(defaultFontDescription); style->fontCascade().update(style->fontCascade().fontSelector()); // Now map the font property longhands into the style. StyleResolver& styleResolver = m_document->ensureStyleResolver(); styleResolver.applyPropertyToStyle(CSSPropertyFontFamily, parsedStyle->getPropertyCSSValue(CSSPropertyFontFamily).get(), style.get()); applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontStyle, parsedStyle); applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontVariant, parsedStyle); applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontWeight, parsedStyle); // As described in BUG66291, setting font-size and line-height on a font may entail a CSSPrimitiveValue::computeLengthDouble call, // which assumes the fontMetrics are available for the affected font, otherwise a crash occurs (see http://trac.webkit.org/changeset/96122). // The updateFont() calls below update the fontMetrics and ensure the proper setting of font-size and line-height. styleResolver.updateFont(); applyPropertyToCurrentStyle(styleResolver, CSSPropertyFontSize, parsedStyle); styleResolver.updateFont(); applyPropertyToCurrentStyle(styleResolver, CSSPropertyLineHeight, parsedStyle); font = style->fontCascade(); font.update(&m_document->fontSelector()); return true; }
void InspectorLayerTreeAgent::loadSnapshot(ErrorString* errorString, const RefPtr<JSONArray>& tiles, String* snapshotId) { if (!tiles->length()) { *errorString = "Invalid argument, no tiles provided"; return; } Vector<RefPtr<PictureSnapshot::TilePictureStream> > decodedTiles; decodedTiles.grow(tiles->length()); for (size_t i = 0; i < tiles->length(); ++i) { RefPtr<JSONObject> item; if (!tiles->get(i)->asObject(&item)) { *errorString = "Invalid argument, array item is not an object"; return; } double x = 0, y = 0; String picture; if (!item->getNumber("x", &x) || !item->getNumber("y", &y) || !item->getString("picture", &picture)) { *errorString = "Invalid argument, missing required field"; return; } decodedTiles[i] = adoptRef(new PictureSnapshot::TilePictureStream()); decodedTiles[i]->layerOffset.set(x, y); if (!base64Decode(picture, decodedTiles[i]->data)) { *errorString = "Invalid base64 encoding"; return; } } RefPtr<PictureSnapshot> snapshot = PictureSnapshot::load(decodedTiles); if (!snapshot) { *errorString = "Invalid snapshot format"; return; } if (snapshot->isEmpty()) { *errorString = "Empty snapshot"; return; } *snapshotId = String::number(++s_lastSnapshotId); bool newEntry = m_snapshotById.add(*snapshotId, snapshot).isNewEntry; ASSERT_UNUSED(newEntry, newEntry); }
void V8Window::namedPropertyGetterCustom(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { DOMWindow* window = V8Window::toNative(info.Holder()); if (!window) return; Frame* frame = window->frame(); // window is detached from a frame. if (!frame) return; // Search sub-frames. AtomicString propName = toWebCoreAtomicString(name); Frame* child = frame->tree()->scopedChild(propName); if (child) { v8SetReturnValue(info, toV8Fast(child->domWindow(), info, window)); return; } // Search IDL functions defined in the prototype if (!info.Holder()->GetRealNamedProperty(name).IsEmpty()) return; // Search named items in the document. Document* doc = frame->document(); if (doc && doc->isHTMLDocument()) { if (toHTMLDocument(doc)->hasNamedItem(propName.impl()) || doc->hasElementWithId(propName.impl())) { RefPtr<HTMLCollection> items = doc->windowNamedItems(propName); if (!items->isEmpty()) { if (items->hasExactlyOneItem()) { v8SetReturnValue(info, toV8Fast(items->item(0), info, window)); return; } v8SetReturnValue(info, toV8Fast(items.release(), info, window)); return; } } } }
JSValue JSHTMLDocument::nameGetter(ExecState* exec, JSValue slotBase, PropertyName propertyName) { JSHTMLDocument* thisObj = jsCast<JSHTMLDocument*>(asObject(slotBase)); HTMLDocument* document = toHTMLDocument(thisObj->impl()); AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); if (!atomicPropertyName || !document->documentNamedItemMap().contains(atomicPropertyName)) return jsUndefined(); if (UNLIKELY(!document->documentNamedItemMap().containsSingle(atomicPropertyName))) { RefPtr<HTMLCollection> collection = document->documentNamedItems(atomicPropertyName); ASSERT(!collection->isEmpty()); ASSERT(!collection->hasExactlyOneItem()); return toJS(exec, thisObj->globalObject(), WTF::getPtr(collection)); } Node* node = document->documentNamedItemMap().getElementByDocumentNamedItem(atomicPropertyName, document); Frame* frame; if (node->hasTagName(iframeTag) && (frame = static_cast<HTMLIFrameElement*>(node)->contentFrame())) return toJS(exec, frame); return toJS(exec, thisObj->globalObject(), node); }
void FontFaceCache::removeFontFace(FontFace* fontFace, bool cssConnected) { FamilyToTraitsMap::iterator fontFacesIter = m_fontFaces.find(fontFace->family()); if (fontFacesIter == m_fontFaces.end()) return; TraitsMap* familyFontFaces = fontFacesIter->value.get(); TraitsMap::iterator familyFontFacesIter = familyFontFaces->find(fontFace->traits().bitfield()); if (familyFontFacesIter == familyFontFaces->end()) return; RefPtr<CSSSegmentedFontFace> segmentedFontFace = familyFontFacesIter->value; segmentedFontFace->removeFontFace(fontFace); if (segmentedFontFace->isEmpty()) { familyFontFaces->remove(familyFontFacesIter); if (familyFontFaces->isEmpty()) m_fontFaces.remove(fontFacesIter); } m_fonts.clear(); if (cssConnected) m_cssConnectedFontFaces.remove(fontFace); ++m_version; }
void InsertLineBreakCommand::doApply() { deleteSelection(); VisibleSelection selection = endingSelection(); if (!selection.isNonOrphanedCaretOrRange()) return; VisiblePosition caret(selection.visibleStart()); // FIXME: If the node is hidden, we should still be able to insert text. // For now, we return to avoid a crash. https://bugs.webkit.org/show_bug.cgi?id=40342 if (caret.isNull()) return; Position pos(caret.deepEquivalent()); pos = positionAvoidingSpecialElementBoundary(pos); pos = positionOutsideTabSpan(pos); RefPtr<Node> nodeToInsert; if (shouldUseBreakElement(pos)) nodeToInsert = createBreakElement(document()); else nodeToInsert = document().createTextNode("\n"); // FIXME: Need to merge text nodes when inserting just after or before text. if (isEndOfParagraph(caret) && !lineBreakExistsAtVisiblePosition(caret)) { bool needExtraLineBreak = !pos.deprecatedNode()->hasTagName(hrTag) && !pos.deprecatedNode()->hasTagName(tableTag); insertNodeAt(nodeToInsert.get(), pos); if (needExtraLineBreak) insertNodeBefore(nodeToInsert->cloneNode(false), nodeToInsert); VisiblePosition endingPosition(positionBeforeNode(nodeToInsert.get())); setEndingSelection(VisibleSelection(endingPosition, endingSelection().isDirectional())); } else if (pos.deprecatedEditingOffset() <= caretMinOffset(pos.deprecatedNode())) { insertNodeAt(nodeToInsert.get(), pos); // Insert an extra br or '\n' if the just inserted one collapsed. if (!isStartOfParagraph(positionBeforeNode(nodeToInsert.get()))) insertNodeBefore(nodeToInsert->cloneNode(false).get(), nodeToInsert.get()); setEndingSelection(VisibleSelection(positionInParentAfterNode(nodeToInsert.get()), DOWNSTREAM, endingSelection().isDirectional())); // If we're inserting after all of the rendered text in a text node, or into a non-text node, // a simple insertion is sufficient. } else if (pos.deprecatedEditingOffset() >= caretMaxOffset(pos.deprecatedNode()) || !pos.deprecatedNode()->isTextNode()) { insertNodeAt(nodeToInsert.get(), pos); setEndingSelection(VisibleSelection(positionInParentAfterNode(nodeToInsert.get()), DOWNSTREAM, endingSelection().isDirectional())); } else if (pos.deprecatedNode()->isTextNode()) { // Split a text node Text* textNode = toText(pos.deprecatedNode()); splitTextNode(textNode, pos.deprecatedEditingOffset()); insertNodeBefore(nodeToInsert, textNode); Position endingPosition = firstPositionInNode(textNode); // Handle whitespace that occurs after the split document().updateLayoutIgnorePendingStylesheets(); if (!endingPosition.isRenderedCharacter()) { Position positionBeforeTextNode(positionInParentBeforeNode(textNode)); // Clear out all whitespace and insert one non-breaking space deleteInsignificantTextDownstream(endingPosition); ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace()); // Deleting insignificant whitespace will remove textNode if it contains nothing but insignificant whitespace. if (textNode->inDocument()) insertTextIntoNode(textNode, 0, nonBreakingSpaceString()); else { RefPtr<Text> nbspNode = document().createTextNode(nonBreakingSpaceString()); insertNodeAt(nbspNode.get(), positionBeforeTextNode); endingPosition = firstPositionInNode(nbspNode.get()); } } setEndingSelection(VisibleSelection(endingPosition, DOWNSTREAM, endingSelection().isDirectional())); } // Handle the case where there is a typing style. RefPtr<EditingStyle> typingStyle = document().frame()->selection().typingStyle(); if (typingStyle && !typingStyle->isEmpty()) { // Apply the typing style to the inserted line break, so that if the selection // leaves and then comes back, new input will have the right style. // FIXME: We shouldn't always apply the typing style to the line break here, // see <rdar://problem/5794462>. applyStyle(typingStyle.get(), firstPositionInOrBeforeNode(nodeToInsert.get()), lastPositionInOrAfterNode(nodeToInsert.get())); // Even though this applyStyle operates on a Range, it still sets an endingSelection(). // It tries to set a VisibleSelection around the content it operated on. So, that VisibleSelection // will either (a) select the line break we inserted, or it will (b) be a caret just // before the line break (if the line break is at the end of a block it isn't selectable). // So, this next call sets the endingSelection() to a caret just after the line break // that we inserted, or just before it if it's at the end of a block. setEndingSelection(endingSelection().visibleEnd()); } rebalanceWhitespace(); }
/* * Evaluates this Expr based on the given context node and processor state * @param context the context node for evaluation of this Expr * @param ps the ContextState containing the stack information needed * for evaluation * @return the result of the evaluation */ nsresult txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) { *aResult = nullptr; if (!requireParams(descriptTable[mType].mMinParams, descriptTable[mType].mMaxParams, aContext)) { return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; } nsresult rv = NS_OK; switch (mType) { case COUNT: { RefPtr<txNodeSet> nodes; rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes)); NS_ENSURE_SUCCESS(rv, rv); return aContext->recycler()->getNumberResult(nodes->size(), aResult); } case ID: { RefPtr<txAExprResult> exprResult; rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult)); NS_ENSURE_SUCCESS(rv, rv); RefPtr<txNodeSet> resultSet; rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet)); NS_ENSURE_SUCCESS(rv, rv); txXPathTreeWalker walker(aContext->getContextNode()); if (exprResult->getResultType() == txAExprResult::NODESET) { txNodeSet* nodes = static_cast<txNodeSet*> (static_cast<txAExprResult*> (exprResult)); int32_t i; for (i = 0; i < nodes->size(); ++i) { nsAutoString idList; txXPathNodeUtils::appendNodeValue(nodes->get(i), idList); nsWhitespaceTokenizer tokenizer(idList); while (tokenizer.hasMoreTokens()) { if (walker.moveToElementById(tokenizer.nextToken())) { resultSet->add(walker.getCurrentPosition()); } } } } else { nsAutoString idList; exprResult->stringValue(idList); nsWhitespaceTokenizer tokenizer(idList); while (tokenizer.hasMoreTokens()) { if (walker.moveToElementById(tokenizer.nextToken())) { resultSet->add(walker.getCurrentPosition()); } } } *aResult = resultSet; NS_ADDREF(*aResult); return NS_OK; } case LAST: { return aContext->recycler()->getNumberResult(aContext->size(), aResult); } case LOCAL_NAME: case NAME: case NAMESPACE_URI: { // Check for optional arg RefPtr<txNodeSet> nodes; if (!mParams.IsEmpty()) { rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes)); NS_ENSURE_SUCCESS(rv, rv); if (nodes->isEmpty()) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } } const txXPathNode& node = nodes ? nodes->get(0) : aContext->getContextNode(); switch (mType) { case LOCAL_NAME: { StringResult* strRes = nullptr; rv = aContext->recycler()->getStringResult(&strRes); NS_ENSURE_SUCCESS(rv, rv); *aResult = strRes; txXPathNodeUtils::getLocalName(node, strRes->mValue); return NS_OK; } case NAMESPACE_URI: { StringResult* strRes = nullptr; rv = aContext->recycler()->getStringResult(&strRes); NS_ENSURE_SUCCESS(rv, rv); *aResult = strRes; txXPathNodeUtils::getNamespaceURI(node, strRes->mValue); return NS_OK; } case NAME: { // XXX Namespace: namespaces have a name if (txXPathNodeUtils::isAttribute(node) || txXPathNodeUtils::isElement(node) || txXPathNodeUtils::isProcessingInstruction(node)) { StringResult* strRes = nullptr; rv = aContext->recycler()->getStringResult(&strRes); NS_ENSURE_SUCCESS(rv, rv); *aResult = strRes; txXPathNodeUtils::getNodeName(node, strRes->mValue); } else { aContext->recycler()->getEmptyStringResult(aResult); } return NS_OK; } default: { break; } } } case POSITION: { return aContext->recycler()->getNumberResult(aContext->position(), aResult); } // String functions case CONCAT: { RefPtr<StringResult> strRes; rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes)); NS_ENSURE_SUCCESS(rv, rv); uint32_t i, len = mParams.Length(); for (i = 0; i < len; ++i) { rv = mParams[i]->evaluateToString(aContext, strRes->mValue); NS_ENSURE_SUCCESS(rv, rv); } NS_ADDREF(*aResult = strRes); return NS_OK; } case CONTAINS: { nsAutoString arg2; rv = mParams[1]->evaluateToString(aContext, arg2); NS_ENSURE_SUCCESS(rv, rv); if (arg2.IsEmpty()) { aContext->recycler()->getBoolResult(true, aResult); } else { nsAutoString arg1; rv = mParams[0]->evaluateToString(aContext, arg1); NS_ENSURE_SUCCESS(rv, rv); aContext->recycler()->getBoolResult(FindInReadable(arg2, arg1), aResult); } return NS_OK; } case NORMALIZE_SPACE: { nsAutoString resultStr; if (!mParams.IsEmpty()) { rv = mParams[0]->evaluateToString(aContext, resultStr); NS_ENSURE_SUCCESS(rv, rv); } else { txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), resultStr); } RefPtr<StringResult> strRes; rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes)); NS_ENSURE_SUCCESS(rv, rv); bool addSpace = false; bool first = true; strRes->mValue.SetCapacity(resultStr.Length()); char16_t c; uint32_t src; for (src = 0; src < resultStr.Length(); src++) { c = resultStr.CharAt(src); if (XMLUtils::isWhitespace(c)) { addSpace = true; } else { if (addSpace && !first) strRes->mValue.Append(char16_t(' ')); strRes->mValue.Append(c); addSpace = false; first = false; } } *aResult = strRes; NS_ADDREF(*aResult); return NS_OK; } case STARTS_WITH: { nsAutoString arg2; rv = mParams[1]->evaluateToString(aContext, arg2); NS_ENSURE_SUCCESS(rv, rv); bool result = false; if (arg2.IsEmpty()) { result = true; } else { nsAutoString arg1; rv = mParams[0]->evaluateToString(aContext, arg1); NS_ENSURE_SUCCESS(rv, rv); result = StringBeginsWith(arg1, arg2); } aContext->recycler()->getBoolResult(result, aResult); return NS_OK; } case STRING: { RefPtr<StringResult> strRes; rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes)); NS_ENSURE_SUCCESS(rv, rv); if (!mParams.IsEmpty()) { rv = mParams[0]->evaluateToString(aContext, strRes->mValue); NS_ENSURE_SUCCESS(rv, rv); } else { txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), strRes->mValue); } NS_ADDREF(*aResult = strRes); return NS_OK; } case STRING_LENGTH: { nsAutoString resultStr; if (!mParams.IsEmpty()) { rv = mParams[0]->evaluateToString(aContext, resultStr); NS_ENSURE_SUCCESS(rv, rv); } else { txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), resultStr); } rv = aContext->recycler()->getNumberResult(resultStr.Length(), aResult); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } case SUBSTRING: { nsAutoString src; rv = mParams[0]->evaluateToString(aContext, src); NS_ENSURE_SUCCESS(rv, rv); double start; rv = evaluateToNumber(mParams[1], aContext, &start); NS_ENSURE_SUCCESS(rv, rv); // check for NaN or +/-Inf if (mozilla::IsNaN(start) || mozilla::IsInfinite(start) || start >= src.Length() + 0.5) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } start = floor(start + 0.5) - 1; double end; if (mParams.Length() == 3) { rv = evaluateToNumber(mParams[2], aContext, &end); NS_ENSURE_SUCCESS(rv, rv); end += start; if (mozilla::IsNaN(end) || end < 0) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } if (end > src.Length()) end = src.Length(); else end = floor(end + 0.5); } else { end = src.Length(); } if (start < 0) start = 0; if (start > end) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } return aContext->recycler()->getStringResult( Substring(src, (uint32_t)start, (uint32_t)(end - start)), aResult); } case SUBSTRING_AFTER: { nsAutoString arg1; rv = mParams[0]->evaluateToString(aContext, arg1); NS_ENSURE_SUCCESS(rv, rv); nsAutoString arg2; rv = mParams[1]->evaluateToString(aContext, arg2); NS_ENSURE_SUCCESS(rv, rv); if (arg2.IsEmpty()) { return aContext->recycler()->getStringResult(arg1, aResult); } int32_t idx = arg1.Find(arg2); if (idx == kNotFound) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } const nsSubstring& result = Substring(arg1, idx + arg2.Length()); return aContext->recycler()->getStringResult(result, aResult); } case SUBSTRING_BEFORE: { nsAutoString arg2; rv = mParams[1]->evaluateToString(aContext, arg2); NS_ENSURE_SUCCESS(rv, rv); if (arg2.IsEmpty()) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } nsAutoString arg1; rv = mParams[0]->evaluateToString(aContext, arg1); NS_ENSURE_SUCCESS(rv, rv); int32_t idx = arg1.Find(arg2); if (idx == kNotFound) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } return aContext->recycler()->getStringResult(StringHead(arg1, idx), aResult); } case TRANSLATE: { nsAutoString src; rv = mParams[0]->evaluateToString(aContext, src); NS_ENSURE_SUCCESS(rv, rv); if (src.IsEmpty()) { aContext->recycler()->getEmptyStringResult(aResult); return NS_OK; } RefPtr<StringResult> strRes; rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes)); NS_ENSURE_SUCCESS(rv, rv); strRes->mValue.SetCapacity(src.Length()); nsAutoString oldChars, newChars; rv = mParams[1]->evaluateToString(aContext, oldChars); NS_ENSURE_SUCCESS(rv, rv); rv = mParams[2]->evaluateToString(aContext, newChars); NS_ENSURE_SUCCESS(rv, rv); uint32_t i; int32_t newCharsLength = (int32_t)newChars.Length(); for (i = 0; i < src.Length(); i++) { int32_t idx = oldChars.FindChar(src.CharAt(i)); if (idx != kNotFound) { if (idx < newCharsLength) strRes->mValue.Append(newChars.CharAt((uint32_t)idx)); } else { strRes->mValue.Append(src.CharAt(i)); } } NS_ADDREF(*aResult = strRes); return NS_OK; } // Number functions case NUMBER: { double res; if (!mParams.IsEmpty()) { rv = evaluateToNumber(mParams[0], aContext, &res); NS_ENSURE_SUCCESS(rv, rv); } else { nsAutoString resultStr; txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), resultStr); res = txDouble::toDouble(resultStr); } return aContext->recycler()->getNumberResult(res, aResult); } case ROUND: { double dbl; rv = evaluateToNumber(mParams[0], aContext, &dbl); NS_ENSURE_SUCCESS(rv, rv); if (mozilla::IsFinite(dbl)) { if (mozilla::IsNegative(dbl) && dbl >= -0.5) { dbl *= 0; } else { dbl = floor(dbl + 0.5); } } return aContext->recycler()->getNumberResult(dbl, aResult); } case FLOOR: { double dbl; rv = evaluateToNumber(mParams[0], aContext, &dbl); NS_ENSURE_SUCCESS(rv, rv); if (mozilla::IsFinite(dbl) && !mozilla::IsNegativeZero(dbl)) dbl = floor(dbl); return aContext->recycler()->getNumberResult(dbl, aResult); } case CEILING: { double dbl; rv = evaluateToNumber(mParams[0], aContext, &dbl); NS_ENSURE_SUCCESS(rv, rv); if (mozilla::IsFinite(dbl)) { if (mozilla::IsNegative(dbl) && dbl > -1) dbl *= 0; else dbl = ceil(dbl); } return aContext->recycler()->getNumberResult(dbl, aResult); } case SUM: { RefPtr<txNodeSet> nodes; nsresult rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes)); NS_ENSURE_SUCCESS(rv, rv); double res = 0; int32_t i; for (i = 0; i < nodes->size(); ++i) { nsAutoString resultStr; txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr); res += txDouble::toDouble(resultStr); } return aContext->recycler()->getNumberResult(res, aResult); } // Boolean functions case BOOLEAN: { bool result; nsresult rv = mParams[0]->evaluateToBool(aContext, result); NS_ENSURE_SUCCESS(rv, rv); aContext->recycler()->getBoolResult(result, aResult); return NS_OK; } case _FALSE: { aContext->recycler()->getBoolResult(false, aResult); return NS_OK; } case LANG: { txXPathTreeWalker walker(aContext->getContextNode()); nsAutoString lang; bool found; do { found = walker.getAttr(nsGkAtoms::lang, kNameSpaceID_XML, lang); } while (!found && walker.moveToParent()); if (!found) { aContext->recycler()->getBoolResult(false, aResult); return NS_OK; } nsAutoString arg; rv = mParams[0]->evaluateToString(aContext, arg); NS_ENSURE_SUCCESS(rv, rv); bool result = StringBeginsWith(lang, arg, txCaseInsensitiveStringComparator()) && (lang.Length() == arg.Length() || lang.CharAt(arg.Length()) == '-'); aContext->recycler()->getBoolResult(result, aResult); return NS_OK; } case _NOT: { bool result; rv = mParams[0]->evaluateToBool(aContext, result); NS_ENSURE_SUCCESS(rv, rv); aContext->recycler()->getBoolResult(!result, aResult); return NS_OK; } case _TRUE: { aContext->recycler()->getBoolResult(true, aResult); return NS_OK; } } aContext->receiveError(NS_LITERAL_STRING("Internal error"), NS_ERROR_UNEXPECTED); return NS_ERROR_UNEXPECTED; }