Diff
Modified: trunk/Source/WebCore/ChangeLog (238451 => 238452)
--- trunk/Source/WebCore/ChangeLog 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/ChangeLog 2018-11-22 23:47:33 UTC (rev 238452)
@@ -1,3 +1,53 @@
+2018-11-21 Ryosuke Niwa <rn...@webkit.org>
+
+ Modernize SVGURIReference::targetElementFromIRIString
+ https://bugs.webkit.org/show_bug.cgi?id=191898
+
+ Reviewed by Daniel Bates.
+
+ Made targetElementFromIRIString return an element and the fragment identifier,
+ and merged urlFromIRIStringWithFragmentIdentifier into it.
+
+ Also replaced the code computing the full URL using the base URL after removing
+ the fragment identifier and rejoining it later with a single call to completeURL.
+
+ No new tests since there should be no observable behavior change.
+
+ * accessibility/AccessibilitySVGElement.cpp:
+ (WebCore::AccessibilitySVGElement::targetForUseElement const):
+ * css/CSSCursorImageValue.cpp:
+ (WebCore::CSSCursorImageValue::updateCursorElement):
+ * rendering/svg/RenderSVGTextPath.cpp:
+ (WebCore::RenderSVGTextPath::layoutPath const):
+ * svg/SVGAltGlyphElement.cpp:
+ (WebCore::SVGAltGlyphElement::hasValidGlyphElements const):
+ * svg/SVGFEImageElement.cpp:
+ (WebCore::SVGFEImageElement::buildPendingResource):
+ * svg/SVGGlyphRefElement.cpp:
+ (WebCore::SVGGlyphRefElement::hasValidGlyphElement const):
+ * svg/SVGLinearGradientElement.cpp:
+ (WebCore::SVGLinearGradientElement::collectGradientAttributes):
+ * svg/SVGMPathElement.cpp:
+ (WebCore::SVGMPathElement::buildPendingResource):
+ (WebCore::SVGMPathElement::pathElement):
+ * svg/SVGRadialGradientElement.cpp:
+ (WebCore::SVGRadialGradientElement::collectGradientAttributes):
+ * svg/SVGTRefElement.cpp:
+ (WebCore::SVGTRefElement::detachTarget):
+ (WebCore::SVGTRefElement::buildPendingResource):
+ * svg/SVGTextPathElement.cpp:
+ (WebCore::SVGTextPathElement::buildPendingResource):
+ * svg/SVGURIReference.cpp:
+ (WebCore::SVGURIReference::targetElementFromIRIString):
+ (WebCore::urlFromIRIStringWithFragmentIdentifier): Deleted.
+ * svg/SVGURIReference.h:
+ * svg/SVGUseElement.cpp:
+ (WebCore::SVGUseElement::findTarget const):
+ * svg/animation/SVGSMILElement.cpp:
+ (WebCore::SVGSMILElement::buildPendingResource):
+ * svg/graphics/filters/SVGFEImage.cpp:
+ (WebCore::FEImage::referencedRenderer const):
+
2018-11-22 Dean Jackson <d...@apple.com>
Implement WebGPUQueue and device.getQueue()
Modified: trunk/Source/WebCore/accessibility/AccessibilitySVGElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/accessibility/AccessibilitySVGElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/accessibility/AccessibilitySVGElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -65,11 +65,10 @@
if (href.isEmpty())
href = ""
- Element* target = SVGURIReference::targetElementFromIRIString(href, use.document());
- if (target)
- return axObjectCache()->getOrCreate(target);
-
- return nullptr;
+ auto target = SVGURIReference::targetElementFromIRIString(href, use.document());
+ if (!target.element)
+ return nullptr;
+ return axObjectCache()->getOrCreate(target.element.get());
}
template <typename ChildrenType>
Modified: trunk/Source/WebCore/css/CSSCursorImageValue.cpp (238451 => 238452)
--- trunk/Source/WebCore/css/CSSCursorImageValue.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/css/CSSCursorImageValue.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -69,7 +69,7 @@
if (!m_originalURL.hasFragmentIdentifier())
return nullptr;
- auto* element = SVGURIReference::targetElementFromIRIString(m_originalURL, document);
+ auto element = SVGURIReference::targetElementFromIRIString(m_originalURL, document).element;
if (!is<SVGCursorElement>(element))
return nullptr;
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp (238451 => 238452)
--- trunk/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -46,12 +46,12 @@
Path RenderSVGTextPath::layoutPath() const
{
- Element* targetElement = SVGURIReference::targetElementFromIRIString(textPathElement().href(), document());
- if (!targetElement || !targetElement->hasTagName(SVGNames::pathTag))
+ auto target = SVGURIReference::targetElementFromIRIString(textPathElement().href(), document());
+ if (!is<SVGPathElement>(target.element))
return Path();
-
- SVGPathElement& pathElement = downcast<SVGPathElement>(*targetElement);
-
+
+ SVGPathElement& pathElement = downcast<SVGPathElement>(*target.element);
+
Path path = pathFromGraphicsElement(&pathElement);
// Spec: The transform attribute on the referenced 'path' element represents a
Modified: trunk/Source/WebCore/svg/SVGAltGlyphElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGAltGlyphElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGAltGlyphElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -81,18 +81,17 @@
bool SVGAltGlyphElement::hasValidGlyphElements(Vector<String>& glyphNames) const
{
- String target;
- auto element = makeRefPtr(targetElementFromIRIString(getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr), document(), &target));
+ auto target = targetElementFromIRIString(getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr), document());
- if (is<SVGGlyphElement>(element)) {
- glyphNames.append(target);
+ if (is<SVGGlyphElement>(target.element)) {
+ glyphNames.append(target.identifier);
return true;
}
+
+ if (!is<SVGAltGlyphDefElement>(target.element))
+ return false;
- if (is<SVGAltGlyphDefElement>(element) && downcast<SVGAltGlyphDefElement>(*element).hasValidGlyphElements(glyphNames))
- return true;
-
- return false;
+ return downcast<SVGAltGlyphDefElement>(*target.element).hasValidGlyphElements(glyphNames);
}
}
Modified: trunk/Source/WebCore/svg/SVGFEImageElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGFEImageElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGFEImageElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -94,19 +94,18 @@
if (!isConnected())
return;
- String id;
- auto target = makeRefPtr(SVGURIReference::targetElementFromIRIString(href(), document(), &id));
- if (!target) {
- if (id.isEmpty())
+ auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+ if (!target.element) {
+ if (target.identifier.isEmpty())
requestImageResource();
else {
- document().accessSVGExtensions().addPendingResource(id, this);
+ document().accessSVGExtensions().addPendingResource(target.identifier, this);
ASSERT(hasPendingResources());
}
- } else if (target->isSVGElement()) {
+ } else if (target.element->isSVGElement()) {
// Register us with the target in the dependencies map. Any change of hrefElement
// that leads to relayout/repainting now informs us, so we can react to it.
- document().accessSVGExtensions().addElementReferencingTarget(this, downcast<SVGElement>(target.get()));
+ document().accessSVGExtensions().addElementReferencingTarget(this, downcast<SVGElement>(target.element.get()));
}
invalidate();
Modified: trunk/Source/WebCore/svg/SVGGlyphRefElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGGlyphRefElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGGlyphRefElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -50,7 +50,9 @@
{
// FIXME: We only support xlink:href so far.
// https://bugs.webkit.org/show_bug.cgi?id=64787
- return is<SVGGlyphElement>(targetElementFromIRIString(getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr), document(), &glyphName));
+ auto target = targetElementFromIRIString(getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr), document());
+ glyphName = target.identifier;
+ return is<SVGGlyphElement>(target.element);
}
static float parseFloat(const AtomicString& value)
Modified: trunk/Source/WebCore/svg/SVGLinearGradientElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGLinearGradientElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGLinearGradientElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -141,17 +141,17 @@
if (!renderer())
return false;
- HashSet<SVGGradientElement*> processedGradients;
- SVGGradientElement* current = this;
+ HashSet<Ref<SVGGradientElement>> processedGradients;
+ Ref<SVGGradientElement> current { *this };
- setGradientAttributes(*current, attributes);
- processedGradients.add(current);
+ setGradientAttributes(current.get(), attributes);
+ processedGradients.add(current.copyRef());
while (true) {
// Respect xlink:href, take attributes from referenced element
- auto refNode = makeRefPtr(SVGURIReference::targetElementFromIRIString(current->href(), document()));
- if (is<SVGGradientElement>(refNode)) {
- current = downcast<SVGGradientElement>(refNode.get());
+ auto target = SVGURIReference::targetElementFromIRIString(current->href(), document());
+ if (is<SVGGradientElement>(target.element)) {
+ current = downcast<SVGGradientElement>(*target.element);
// Cycle detection
if (processedGradients.contains(current))
@@ -160,8 +160,8 @@
if (!current->renderer())
return false;
- setGradientAttributes(*current, attributes, current->hasTagName(SVGNames::linearGradientTag));
- processedGradients.add(current);
+ setGradientAttributes(current.get(), attributes, current->hasTagName(SVGNames::linearGradientTag));
+ processedGradients.add(current.copyRef());
} else
return true;
}
Modified: trunk/Source/WebCore/svg/SVGMPathElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGMPathElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGMPathElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -55,21 +55,20 @@
if (!isConnected())
return;
- String id;
- auto target = makeRefPtr(SVGURIReference::targetElementFromIRIString(href(), document(), &id));
- if (!target) {
+ auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+ if (!target.element) {
// Do not register as pending if we are already pending this resource.
- if (document().accessSVGExtensions().isPendingResource(this, id))
+ if (document().accessSVGExtensions().isPendingResource(this, target.identifier))
return;
- if (!id.isEmpty()) {
- document().accessSVGExtensions().addPendingResource(id, this);
+ if (!target.identifier.isEmpty()) {
+ document().accessSVGExtensions().addPendingResource(target.identifier, this);
ASSERT(hasPendingResources());
}
- } else if (target->isSVGElement()) {
+ } else if (target.element->isSVGElement()) {
// Register us with the target in the dependencies map. Any change of hrefElement
// that leads to relayout/repainting now informs us, so we can react to it.
- document().accessSVGExtensions().addElementReferencingTarget(this, downcast<SVGElement>(target.get()));
+ document().accessSVGExtensions().addElementReferencingTarget(this, downcast<SVGElement>(target.element.get()));
}
targetPathChanged();
@@ -122,9 +121,9 @@
RefPtr<SVGPathElement> SVGMPathElement::pathElement()
{
- Element* target = targetElementFromIRIString(href(), document());
- if (is<SVGPathElement>(target))
- return downcast<SVGPathElement>(target);
+ auto target = targetElementFromIRIString(href(), document());
+ if (is<SVGPathElement>(target.element))
+ return downcast<SVGPathElement>(target.element.get());
return nullptr;
}
Modified: trunk/Source/WebCore/svg/SVGRadialGradientElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGRadialGradientElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGRadialGradientElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -161,9 +161,9 @@
while (true) {
// Respect xlink:href, take attributes from referenced element
- auto refNode = makeRefPtr(SVGURIReference::targetElementFromIRIString(current->href(), document()));
- if (is<SVGGradientElement>(refNode)) {
- current = downcast<SVGGradientElement>(refNode.get());
+ auto target = SVGURIReference::targetElementFromIRIString(current->href(), document());
+ if (is<SVGGradientElement>(target.element)) {
+ current = downcast<SVGGradientElement>(target.element.get());
// Cycle detection
if (processedGradients.contains(current))
Modified: trunk/Source/WebCore/svg/SVGTRefElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGTRefElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGTRefElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -167,10 +167,9 @@
return;
// Mark the referenced ID as pending.
- String id;
- SVGURIReference::targetElementFromIRIString(href(), document(), &id);
- if (!id.isEmpty())
- document().accessSVGExtensions().addPendingResource(id, this);
+ auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+ if (!target.identifier.isEmpty())
+ document().accessSVGExtensions().addPendingResource(target.identifier, this);
}
void SVGTRefElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
@@ -231,13 +230,12 @@
if (!isConnected())
return;
- String id;
- RefPtr<Element> target = SVGURIReference::targetElementFromIRIString(href(), document(), &id);
- if (!target.get()) {
- if (id.isEmpty())
+ auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+ if (!target.element) {
+ if (target.identifier.isEmpty())
return;
- document().accessSVGExtensions().addPendingResource(id, this);
+ document().accessSVGExtensions().addPendingResource(target.identifier, this);
ASSERT(hasPendingResources());
return;
}
@@ -247,9 +245,9 @@
// expects every element instance to have an associated shadow tree element - which is not the
// case when we land here from SVGUseElement::buildShadowTree().
if (!isInShadowTree())
- m_targetListener->attach(target.copyRef());
+ m_targetListener->attach(target.element.copyRef());
- updateReferencedText(target.get());
+ updateReferencedText(target.element.get());
}
Node::InsertedIntoAncestorResult SVGTRefElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
Modified: trunk/Source/WebCore/svg/SVGTextPathElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGTextPathElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGTextPathElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -141,21 +141,20 @@
if (!isConnected())
return;
- String id;
- auto target = makeRefPtr(SVGURIReference::targetElementFromIRIString(href(), document(), &id));
- if (!target) {
+ auto target = SVGURIReference::targetElementFromIRIString(href(), document());
+ if (!target.element) {
// Do not register as pending if we are already pending this resource.
- if (document().accessSVGExtensions().isPendingResource(this, id))
+ if (document().accessSVGExtensions().isPendingResource(this, target.identifier))
return;
- if (!id.isEmpty()) {
- document().accessSVGExtensions().addPendingResource(id, this);
+ if (!target.identifier.isEmpty()) {
+ document().accessSVGExtensions().addPendingResource(target.identifier, this);
ASSERT(hasPendingResources());
}
- } else if (target->hasTagName(SVGNames::pathTag)) {
+ } else if (target.element->hasTagName(SVGNames::pathTag)) {
// Register us with the target in the dependencies map. Any change of hrefElement
// that leads to relayout/repainting now informs us, so we can react to it.
- document().accessSVGExtensions().addElementReferencingTarget(this, downcast<SVGElement>(target.get()));
+ document().accessSVGExtensions().addElementReferencingTarget(this, downcast<SVGElement>(target.element.get()));
}
}
Modified: trunk/Source/WebCore/svg/SVGURIReference.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGURIReference.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGURIReference.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -87,47 +87,30 @@
return emptyString();
}
-static inline URL urlFromIRIStringWithFragmentIdentifier(const String& url, const Document& document, String& fragmentIdentifier)
+auto SVGURIReference::targetElementFromIRIString(const String& iri, const Document& document, RefPtr<Document> externalDocument) -> TargetElementResult
{
- size_t startOfFragmentIdentifier = url.find('#');
+ // If there's no fragment identifier contained within the IRI string, we can't lookup an element.
+ size_t startOfFragmentIdentifier = iri.find('#');
if (startOfFragmentIdentifier == notFound)
- return URL();
+ return { };
// Exclude the '#' character when determining the fragmentIdentifier.
- fragmentIdentifier = url.substring(startOfFragmentIdentifier + 1);
- if (startOfFragmentIdentifier) {
- URL base(document.baseURL(), url.substring(0, startOfFragmentIdentifier));
- return URL(base, url.substring(startOfFragmentIdentifier));
- }
-
- return URL(document.baseURL(), url.substring(startOfFragmentIdentifier));
-}
-
-Element* SVGURIReference::targetElementFromIRIString(const String& iri, const Document& document, String* fragmentIdentifier, const Document* externalDocument)
-{
- // If there's no fragment identifier contained within the IRI string, we can't lookup an element.
- String id;
- URL url = "" document, id);
- if (url == URL())
- return 0;
-
- if (fragmentIdentifier)
- *fragmentIdentifier = id;
-
+ auto id = iri.substring(startOfFragmentIdentifier + 1);
if (id.isEmpty())
- return 0;
+ return { };
+ auto url = ""
if (externalDocument) {
// Enforce that the referenced url matches the url of the document that we've loaded for it!
ASSERT(equalIgnoringFragmentIdentifier(url, externalDocument->url()));
- return externalDocument->getElementById(id);
+ return { externalDocument->getElementById(id), WTFMove(id) };
}
// Exit early if the referenced url is external, and we have no externalDocument given.
if (isExternalURIReference(iri, document))
- return 0;
+ return { nullptr, WTFMove(id) };
- return document.getElementById(id);
+ return { document.getElementById(id), WTFMove(id) };
}
}
Modified: trunk/Source/WebCore/svg/SVGURIReference.h (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGURIReference.h 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGURIReference.h 2018-11-22 23:47:33 UTC (rev 238452)
@@ -41,8 +41,13 @@
void parseAttribute(const QualifiedName&, const AtomicString&);
static String fragmentIdentifierFromIRIString(const String&, const Document&);
- static Element* targetElementFromIRIString(const String&, const Document&, String* fragmentIdentifier = nullptr, const Document* externalDocument = nullptr);
+ struct TargetElementResult {
+ RefPtr<Element> element;
+ String identifier;
+ };
+ static TargetElementResult targetElementFromIRIString(const String&, const Document&, RefPtr<Document> externalDocument = nullptr);
+
static bool isExternalURIReference(const String& uri, const Document& document)
{
// Fragment-only URIs are always internal
Modified: trunk/Source/WebCore/svg/SVGUseElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/SVGUseElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/SVGUseElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -410,18 +410,19 @@
auto* correspondingElement = this->correspondingElement();
auto& original = correspondingElement ? downcast<SVGUseElement>(*correspondingElement) : *this;
- auto targetCandidate = makeRefPtr(targetElementFromIRIString(original.href(), original.document(), targetID, original.externalDocument()));
- if (targetID && !targetID->isNull()) {
+ auto targetResult = targetElementFromIRIString(original.href(), original.document(), original.externalDocument());
+ if (targetID) {
+ *targetID = WTFMove(targetResult.identifier);
// If the reference is external, don't return the target ID to the caller.
// The caller would use the target ID to wait for a pending resource on the wrong document.
// If we ever want the change that and let the caller to wait on the external document,
// we should change this function so it returns the appropriate document to go with the ID.
- if (isExternalURIReference(original.href(), original.document()))
- *targetID = String();
+ if (!targetID->isNull() && isExternalURIReference(original.href(), original.document()))
+ *targetID = String { };
}
- if (!is<SVGElement>(targetCandidate))
+ if (!is<SVGElement>(targetResult.element))
return nullptr;
- auto& target = downcast<SVGElement>(*targetCandidate);
+ auto& target = downcast<SVGElement>(*targetResult.element);
if (!target.isConnected() || isDisallowedElement(target))
return nullptr;
Modified: trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -183,8 +183,11 @@
auto& href = ""
if (href.isEmpty())
target = parentElement();
- else
- target = SVGURIReference::targetElementFromIRIString(href.string(), document(), &id);
+ else {
+ auto result = SVGURIReference::targetElementFromIRIString(href.string(), document());
+ target = WTFMove(result.element);
+ id = WTFMove(result.identifier);
+ }
SVGElement* svgTarget = is<SVGElement>(target) ? downcast<SVGElement>(target.get()) : nullptr;
if (svgTarget && !svgTarget->isConnected())
Modified: trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.cpp (238451 => 238452)
--- trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.cpp 2018-11-22 21:17:41 UTC (rev 238451)
+++ trunk/Source/WebCore/svg/graphics/filters/SVGFEImage.cpp 2018-11-22 23:47:33 UTC (rev 238452)
@@ -81,11 +81,11 @@
RenderElement* FEImage::referencedRenderer() const
{
if (!m_document)
- return 0;
- Element* hrefElement = SVGURIReference::targetElementFromIRIString(m_href, *m_document);
- if (!hrefElement || !hrefElement->isSVGElement())
- return 0;
- return hrefElement->renderer();
+ return nullptr;
+ auto target = SVGURIReference::targetElementFromIRIString(m_href, *m_document);
+ if (!is<SVGElement>(target.element))
+ return nullptr;
+ return target.element->renderer();
}
void FEImage::platformApplySoftware()