diff options
Diffstat (limited to 'Source/WebCore')
109 files changed, 1450 insertions, 785 deletions
diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt index cb9244302..ff9e12889 100644 --- a/Source/WebCore/CMakeLists.txt +++ b/Source/WebCore/CMakeLists.txt @@ -2099,6 +2099,7 @@ set(WebCore_SOURCES platform/FileSystem.cpp platform/Language.cpp platform/Length.cpp + platform/LengthPoint.cpp platform/LengthSize.cpp platform/LinkHash.cpp platform/Logging.cpp @@ -3352,6 +3353,11 @@ if (ENABLE_USER_MESSAGE_HANDLERS) ) endif () +if (USE_WOFF2) + list(APPEND WebCore_INCLUDE_DIRECTORIES "${THIRDPARTY_DIR}/woff2/src") + list(APPEND WebCore_LIBRARIES woff2) +endif () + set(WebCoreTestSupport_INCLUDE_DIRECTORIES "${WEBCORE_DIR}/platform/mock" "${WEBCORE_DIR}/testing" @@ -3782,7 +3788,7 @@ if (ENABLE_GRAPHICS_CONTEXT_3D AND NOT WIN32) set_target_properties(ANGLESupport PROPERTIES FOLDER "WebCore") # Suppress null conversion warnings for sources in Source/ThirdParty/ANGLE - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + if (COMPILER_IS_CLANG) ADD_TARGET_PROPERTIES(ANGLESupport COMPILE_FLAGS "-Wno-null-conversion") endif () diff --git a/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.cpp b/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.cpp index f5bc6a8c3..9272dfc98 100644 --- a/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.cpp +++ b/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.cpp @@ -35,6 +35,10 @@ #include "Page.h" #include "SecurityOrigin.h" +#if PLATFORM(QT) +#include "Settings.h" +#endif + namespace WebCore { DOMWindowIndexedDatabase::DOMWindowIndexedDatabase(DOMWindow* window) @@ -93,9 +97,9 @@ void DOMWindowIndexedDatabase::willDetachGlobalObjectFromFrame() DOMWindowProperty::willDetachGlobalObjectFromFrame(); } -IDBFactory* DOMWindowIndexedDatabase::indexedDB(DOMWindow* window) +IDBFactory* DOMWindowIndexedDatabase::indexedDB(DOMWindow& window) { - return from(window)->indexedDB(); + return from(&window)->indexedDB(); } IDBFactory* DOMWindowIndexedDatabase::indexedDB() @@ -108,6 +112,11 @@ IDBFactory* DOMWindowIndexedDatabase::indexedDB() if (!page) return nullptr; +#if PLATFORM(QT) + if (!page->settings().offlineStorageDatabaseEnabled()) + return nullptr; +#endif + if (!m_window->isCurrentlyDisplayedInFrame()) return nullptr; diff --git a/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.h b/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.h index 3ffb71c5c..7f3c193a9 100644 --- a/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.h +++ b/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.h @@ -44,7 +44,7 @@ public: static DOMWindowIndexedDatabase* from(DOMWindow*); - static IDBFactory* indexedDB(DOMWindow*); + static IDBFactory* indexedDB(DOMWindow&); virtual void disconnectFrameForDocumentSuspension() override; virtual void reconnectFrameFromDocumentSuspension(Frame*) override; diff --git a/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.idl b/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.idl index d1b02038f..72b7b2750 100644 --- a/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.idl +++ b/Source/WebCore/Modules/indexeddb/DOMWindowIndexedDatabase.idl @@ -27,6 +27,7 @@ [ Conditional=INDEXED_DATABASE, ] partial interface DOMWindow { - // This space is intentionally left blank. + [EnabledAtRuntime=IndexedDB] readonly attribute IDBFactory indexedDB; + [EnabledAtRuntime=IndexedDB, ImplementedAs=indexedDB] readonly attribute IDBFactory webkitIndexedDB; }; diff --git a/Source/WebCore/Modules/webdatabase/DatabaseContext.cpp b/Source/WebCore/Modules/webdatabase/DatabaseContext.cpp index 42be91b15..8f3ff3665 100644 --- a/Source/WebCore/Modules/webdatabase/DatabaseContext.cpp +++ b/Source/WebCore/Modules/webdatabase/DatabaseContext.cpp @@ -198,6 +198,10 @@ bool DatabaseContext::allowDatabaseAccess() const { if (is<Document>(*m_scriptExecutionContext)) { Document& document = downcast<Document>(*m_scriptExecutionContext); +#if PLATFORM(QT) + if (document.page() && !document.page()->settings().offlineStorageDatabaseEnabled()) + return false; +#endif if (!document.page() || (document.page()->usesEphemeralSession() && !SchemeRegistry::allowsDatabaseAccessInPrivateBrowsing(document.securityOrigin()->protocol()))) return false; return true; diff --git a/Source/WebCore/accessibility/AccessibilityNodeObject.cpp b/Source/WebCore/accessibility/AccessibilityNodeObject.cpp index 1e3a91518..5be294ff0 100644 --- a/Source/WebCore/accessibility/AccessibilityNodeObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityNodeObject.cpp @@ -1354,7 +1354,6 @@ void AccessibilityNodeObject::visibleText(Vector<AccessibilityText>& textOrder) case RadioButtonRole: case SwitchRole: case TabRole: - case ProgressIndicatorRole: useTextUnderElement = true; break; default: @@ -1395,9 +1394,17 @@ void AccessibilityNodeObject::helpText(Vector<AccessibilityText>& textOrder) con textOrder.append(AccessibilityText(summary, SummaryText)); // The title attribute should be used as help text unless it is already being used as descriptive text. + // However, when the title attribute is the only text alternative provided, it may be exposed as the + // descriptive text. This is problematic in the case of meters because the HTML spec suggests authors + // can expose units through this attribute. Therefore, if the element is a meter, change its source + // type to HelpText. const AtomicString& title = getAttribute(titleAttr); - if (!title.isEmpty()) - textOrder.append(AccessibilityText(title, TitleTagText)); + if (!title.isEmpty()) { + if (!isMeter()) + textOrder.append(AccessibilityText(title, TitleTagText)); + else + textOrder.append(AccessibilityText(title, HelpText)); + } } void AccessibilityNodeObject::accessibilityText(Vector<AccessibilityText>& textOrder) @@ -1893,6 +1900,32 @@ static String accessibleNameForNode(Node* node, Node* labelledbyNode) return String(); } +String AccessibilityNodeObject::accessibilityDescriptionForChildren() const +{ + Node* node = this->node(); + if (!node) + return String(); + + AXObjectCache* cache = axObjectCache(); + if (!cache) + return String(); + + StringBuilder builder; + for (Node* child = node->firstChild(); child; child = child->nextSibling()) { + if (!is<Element>(child)) + continue; + + if (AccessibilityObject* axObject = cache->getOrCreate(child)) { + String description = axObject->ariaLabeledByAttribute(); + if (description.isEmpty()) + description = accessibleNameForNode(child); + appendNameToStringBuilder(builder, description); + } + } + + return builder.toString(); +} + String AccessibilityNodeObject::accessibilityDescriptionForElements(Vector<Element*> &elements) const { StringBuilder builder; diff --git a/Source/WebCore/accessibility/AccessibilityNodeObject.h b/Source/WebCore/accessibility/AccessibilityNodeObject.h index 5a9f351ed..7b63eaa67 100644 --- a/Source/WebCore/accessibility/AccessibilityNodeObject.h +++ b/Source/WebCore/accessibility/AccessibilityNodeObject.h @@ -123,6 +123,7 @@ public: virtual unsigned hierarchicalLevel() const override; virtual String textUnderElement(AccessibilityTextUnderElementMode = AccessibilityTextUnderElementMode()) const override; + virtual String accessibilityDescriptionForChildren() const; virtual String accessibilityDescription() const override; virtual String helpText() const override; virtual String title() const override; diff --git a/Source/WebCore/accessibility/AccessibilityProgressIndicator.cpp b/Source/WebCore/accessibility/AccessibilityProgressIndicator.cpp index f3a13d918..19485396f 100644 --- a/Source/WebCore/accessibility/AccessibilityProgressIndicator.cpp +++ b/Source/WebCore/accessibility/AccessibilityProgressIndicator.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "AccessibilityProgressIndicator.h" +#include "AXObjectCache.h" #include "FloatConversion.h" #include "HTMLMeterElement.h" #include "HTMLNames.h" @@ -60,6 +61,36 @@ bool AccessibilityProgressIndicator::computeAccessibilityIsIgnored() const return accessibilityIsIgnoredByDefault(); } +String AccessibilityProgressIndicator::valueDescription() const +{ + // If the author has explicitly provided a value through aria-valuetext, use it. + String description = AccessibilityRenderObject::valueDescription(); + if (!description.isEmpty()) + return description; + +#if ENABLE(METER_ELEMENT) + if (!m_renderer->isMeter()) + return String(); + + HTMLMeterElement* meter = meterElement(); + if (!meter) + return String(); + + // The HTML spec encourages authors to include a textual representation of the meter's state in + // the element's contents. We'll fall back on that if there is not a more accessible alternative. + AccessibilityObject* axMeter = axObjectCache()->getOrCreate(meter); + if (is<AccessibilityNodeObject>(axMeter)) { + description = downcast<AccessibilityNodeObject>(axMeter)->accessibilityDescriptionForChildren(); + if (!description.isEmpty()) + return description; + } + + return meter->textContent(); +#endif + + return String(); +} + float AccessibilityProgressIndicator::valueForRange() const { if (!m_renderer) diff --git a/Source/WebCore/accessibility/AccessibilityProgressIndicator.h b/Source/WebCore/accessibility/AccessibilityProgressIndicator.h index f58f39460..3833b2c2c 100644 --- a/Source/WebCore/accessibility/AccessibilityProgressIndicator.h +++ b/Source/WebCore/accessibility/AccessibilityProgressIndicator.h @@ -46,6 +46,7 @@ private: virtual bool isProgressIndicator() const override { return true; } + virtual String valueDescription() const override; virtual float valueForRange() const override; virtual float maxValueForRange() const override; virtual float minValueForRange() const override; diff --git a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp index 67df80e1a..dff12e007 100644 --- a/Source/WebCore/accessibility/AccessibilityRenderObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityRenderObject.cpp @@ -1366,6 +1366,15 @@ bool AccessibilityRenderObject::computeAccessibilityIsIgnored() const if (isWebArea()) return false; +#if ENABLE(METER_ELEMENT) + // The render tree of meter includes a RenderBlock (meter) and a RenderMeter (div). + // We expose the latter and thus should ignore the former. However, if the author + // includes a title attribute on the element, hasAttributesRequiredForInclusion() + // will return true, potentially resulting in a redundant accessible object. + if (is<HTMLMeterElement>(node)) + return true; +#endif + // Using the presence of an accessible name to decide an element's visibility is not // as definitive as previous checks, so this should remain as one of the last. if (hasAttributesRequiredForInclusion()) diff --git a/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp b/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp index a873067df..353b0b1b8 100644 --- a/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp +++ b/Source/WebCore/accessibility/atk/WebKitAccessibleWrapperAtk.cpp @@ -108,54 +108,24 @@ static const gchar* webkitAccessibleGetName(AtkObject* object) g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0); returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0); - AccessibilityObject* coreObject = core(object); - if (coreObject->isFieldset()) { - AccessibilityObject* label = coreObject->titleUIElement(); - if (label) { - AtkObject* atkObject = label->wrapper(); - if (ATK_IS_TEXT(atkObject)) - return atk_text_get_text(ATK_TEXT(atkObject), 0, -1); - } - } - - if (coreObject->isControl()) { - AccessibilityObject* label = coreObject->correspondingLabelForControlElement(); - if (label) { - AtkObject* atkObject = label->wrapper(); - if (ATK_IS_TEXT(atkObject)) - return atk_text_get_text(ATK_TEXT(atkObject), 0, -1); - } - - // Try text under the node. - String textUnder = coreObject->textUnderElement(); - if (textUnder.length()) - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, textUnder); - } - - if (coreObject->isImage() || coreObject->isInputImage() || coreObject->isImageMap() || coreObject->isImageMapLink()) { - Node* node = coreObject->node(); - if (is<HTMLElement>(node)) { - // Get the attribute rather than altText String so as not to fall back on title. - const AtomicString& alt = downcast<HTMLElement>(*node).getAttribute(HTMLNames::altAttr); - if (!alt.isEmpty()) - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, alt); - } + Vector<AccessibilityText> textOrder; + core(object)->accessibilityText(textOrder); + + for (const auto& text : textOrder) { + // FIXME: This check is here because AccessibilityNodeObject::titleElementText() + // appends an empty String for the LabelByElementText source when there is a + // titleUIElement(). Removing this check makes some fieldsets lose their name. + if (text.text.isEmpty()) + continue; + + // WebCore Accessibility should provide us with the text alternative computation + // in the order defined by that spec. So take the first thing that our platform + // does not expose via the AtkObject description. + if (text.textSource != HelpText && text.textSource != SummaryText) + return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, text.text); } - // Fallback for the webArea object: just return the document's title. - if (coreObject->isWebArea()) { - Document* document = coreObject->document(); - if (document) - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, document->title()); - } - - // Nothing worked so far, try with the AccessibilityObject's - // title() before going ahead with stringValue(). - String axTitle = accessibilityTitle(coreObject); - if (!axTitle.isEmpty()) - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, axTitle); - - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, coreObject->stringValue()); + return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, ""); } static const gchar* webkitAccessibleGetDescription(AtkObject* object) @@ -163,27 +133,26 @@ static const gchar* webkitAccessibleGetDescription(AtkObject* object) g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0); returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0); - AccessibilityObject* coreObject = core(object); - Node* node = nullptr; - if (coreObject->isAccessibilityRenderObject()) - node = coreObject->node(); - if (!is<HTMLElement>(node) || coreObject->ariaRoleAttribute() != UnknownRole || coreObject->isImage()) - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, accessibilityDescription(coreObject)); - - // atk_table_get_summary returns an AtkObject. We have no summary object, so expose summary here. - if (coreObject->roleValue() == TableRole) { - const AtomicString& summary = downcast<HTMLTableElement>(*node).summary(); - if (!summary.isEmpty()) - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, summary); - } + Vector<AccessibilityText> textOrder; + core(object)->accessibilityText(textOrder); + + bool nameTextAvailable = false; + for (const auto& text : textOrder) { + // WebCore Accessibility should provide us with the text alternative computation + // in the order defined by that spec. So take the first thing that our platform + // does not expose via the AtkObject name. + if (text.textSource == HelpText || text.textSource == SummaryText) + return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, text.text); - // The title attribute should be reliably available as the object's descripton. - // We do not want to fall back on other attributes in its absence. See bug 25524. - String title = downcast<HTMLElement>(*node).title(); - if (!title.isEmpty()) - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, title); + // If there is no other text alternative, the title tag contents will have been + // used for the AtkObject name. We don't want to duplicate it here. + if (text.textSource == TitleTagText && nameTextAvailable) + return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, text.text); - return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, accessibilityDescription(coreObject)); + nameTextAvailable = true; + } + + return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, ""); } static void removeAtkRelationByType(AtkRelationSet* relationSet, AtkRelationType relationType) @@ -458,6 +427,10 @@ static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object) if (!isReadOnly.isEmpty()) attributeSet = addToAtkAttributeSet(attributeSet, "readonly", isReadOnly.utf8().data()); + String valueDescription = coreObject->valueDescription(); + if (!valueDescription.isEmpty()) + attributeSet = addToAtkAttributeSet(attributeSet, "valuetext", valueDescription.utf8().data()); + // According to the W3C Core Accessibility API Mappings 1.1, section 5.4.1 General Rules: // "User agents must expose the WAI-ARIA role string if the API supports a mechanism to do so." // In the case of ATK, the mechanism to do so is an object attribute pair (xml-roles:"string"). @@ -544,8 +517,7 @@ static AtkRole atkRole(AccessibilityObject* coreObject) case BusyIndicatorRole: return ATK_ROLE_PROGRESS_BAR; // Is this right? case ProgressIndicatorRole: - // return ATK_ROLE_SPIN_BUTTON; // Some confusion about this role in AccessibilityRenderObject.cpp - return ATK_ROLE_PROGRESS_BAR; + return coreObject->isMeter() ? ATK_ROLE_LEVEL_BAR : ATK_ROLE_PROGRESS_BAR; case WindowRole: return ATK_ROLE_WINDOW; case PopUpButtonRole: diff --git a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp index 8d6a4c33b..0154a04b9 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp @@ -76,21 +76,6 @@ static EncodedJSValue jsDOMWindowWebKit(ExecState* exec, EncodedJSValue thisValu } #endif -#if ENABLE(INDEXED_DATABASE) -static EncodedJSValue jsDOMWindowIndexedDB(ExecState* exec, EncodedJSValue thisValue, PropertyName) -{ - UNUSED_PARAM(exec); - auto* castedThis = toJSDOMWindow(JSValue::decode(thisValue)); - if (!RuntimeEnabledFeatures::sharedFeatures().indexedDBEnabled()) - return JSValue::encode(jsUndefined()); - if (!castedThis || !BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->wrapped())) - return JSValue::encode(jsUndefined()); - auto& impl = castedThis->wrapped(); - JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(DOMWindowIndexedDatabase::indexedDB(&impl))); - return JSValue::encode(result); -} -#endif - static bool jsDOMWindowGetOwnPropertySlotRestrictedAccess(JSDOMWindow* thisObject, Frame* frame, ExecState* exec, PropertyName propertyName, PropertySlot& slot, String& errorMessage) { // Allow access to toString() cross-domain, but always Object.prototype.toString. @@ -263,16 +248,6 @@ bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* exec, Property if (getStaticPropertySlot<JSDOMWindow, Base>(exec, *JSDOMWindow::info()->staticPropHashTable, thisObject, propertyName, slot)) return true; -#if ENABLE(INDEXED_DATABASE) - // FIXME: With generated JS bindings built on static property tables there is no way to - // completely remove a generated property at runtime. So to completely disable IndexedDB - // at runtime we have to not generate these accessors and have to handle them specially here. - // Once https://webkit.org/b/145669 is resolved, they can once again be auto generated. - if (RuntimeEnabledFeatures::sharedFeatures().indexedDBEnabled() && (propertyName == exec->propertyNames().indexedDB || propertyName == exec->propertyNames().webkitIndexedDB)) { - slot.setCustom(thisObject, DontDelete | ReadOnly | CustomAccessor, jsDOMWindowIndexedDB); - return true; - } -#endif #if ENABLE(USER_MESSAGE_HANDLERS) if (propertyName == exec->propertyNames().webkit && thisObject->wrapped().shouldHaveWebKitNamespaceForWorld(thisObject->world())) { slot.setCacheableCustom(thisObject, DontDelete | ReadOnly, jsDOMWindowWebKit); diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm index 5e8905460..9dbf5105d 100644 --- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm +++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm @@ -730,6 +730,23 @@ sub OperationShouldBeOnInstance return 0; } +sub GetJSCAttributesForAttribute +{ + my $interface = shift; + my $attribute = shift; + + my @specials = (); + push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute); + + # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable. + my $is_global_constructor = $attribute->signature->type =~ /Constructor$/; + push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor); + push(@specials, "ReadOnly") if IsReadonly($attribute); + push(@specials, "CustomAccessor") unless $is_global_constructor or IsJSBuiltin($interface, $attribute); + push(@specials, "Accessor | Builtin") if IsJSBuiltin($interface, $attribute); + return (@specials > 0) ? join(" | ", @specials) : "0"; +} + sub GetIndexedGetterFunction { my $interface = shift; @@ -1225,6 +1242,7 @@ sub GenerateHeader # Constructor if ($interfaceName eq "DOMWindow") { push(@headerContent, " $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&, JSDOMWindowShell*);\n"); + push(@headerContent, " void finishCreation(JSC::VM&, JSDOMWindowShell*);\n"); } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) { push(@headerContent, " $className(JSC::VM&, JSC::Structure*, Ref<$implType>&&);\n"); } elsif (!NeedsImplementationClass($interface)) { @@ -1387,19 +1405,17 @@ sub GeneratePropertiesHashTable foreach my $attribute (@{$interface->attributes}) { next if ($attribute->isStatic); next if AttributeShouldBeOnInstance($interface, $attribute) != $isInstance; + + # DOMWindow adds RuntimeEnabled attributes after creation so do not add them to the static table. + if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) { + $propertyCount -= 1; + next; + } + my $name = $attribute->signature->name; push(@$hashKeys, $name); - my @specials = (); - push(@specials, "DontDelete") if IsUnforgeable($interface, $attribute); - - # As per Web IDL specification, constructor properties on the ECMAScript global object should not be enumerable. - my $is_global_constructor = $attribute->signature->type =~ /Constructor$/; - push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{"NotEnumerable"} || $is_global_constructor); - push(@specials, "ReadOnly") if IsReadonly($attribute); - push(@specials, "CustomAccessor") unless $is_global_constructor or IsJSBuiltin($interface, $attribute); - push(@specials, "Accessor | Builtin") if IsJSBuiltin($interface, $attribute); - my $special = (@specials > 0) ? join(" | ", @specials) : "0"; + my $special = GetJSCAttributesForAttribute($interface, $attribute); push(@$hashSpecials, $special); my $getter = GetAttributeGetterName($interfaceName, $className, $interface, $attribute); @@ -2157,6 +2173,29 @@ sub GenerateImplementation push(@implContent, " : $parentClassName(vm, structure, WTFMove(impl), shell)\n"); push(@implContent, "{\n"); push(@implContent, "}\n\n"); + + push(@implContent, "void ${className}::finishCreation(VM& vm, JSDOMWindowShell* shell)\n"); + push(@implContent, "{\n"); + push(@implContent, " Base::finishCreation(vm, shell);\n\n"); + # Support for RuntimeEnabled attributes on DOMWindow. + foreach my $attribute (@{$interface->attributes}) { + next unless $attribute->signature->extendedAttributes->{"EnabledAtRuntime"}; + + AddToImplIncludes("RuntimeEnabledFeatures.h"); + my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature); + push(@implContent, "#if ${conditionalString}\n") if $conditionalString; + my $enable_function = GetRuntimeEnableFunctionName($attribute->signature); + my $attributeName = $attribute->signature->name; + push(@implContent, " if (${enable_function}()) {\n"); + my $getter = GetAttributeGetterName($interfaceName, $className, $interface, $attribute); + my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interfaceName, $className, $interface, $attribute); + push(@implContent, " auto* customGetterSetter = CustomGetterSetter::create(vm, $getter, $setter);\n"); + my $jscAttributes = GetJSCAttributesForAttribute($interface, $attribute); + push(@implContent, " putDirectCustomAccessor(vm, vm.propertyNames->$attributeName, customGetterSetter, attributesForStructure($jscAttributes));\n"); + push(@implContent, " }\n"); + push(@implContent, "#endif\n") if $conditionalString; + } + push(@implContent, "}\n\n"); } elsif ($codeGenerator->InheritsInterface($interface, "WorkerGlobalScope")) { AddIncludesForTypeInImpl($interfaceName); push(@implContent, "${className}::$className(VM& vm, Structure* structure, Ref<$implType>&& impl)\n"); @@ -2340,12 +2379,7 @@ sub GenerateImplementation # Global constructors can be disabled at runtime. if ($attribute->signature->type =~ /Constructor$/) { - if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) { - AddToImplIncludes("RuntimeEnabledFeatures.h"); - my $enable_function = GetRuntimeEnableFunctionName($attribute->signature); - push(@implContent, " if (!${enable_function}())\n"); - push(@implContent, " return JSValue::encode(jsUndefined());\n"); - } elsif ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) { + if ($attribute->signature->extendedAttributes->{"EnabledBySetting"}) { AddToImplIncludes("Frame.h"); AddToImplIncludes("Settings.h"); my $enable_function = ToMethodName($attribute->signature->extendedAttributes->{"EnabledBySetting"}) . "Enabled"; diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp index 79da5802c..afb1c69c2 100644 --- a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp @@ -2991,6 +2991,12 @@ RefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID, return zoomAdjustedPixelValueForLength(style->minWidth(), *style); case CSSPropertyObjectFit: return cssValuePool.createValue(style->objectFit()); + case CSSPropertyObjectPosition: { + RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); + list->append(zoomAdjustedPixelValueForLength(style->objectPosition().x(), *style)); + list->append(zoomAdjustedPixelValueForLength(style->objectPosition().y(), *style)); + return list; + } case CSSPropertyOpacity: return cssValuePool.createValue(style->opacity(), CSSPrimitiveValue::CSS_NUMBER); case CSSPropertyOrphans: diff --git a/Source/WebCore/css/CSSFontFace.cpp b/Source/WebCore/css/CSSFontFace.cpp index 552e99cfa..008ef8594 100644 --- a/Source/WebCore/css/CSSFontFace.cpp +++ b/Source/WebCore/css/CSSFontFace.cpp @@ -276,6 +276,8 @@ void CSSFontFace::setStatus(Status newStatus) void CSSFontFace::fontLoaded(CSSFontFaceSource&) { + Ref<CSSFontFace> protectedThis(*this); + // If the font is already in the cache, CSSFontFaceSource may report it's loaded before it is added here as a source. // Let's not pump the state machine until we've got all our sources. font() and load() are smart enough to act correctly // when a source is failed or succeeded before we have asked it to load. diff --git a/Source/WebCore/css/CSSGrammar.y.in b/Source/WebCore/css/CSSGrammar.y.in index 8cc70be80..0aad45663 100644 --- a/Source/WebCore/css/CSSGrammar.y.in +++ b/Source/WebCore/css/CSSGrammar.y.in @@ -294,12 +294,12 @@ static bool selectorListDoesNotMatchAnyPseudoElement(const Vector<std::unique_pt %type <keyframeRuleList> keyframes_rule %destructor { delete $$; } keyframes_rule -// These parser values never need to be destroyed because they are never functions or value lists. -%type <value> calc_func_term key unary_term +// These parser values never need to be destroyed because they are never functions, value lists, or variables. +%type <value> key unary_term -// These parser values need to be destroyed because they might be functions. -%type <value> calc_function function variable_function min_or_max_function term -%destructor { destroy($$); } calc_function function variable_function min_or_max_function term +// These parser values need to be destroyed because they might be functions, value lists, or variables. +%type <value> calc_func_term calc_function function min_or_max_function term variable_function +%destructor { destroy($$); } calc_func_term calc_function function min_or_max_function term variable_function %type <id> property @@ -823,14 +823,18 @@ key_list: } | key_list maybe_space ',' maybe_space key { $$ = $1; - ASSERT($5.unit != CSSParserValue::Function); // No need to call destroy. if ($$) $$->addValue($5); } ; key: - maybe_unary_operator PERCENTAGE { $$.id = CSSValueInvalid; $$.isInt = false; $$.fValue = $1 * $2; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } + maybe_unary_operator PERCENTAGE { + $$.id = CSSValueInvalid; + $$.isInt = false; + $$.fValue = $1 * $2; + $$.unit = CSSPrimitiveValue::CSS_NUMBER; + } | IDENT { $$.id = CSSValueInvalid; $$.isInt = false; @@ -1838,10 +1842,10 @@ invalid_var_fallback: '!' | ';'; calc_func_term: - unary_term - | variable_function { $$ = $1; } - | unary_operator unary_term { $$ = $2; $$.fValue *= $1; } - ; + unary_term + | unary_operator unary_term { $$ = $2; $$.fValue *= $1; } + | variable_function + ; /* * The grammar requires spaces around binary ‘+’ and ‘-’ operators. diff --git a/Source/WebCore/css/CSSParser.cpp b/Source/WebCore/css/CSSParser.cpp index 9aec1c8ac..3ac15d00c 100644 --- a/Source/WebCore/css/CSSParser.cpp +++ b/Source/WebCore/css/CSSParser.cpp @@ -2886,6 +2886,16 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyColumnWidth: // auto | <length> parsedValue = parseColumnWidth(); break; + case CSSPropertyObjectPosition: { + RefPtr<CSSPrimitiveValue> val1; + RefPtr<CSSPrimitiveValue> val2; + parseFillPosition(*m_valueList, val1, val2); + if (val1) { + addProperty(CSSPropertyObjectPosition, createPrimitiveValuePair(val1.release(), val2.release()), important); + return true; + } + return false; + } // End of CSS3 properties case CSSPropertyWillChange: // auto | [scroll-position | contents | <custom-ident>]# diff --git a/Source/WebCore/css/CSSParserValues.cpp b/Source/WebCore/css/CSSParserValues.cpp index db7540e8a..7fb74c6b8 100644 --- a/Source/WebCore/css/CSSParserValues.cpp +++ b/Source/WebCore/css/CSSParserValues.cpp @@ -46,29 +46,26 @@ void destroy(const CSSParserValue& value) CSSParserValueList::~CSSParserValueList() { - for (size_t i = 0, size = m_values.size(); i < size; i++) - destroy(m_values[i]); + for (auto& value : m_values) + destroy(value); } -void CSSParserValueList::addValue(const CSSParserValue& v) +void CSSParserValueList::addValue(const CSSParserValue& value) { - m_values.append(v); + m_values.append(value); } -void CSSParserValueList::insertValueAt(unsigned i, const CSSParserValue& v) +void CSSParserValueList::insertValueAt(unsigned i, const CSSParserValue& value) { - m_values.insert(i, v); + m_values.insert(i, value); } -void CSSParserValueList::deleteValueAt(unsigned i) +void CSSParserValueList::extend(CSSParserValueList& other) { - m_values.remove(i); -} - -void CSSParserValueList::extend(CSSParserValueList& valueList) -{ - for (unsigned int i = 0; i < valueList.size(); ++i) - m_values.append(*(valueList.valueAt(i))); + for (auto& value : other.m_values) { + m_values.append(value); + value.unit = 0; // We moved the CSSParserValue from the other list; this acts like std::move. + } } bool CSSParserValueList::containsVariables() const diff --git a/Source/WebCore/css/CSSParserValues.h b/Source/WebCore/css/CSSParserValues.h index 77a5b1957..ebc16fe0f 100644 --- a/Source/WebCore/css/CSSParserValues.h +++ b/Source/WebCore/css/CSSParserValues.h @@ -18,8 +18,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef CSSParserValues_h -#define CSSParserValues_h +#pragma once #include "CSSSelector.h" #include "CSSValueKeywords.h" @@ -140,7 +139,6 @@ public: void addValue(const CSSParserValue&); void insertValueAt(unsigned, const CSSParserValue&); - void deleteValueAt(unsigned); void extend(CSSParserValueList&); unsigned size() const { return m_values.size(); } @@ -274,5 +272,3 @@ template<unsigned length> inline bool equalLettersIgnoringASCIICase(const CSSPar } } - -#endif diff --git a/Source/WebCore/css/CSSPrimitiveValue.h b/Source/WebCore/css/CSSPrimitiveValue.h index ab5cd6094..23375815c 100644 --- a/Source/WebCore/css/CSSPrimitiveValue.h +++ b/Source/WebCore/css/CSSPrimitiveValue.h @@ -210,6 +210,7 @@ public: #if ENABLE(CSS_SCROLL_SNAP) bool isLengthRepeat() const { return m_primitiveUnitType == CSS_LENGTH_REPEAT; } #endif + bool isPair() const { return m_primitiveUnitType == CSS_PAIR; } bool isPropertyID() const { return m_primitiveUnitType == CSS_PROPERTY_ID; } bool isRGBColor() const { return m_primitiveUnitType == CSS_RGBCOLOR; } bool isShape() const { return m_primitiveUnitType == CSS_SHAPE; } diff --git a/Source/WebCore/css/CSSPropertyNames.in b/Source/WebCore/css/CSSPropertyNames.in index 0fd1d491a..2621e483e 100644 --- a/Source/WebCore/css/CSSPropertyNames.in +++ b/Source/WebCore/css/CSSPropertyNames.in @@ -145,7 +145,7 @@ background [Longhands=background-image|background-position-x|background-position background-attachment [FillLayerProperty, NameForMethods=Attachment] background-blend-mode [FillLayerProperty, NameForMethods=BlendMode] background-clip [FillLayerProperty, NameForMethods=Clip] -background-color [VisitedLinkColorSupport, Initial=invalidColor, NoDefaultColor] +background-color [VisitedLinkColorSupport, NoDefaultColor] background-image [FillLayerProperty, NameForMethods=Image] background-origin [FillLayerProperty, NameForMethods=Origin] background-position [Longhands=background-position-x|background-position-y] @@ -274,6 +274,7 @@ max-width [Initial=initialMaxSize, Converter=LengthMaxSizing] min-height [Initial=initialMinSize, Converter=LengthSizing] min-width [Initial=initialMinSize, Converter=LengthSizing] object-fit +object-position [Converter=ObjectPosition] opacity // Honor -webkit-opacity as a synonym for opacity. This was the only syntax that worked in Safari 1.1, // and may be in use on some websites and widgets. diff --git a/Source/WebCore/css/DocumentRuleSets.cpp b/Source/WebCore/css/DocumentRuleSets.cpp index 9cc08deb7..93f28b94d 100644 --- a/Source/WebCore/css/DocumentRuleSets.cpp +++ b/Source/WebCore/css/DocumentRuleSets.cpp @@ -114,6 +114,9 @@ void DocumentRuleSets::collectFeatures() const m_siblingRuleSet = makeRuleSet(m_features.siblingRules); m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules); + + m_ancestorClassRuleSets.clear(); + m_ancestorAttributeRuleSetsForHTML.clear(); } RuleSet* DocumentRuleSets::ancestorClassRules(AtomicStringImpl* className) const diff --git a/Source/WebCore/css/SelectorChecker.cpp b/Source/WebCore/css/SelectorChecker.cpp index 0f0d365c0..9b0fe19d8 100644 --- a/Source/WebCore/css/SelectorChecker.cpp +++ b/Source/WebCore/css/SelectorChecker.cpp @@ -912,6 +912,10 @@ bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont if (m_strictParsing || element.isLink() || canMatchHoverOrActiveInQuirksMode(context)) { addStyleRelation(checkingContext, element, StyleRelation::AffectedByHover); + // See the comment in generateElementIsHovered() in SelectorCompiler. + if (checkingContext.resolvingMode == SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements && !context.isMatchElement) + return true; + if (element.hovered() || InspectorInstrumentation::forcePseudoState(const_cast<Element&>(element), CSSSelector::PseudoClassHover)) return true; } diff --git a/Source/WebCore/css/StyleBuilderConverter.h b/Source/WebCore/css/StyleBuilderConverter.h index 34f6fe317..6ae433bd8 100644 --- a/Source/WebCore/css/StyleBuilderConverter.h +++ b/Source/WebCore/css/StyleBuilderConverter.h @@ -57,7 +57,7 @@ namespace WebCore { // Note that we assume the CSS parser only allows valid CSSValue types. class StyleBuilderConverter { public: - static Length convertLength(StyleResolver&, CSSValue&); + static Length convertLength(StyleResolver&, const CSSValue&); static Length convertLengthOrAuto(StyleResolver&, CSSValue&); static Length convertLengthSizing(StyleResolver&, CSSValue&); static Length convertLengthMaxSizing(StyleResolver&, CSSValue&); @@ -65,6 +65,7 @@ public: template <typename T> static T convertLineWidth(StyleResolver&, CSSValue&); static float convertSpacing(StyleResolver&, CSSValue&); static LengthSize convertRadius(StyleResolver&, CSSValue&); + static LengthPoint convertObjectPosition(StyleResolver&, CSSValue&); static TextDecoration convertTextDecoration(StyleResolver&, CSSValue&); template <typename T> static T convertNumber(StyleResolver&, CSSValue&); template <typename T> static T convertNumberOrAuto(StyleResolver&, CSSValue&); @@ -148,6 +149,10 @@ private: #if ENABLE(CSS_SCROLL_SNAP) static Length parseSnapCoordinate(StyleResolver&, const CSSValue&); #endif + + static Length convertTo100PercentMinusLength(const Length&); + static Length convertPositionComponent(StyleResolver&, const CSSPrimitiveValue&); + #if ENABLE(CSS_GRID_LAYOUT) static GridLength createGridTrackBreadth(CSSPrimitiveValue&, StyleResolver&); static GridTrackSize createGridTrackSize(CSSValue&, StyleResolver&); @@ -158,7 +163,7 @@ private: static CSSToLengthConversionData csstoLengthConversionDataWithTextZoomFactor(StyleResolver&); }; -inline Length StyleBuilderConverter::convertLength(StyleResolver& styleResolver, CSSValue& value) +inline Length StyleBuilderConverter::convertLength(StyleResolver& styleResolver, const CSSValue& value) { auto& primitiveValue = downcast<CSSPrimitiveValue>(value); CSSToLengthConversionData conversionData = styleResolver.useSVGZoomRulesForLength() ? @@ -298,6 +303,54 @@ inline LengthSize StyleBuilderConverter::convertRadius(StyleResolver& styleResol return LengthSize(radiusWidth, radiusHeight); } +inline Length StyleBuilderConverter::convertTo100PercentMinusLength(const Length& length) +{ + if (length.isPercent()) + return Length(100 - length.value(), Percent); + + // Turn this into a calc expression: calc(100% - length) + auto lhs = std::make_unique<CalcExpressionLength>(Length(100, Percent)); + auto rhs = std::make_unique<CalcExpressionLength>(length); + auto op = std::make_unique<CalcExpressionBinaryOperation>(WTFMove(lhs), WTFMove(rhs), CalcSubtract); + return Length(CalculationValue::create(WTFMove(op), CalculationRangeAll)); +} + +inline Length StyleBuilderConverter::convertPositionComponent(StyleResolver& styleResolver, const CSSPrimitiveValue& value) +{ + Length length; + + auto* lengthValue = &value; + bool relativeToTrailingEdge = false; + + if (value.isPair()) { + auto& first = *value.getPairValue()->first(); + if (first.getValueID() == CSSValueRight || first.getValueID() == CSSValueBottom) + relativeToTrailingEdge = true; + + lengthValue = value.getPairValue()->second(); + } + + length = convertLength(styleResolver, *lengthValue); + + if (relativeToTrailingEdge) + length = convertTo100PercentMinusLength(length); + + return length; +} + +inline LengthPoint StyleBuilderConverter::convertObjectPosition(StyleResolver& styleResolver, CSSValue& value) +{ + auto& primitiveValue = downcast<CSSPrimitiveValue>(value); + Pair* pair = primitiveValue.getPairValue(); + if (!pair || !pair->first() || !pair->second()) + return RenderStyle::initialObjectPosition(); + + Length lengthX = convertPositionComponent(styleResolver, *pair->first()); + Length lengthY = convertPositionComponent(styleResolver, *pair->second()); + + return LengthPoint(lengthX, lengthY); +} + inline TextDecoration StyleBuilderConverter::convertTextDecoration(StyleResolver&, CSSValue& value) { TextDecoration result = RenderStyle::initialTextDecoration(); @@ -735,7 +788,6 @@ inline std::unique_ptr<ScrollSnapPoints> StyleBuilderConverter::convertScrollSna return points; } - points->hasRepeat = false; for (auto& currentValue : downcast<CSSValueList>(value)) { auto& itemValue = downcast<CSSPrimitiveValue>(currentValue.get()); if (auto* lengthRepeat = itemValue.getLengthRepeatValue()) { diff --git a/Source/WebCore/cssjit/SelectorCompiler.cpp b/Source/WebCore/cssjit/SelectorCompiler.cpp index 7139f52d7..7597a9c90 100644 --- a/Source/WebCore/cssjit/SelectorCompiler.cpp +++ b/Source/WebCore/cssjit/SelectorCompiler.cpp @@ -3164,10 +3164,22 @@ void SelectorCodeGenerator::generateElementIsHovered(Assembler::JumpList& failur generateAddStyleRelationIfResolvingStyle(elementAddressRegister, SelectorChecker::StyleRelation::AffectedByHover); + Assembler::JumpList successCases; + if (m_selectorContext != SelectorContext::QuerySelector && fragment.relationToRightFragment != FragmentRelation::Rightmost) { + // :hover always matches when not in rightmost position when collecting rules for descendant style invalidation optimization. + // Resolving style for a matching descendant will set parent childrenAffectedByHover bit even when the element is not currently hovered. + // This bit has to be set for the event based :hover invalidation to work. + // FIXME: We should just collect style relation bits and apply them as needed when computing style invalidation optimization. + LocalRegister checkingContext(m_registerAllocator); + successCases.append(branchOnResolvingMode(Assembler::Equal, SelectorChecker::Mode::CollectingRulesIgnoringVirtualPseudoElements, checkingContext)); + } + FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls); functionCall.setFunctionAddress(elementIsHovered); functionCall.setOneArgument(elementAddressRegister); failureCases.append(functionCall.callAndBranchOnBooleanReturnValue(Assembler::Zero)); + + successCases.link(&m_assembler); } void SelectorCodeGenerator::generateElementIsInLanguage(Assembler::JumpList& failureCases, const SelectorFragment& fragment) diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index 5fe400c82..c7d87bb6c 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -343,19 +343,6 @@ static inline bool isValidNamePart(UChar32 c) return true; } -static bool shouldInheritSecurityOriginFromOwner(const URL& url) -{ - // http://www.whatwg.org/specs/web-apps/current-work/#origin-0 - // - // If a Document has the address "about:blank" - // The origin of the Document is the origin it was assigned when its browsing context was created. - // - // Note: We generalize this to all "blank" URLs and invalid URLs because we - // treat all of these URLs as about:blank. - // - return url.isEmpty() || url.isBlankURL(); -} - static Widget* widgetForElement(Element* focusedElement) { if (!focusedElement) @@ -546,8 +533,6 @@ Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsig , m_cookieCacheExpiryTimer(*this, &Document::invalidateDOMCookieCache) , m_disabledFieldsetElementsCount(0) , m_hasInjectedPlugInsScript(false) - , m_renderTreeBeingDestroyed(false) - , m_hasPreparedForDestruction(false) , m_hasStyleWithViewportUnits(false) { allDocuments().add(this); @@ -680,6 +665,7 @@ void Document::removedLastRef() // until after removeDetachedChildren returns, so we protect ourselves. incrementReferencingNodeCount(); + prepareForDestruction(); // We must make sure not to be retaining any of our children through // these extra pointers or we will create a reference cycle. m_focusedElement = nullptr; @@ -2575,12 +2561,11 @@ void Document::cancelParsing() void Document::implicitOpen() { - cancelParsing(); - removeChildren(); setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode); + cancelParsing(); m_parser = createParser(); setParsing(true); setReadyState(Loading); @@ -5080,6 +5065,20 @@ RefPtr<XPathResult> Document::evaluate(const String& expression, Node* contextNo return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec); } +static bool shouldInheritSecurityOriginFromOwner(const URL& url) +{ + // Paraphrased from <https://html.spec.whatwg.org/multipage/browsers.html#origin> (8 July 2016) + // + // If a Document has the address "about:blank" + // The origin of the document is the origin it was assigned when its browsing context was created. + // If a Document has the address "about:srcdoc" + // The origin of the document is the origin of its parent document. + // + // Note: We generalize this to invalid URLs because we treat such URLs as about:blank. + // + return url.isEmpty() || equalIgnoringASCIICase(url.string(), blankURL()) || equalLettersIgnoringASCIICase(url.string(), "about:srcdoc"); +} + void Document::initSecurityContext() { if (haveInitializedSecurityOrigin()) { diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index 1472b0bdc..cd35b20e6 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -1759,8 +1759,8 @@ private: unsigned m_disabledFieldsetElementsCount; bool m_hasInjectedPlugInsScript; - bool m_renderTreeBeingDestroyed; - bool m_hasPreparedForDestruction; + bool m_renderTreeBeingDestroyed { false }; + bool m_hasPreparedForDestruction { false }; bool m_hasStyleWithViewportUnits; bool m_isTimerThrottlingEnabled { false }; diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp index 84ccf5666..cd85ae496 100644 --- a/Source/WebCore/dom/Element.cpp +++ b/Source/WebCore/dom/Element.cpp @@ -2489,7 +2489,7 @@ bool Element::needsStyleInvalidation() const return false; if (styleChangeType() >= FullStyleChange) return false; - if (!document().styleResolverIfExists()) + if (document().hasPendingForcedStyleRecalc()) return false; return true; diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp index ba9886615..34495b5c7 100644 --- a/Source/WebCore/dom/Node.cpp +++ b/Source/WebCore/dom/Node.cpp @@ -938,65 +938,6 @@ bool Node::containsIncludingHostElements(const Node* node) const #endif } -static inline Node* ancestor(Node* node, unsigned depth) -{ - for (unsigned i = 0; i < depth; ++i) - node = node->parentNode(); - return node; -} - -Node* commonAncestor(Node& thisNode, Node& otherNode) -{ - unsigned thisDepth = 0; - for (auto node = &thisNode; node; node = node->parentNode()) { - if (node == &otherNode) - return node; - thisDepth++; - } - unsigned otherDepth = 0; - for (auto node = &otherNode; node; node = node->parentNode()) { - if (node == &thisNode) - return &thisNode; - otherDepth++; - } - - Node* thisAncestor = &thisNode; - Node* otherAncestor = &otherNode; - if (thisDepth > otherDepth) - thisAncestor = ancestor(thisAncestor, thisDepth - otherDepth); - else if (otherDepth > thisDepth) - otherAncestor = ancestor(otherAncestor, otherDepth - thisDepth); - - for (; thisAncestor; thisAncestor = thisAncestor->parentNode()) { - if (thisAncestor == otherAncestor) - return thisAncestor; - otherAncestor = otherAncestor->parentNode(); - } - ASSERT(!otherAncestor); - return nullptr; -} - -Node* commonAncestorCrossingShadowBoundary(Node& node, Node& other) -{ - if (&node == &other) - return &node; - - Element* shadowHost = node.shadowHost(); - // FIXME: This test might be wrong for user-authored shadow trees. - if (shadowHost && shadowHost == other.shadowHost()) - return shadowHost; - - TreeScope* scope = commonTreeScope(&node, &other); - if (!scope) - return nullptr; - - Node* parentNode = scope->ancestorInThisScope(&node); - ASSERT(parentNode); - Node* parentOther = scope->ancestorInThisScope(&other); - ASSERT(parentOther); - return commonAncestor(*parentNode, *parentOther); -} - Node* Node::pseudoAwarePreviousSibling() const { Element* parentOrHost = is<PseudoElement>(*this) ? downcast<PseudoElement>(*this).hostElement() : parentElement(); diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h index ec24e2163..842bd8775 100644 --- a/Source/WebCore/dom/Node.h +++ b/Source/WebCore/dom/Node.h @@ -791,9 +791,6 @@ inline ContainerNode* Node::parentNodeGuaranteedHostFree() const return parentNode(); } -Node* commonAncestor(Node&, Node&); -Node* commonAncestorCrossingShadowBoundary(Node&, Node&); - } // namespace WebCore #if ENABLE(TREE_DEBUGGING) diff --git a/Source/WebCore/editing/SpellChecker.cpp b/Source/WebCore/editing/SpellChecker.cpp index 577ec957f..d9ee2f149 100644 --- a/Source/WebCore/editing/SpellChecker.cpp +++ b/Source/WebCore/editing/SpellChecker.cpp @@ -77,6 +77,8 @@ void SpellCheckRequest::didSucceed(const Vector<TextCheckingResult>& results) { if (!m_checker) return; + + Ref<SpellCheckRequest> protectedThis(*this); m_checker->didCheckSucceed(m_requestData.sequence(), results); m_checker = nullptr; } @@ -85,6 +87,8 @@ void SpellCheckRequest::didCancel() { if (!m_checker) return; + + Ref<SpellCheckRequest> protectedThis(*this); m_checker->didCheckCancel(m_requestData.sequence()); m_checker = nullptr; } diff --git a/Source/WebCore/editing/atk/FrameSelectionAtk.cpp b/Source/WebCore/editing/atk/FrameSelectionAtk.cpp index 45f0e3b7f..ef77128ba 100644 --- a/Source/WebCore/editing/atk/FrameSelectionAtk.cpp +++ b/Source/WebCore/editing/atk/FrameSelectionAtk.cpp @@ -94,12 +94,15 @@ void FrameSelection::notifyAccessibilityForSelectionChange(const AXTextStateChan if (!m_selection.start().isNotNull() || !m_selection.end().isNotNull()) return; - RenderObject* focusedNode = m_selection.end().containerNode()->renderer(); + Node* focusedNode = m_selection.end().containerNode(); + if (!focusedNode) + return; + AXObjectCache* cache = m_frame->document()->existingAXObjectCache(); if (!cache) return; - AccessibilityObject* accessibilityObject = cache->getOrCreate(focusedNode); + AccessibilityObject* accessibilityObject = cache->getOrCreate(focusedNode->renderer()); if (!accessibilityObject) return; diff --git a/Source/WebCore/html/HTMLMarqueeElement.cpp b/Source/WebCore/html/HTMLMarqueeElement.cpp index 6bd6545af..4791ae9ae 100644 --- a/Source/WebCore/html/HTMLMarqueeElement.cpp +++ b/Source/WebCore/html/HTMLMarqueeElement.cpp @@ -55,7 +55,7 @@ int HTMLMarqueeElement::minimumDelay() const // WinIE uses 60ms as the minimum delay by default. return 60; } - return 0; + return 16; // Don't allow timers at < 16ms intervals to avoid CPU hogging: webkit.org/b/160609 } bool HTMLMarqueeElement::isPresentationAttribute(const QualifiedName& name) const diff --git a/Source/WebCore/html/HTMLMarqueeElement.h b/Source/WebCore/html/HTMLMarqueeElement.h index 394a163b5..a20926ecd 100644 --- a/Source/WebCore/html/HTMLMarqueeElement.h +++ b/Source/WebCore/html/HTMLMarqueeElement.h @@ -41,12 +41,15 @@ public: void start(); virtual void stop() override; + // Number of pixels to move on each scroll movement. Defaults to 6. int scrollAmount() const; void setScrollAmount(int, ExceptionCode&); + // Interval between each scroll movement, in milliseconds. Defaults to 60. int scrollDelay() const; void setScrollDelay(int, ExceptionCode&); + // Loop count. -1 means loop indefinitely. int loop() const; void setLoop(int, ExceptionCode&); diff --git a/Source/WebCore/html/ImageData.cpp b/Source/WebCore/html/ImageData.cpp index 27b57c372..907eb702c 100644 --- a/Source/WebCore/html/ImageData.cpp +++ b/Source/WebCore/html/ImageData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008-2016 Apple Inc. All rights reserved. * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -115,6 +115,7 @@ ImageData::ImageData(const IntSize& size) : m_size(size) , m_data(Uint8ClampedArray::createUninitialized(size.width() * size.height() * 4)) { + ASSERT_WITH_SECURITY_IMPLICATION(m_data); } ImageData::ImageData(const IntSize& size, PassRefPtr<Uint8ClampedArray> byteArray) diff --git a/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp index 829e7b356..b87f68ee4 100644 --- a/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp +++ b/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp @@ -350,12 +350,25 @@ inline void CanvasRenderingContext2D::FontProxy::drawBidiText(GraphicsContext& c context.drawBidiText(m_font, run, point, action); } +void CanvasRenderingContext2D::realizeSaves() +{ + if (m_unrealizedSaveCount) + realizeSavesLoop(); + + if (m_unrealizedSaveCount) { + static NeverDestroyed<String> consoleMessage(ASCIILiteral("CanvasRenderingContext2D.save() has been called without a matching restore() too many times. Ignoring save().")); + canvas()->document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, consoleMessage); + } +} + void CanvasRenderingContext2D::realizeSavesLoop() { ASSERT(m_unrealizedSaveCount); ASSERT(m_stateStack.size() >= 1); GraphicsContext* context = drawingContext(); do { + if (m_stateStack.size() > MaxSaveCount) + break; m_stateStack.append(state()); if (context) context->save(); @@ -1458,7 +1471,7 @@ void CanvasRenderingContext2D::drawImage(HTMLImageElement* imageElement, const F if (image->isSVGImage()) { image->setImageObserver(nullptr); - image->setContainerSize(normalizedSrcRect.size()); + image->setContainerSize(imageRect.size()); } if (rectContainsCanvas(normalizedDstRect)) { @@ -2090,8 +2103,17 @@ RefPtr<ImageData> CanvasRenderingContext2D::getImageData(ImageBuffer::Coordinate return createEmptyImageData(imageDataRect.size()); RefPtr<Uint8ClampedArray> byteArray = buffer->getUnmultipliedImageData(imageDataRect, coordinateSystem); - if (!byteArray) + if (!byteArray) { + StringBuilder consoleMessage; + consoleMessage.appendLiteral("Unable to get image data from canvas. Requested size was "); + consoleMessage.appendNumber(imageDataRect.width()); + consoleMessage.appendLiteral(" x "); + consoleMessage.appendNumber(imageDataRect.height()); + + canvas()->document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, consoleMessage.toString()); + ec = INVALID_STATE_ERR; return nullptr; + } return ImageData::create(imageDataRect.size(), byteArray.release()); } diff --git a/Source/WebCore/html/canvas/CanvasRenderingContext2D.h b/Source/WebCore/html/canvas/CanvasRenderingContext2D.h index a334873dc..783e95d31 100644 --- a/Source/WebCore/html/canvas/CanvasRenderingContext2D.h +++ b/Source/WebCore/html/canvas/CanvasRenderingContext2D.h @@ -318,7 +318,7 @@ private: CanvasDidDrawApplyAll = 0xffffffff }; - State& modifiableState() { ASSERT(!m_unrealizedSaveCount); return m_stateStack.last(); } + State& modifiableState() { ASSERT(!m_unrealizedSaveCount || m_stateStack.size() >= MaxSaveCount); return m_stateStack.last(); } const State& state() const { return m_stateStack.last(); } void applyLineDash() const; @@ -334,11 +334,7 @@ private: GraphicsContext* drawingContext() const; void unwindStateStack(); - void realizeSaves() - { - if (m_unrealizedSaveCount) - realizeSavesLoop(); - } + void realizeSaves(); void realizeSavesLoop(); void applyStrokePattern(); @@ -394,6 +390,7 @@ private: virtual PlatformLayer* platformLayer() const override; #endif + static const unsigned MaxSaveCount = 1024 * 16; Vector<State, 1> m_stateStack; unsigned m_unrealizedSaveCount { 0 }; bool m_usesCSSCompatibilityParseMode; diff --git a/Source/WebCore/inspector/InspectorIndexedDBAgent.cpp b/Source/WebCore/inspector/InspectorIndexedDBAgent.cpp index d6deef34f..37827fcda 100644 --- a/Source/WebCore/inspector/InspectorIndexedDBAgent.cpp +++ b/Source/WebCore/inspector/InspectorIndexedDBAgent.cpp @@ -494,7 +494,7 @@ static IDBFactory* assertIDBFactory(ErrorString& errorString, Document* document return nullptr; } - IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(domWindow); + IDBFactory* idbFactory = DOMWindowIndexedDatabase::indexedDB(*domWindow); if (!idbFactory) errorString = ASCIILiteral("No IndexedDB factory for given frame found"); diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp index d91420c58..9bc231ca2 100644 --- a/Source/WebCore/page/DOMWindow.cpp +++ b/Source/WebCore/page/DOMWindow.cpp @@ -477,6 +477,8 @@ Page* DOMWindow::page() void DOMWindow::frameDestroyed() { + Ref<DOMWindow> protectedThis(*this); + willDestroyDocumentInFrame(); FrameDestructionObserver::frameDestroyed(); resetDOMWindowProperties(); diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp index f13749ba0..e8aa9dfb3 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp @@ -1128,14 +1128,14 @@ HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTe } } + // We should always start hit testing a clean tree. + if (m_frame.document()) + m_frame.document()->updateLayoutIgnorePendingStylesheets(); HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width()); - RenderView* renderView = m_frame.contentRenderer(); if (!renderView) return result; - - // We should always start hittesting a clean tree. - renderView->document().updateLayoutIgnorePendingStylesheets(); + // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content. HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent); renderView->hitTest(request, result); @@ -1948,6 +1948,24 @@ void EventHandler::invalidateClick() m_clickNode = nullptr; } +static Node* targetNodeForClickEvent(Node* mousePressNode, Node* mouseReleaseNode) +{ + if (!mousePressNode || !mouseReleaseNode) + return nullptr; + + if (mousePressNode == mouseReleaseNode) + return mouseReleaseNode; + + Element* mouseReleaseShadowHost = mouseReleaseNode->shadowHost(); + if (mouseReleaseShadowHost && mouseReleaseShadowHost == mousePressNode->shadowHost()) { + // We want to dispatch the click to the shadow tree host element to give listeners the illusion that the + // shadom tree is a single element. For example, we want to give the illusion that <input type="range"> + // is a single element even though it is a composition of multiple shadom tree elements. + return mouseReleaseShadowHost; + } + return nullptr; +} + bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& platformMouseEvent) { RefPtr<FrameView> protector(m_frame.view()); @@ -2009,8 +2027,7 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& platformMou bool contextMenuEvent = platformMouseEvent.button() == RightButton; - Node* targetNode = mouseEvent.targetNode(); - Node* nodeToClick = (m_clickNode && targetNode) ? commonAncestorCrossingShadowBoundary(*m_clickNode, *targetNode) : nullptr; + Node* nodeToClick = targetNodeForClickEvent(m_clickNode.get(), mouseEvent.targetNode()); bool swallowClickEvent = m_clickCount > 0 && !contextMenuEvent && nodeToClick && !dispatchMouseEvent(eventNames().clickEvent, nodeToClick, true, m_clickCount, platformMouseEvent, true); if (m_resizeLayer) { diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp index c3b46c920..b1b84a462 100644 --- a/Source/WebCore/page/Frame.cpp +++ b/Source/WebCore/page/Frame.cpp @@ -217,8 +217,8 @@ Frame::~Frame() disconnectOwnerElement(); - for (auto& observer : m_destructionObservers) - observer->frameDestroyed(); + while (auto* destructionObserver = m_destructionObservers.takeAny()) + destructionObserver->frameDestroyed(); if (!isMainFrame()) m_mainFrame.selfOnlyDeref(); diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp index e1dd28906..4bae77613 100644 --- a/Source/WebCore/page/FrameView.cpp +++ b/Source/WebCore/page/FrameView.cpp @@ -2649,7 +2649,9 @@ void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot) ASSERT(!renderView.documentBeingDestroyed()); ASSERT(frame().view() == this); - if (renderView.needsLayout()) { + // When m_layoutRoot is already set, ignore the renderView's needsLayout bit + // since we need to resolve the conflict between the m_layoutRoot and newRelayoutRoot layouts. + if (renderView.needsLayout() && !m_layoutRoot) { m_layoutRoot = &newRelayoutRoot; convertSubtreeLayoutToFullLayout(); return; @@ -2657,7 +2659,7 @@ void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot) if (!layoutPending() && m_layoutSchedulingEnabled) { std::chrono::milliseconds delay = renderView.document().minimumLayoutDelay(); - ASSERT(!newRelayoutRoot.container() || !newRelayoutRoot.container()->needsLayout()); + ASSERT(!newRelayoutRoot.container() || is<RenderView>(newRelayoutRoot.container()) || !newRelayoutRoot.container()->needsLayout()); m_layoutRoot = &newRelayoutRoot; InspectorInstrumentation::didInvalidateLayout(frame()); m_delayedLayout = delay.count(); @@ -2678,7 +2680,7 @@ void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot) if (isObjectAncestorContainerOf(m_layoutRoot, &newRelayoutRoot)) { // Keep the current root. newRelayoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No, m_layoutRoot); - ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout()); + ASSERT(!m_layoutRoot->container() || is<RenderView>(m_layoutRoot->container()) || !m_layoutRoot->container()->needsLayout()); return; } @@ -2686,7 +2688,7 @@ void FrameView::scheduleRelayoutOfSubtree(RenderElement& newRelayoutRoot) // Re-root at newRelayoutRoot. m_layoutRoot->markContainingBlocksForLayout(ScheduleRelayout::No, &newRelayoutRoot); m_layoutRoot = &newRelayoutRoot; - ASSERT(!m_layoutRoot->container() || !m_layoutRoot->container()->needsLayout()); + ASSERT(!m_layoutRoot->container() || is<RenderView>(m_layoutRoot->container()) || !m_layoutRoot->container()->needsLayout()); InspectorInstrumentation::didInvalidateLayout(frame()); return; } diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp index b9571c1d4..d4f184ced 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp @@ -154,6 +154,15 @@ void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const Str return; } + if (fullURL.hasUsername() || fullURL.hasPassword()) { + ec.code = SECURITY_ERR; + if (stateObjectType == StateObjectType::Replace) + ec.message = makeString("Attempt to use history.replaceState() to change session history URL to ", fullURL.string(), " is insecure; Username/passwords aren't allowed in state object URLs"); + else + ec.message = makeString("Attempt to use history.pushState() to add URL ", fullURL.string(), " to session history is insecure; Username/passwords aren't allowed in state object URLs"); + return; + } + Document* mainDocument = m_frame->page()->mainFrame().document(); History* mainHistory = nullptr; if (mainDocument) { diff --git a/Source/WebCore/page/Location.cpp b/Source/WebCore/page/Location.cpp index fea54e4af..7eb40017a 100644 --- a/Source/WebCore/page/Location.cpp +++ b/Source/WebCore/page/Location.cpp @@ -60,7 +60,15 @@ String Location::href() const if (!m_frame) return String(); - return url().string(); + auto& url = this->url(); + + if (!url.hasUsername() && !url.hasPassword()) + return url.string(); + + URL urlWithoutCredentials(url); + urlWithoutCredentials.setUser(WTF::emptyString()); + urlWithoutCredentials.setPass(WTF::emptyString()); + return urlWithoutCredentials.string(); } String Location::protocol() const diff --git a/Source/WebCore/page/SecurityOrigin.cpp b/Source/WebCore/page/SecurityOrigin.cpp index 976c33f3f..997a74882 100644 --- a/Source/WebCore/page/SecurityOrigin.cpp +++ b/Source/WebCore/page/SecurityOrigin.cpp @@ -375,11 +375,6 @@ bool SecurityOrigin::canAccessStorage(const SecurityOrigin* topOrigin, ShouldAll if (m_storageBlockingPolicy == BlockAllStorage) return false; - // We allow access to local storage from file URLs also when allowFileAccessFromFileURLs setting is enabled, - // for backwards compatibility only in WebKitGTK+ 2.12 branch, this should not be backported to any other branch, nor trunk. - if (isLocal() && !m_universalAccess && m_enforceFilePathSeparation && shouldAllowFromThirdParty != AlwaysAllowFromThirdParty) - return false; - // FIXME: This check should be replaced with an ASSERT once we can guarantee that topOrigin is not null. if (!topOrigin) return true; diff --git a/Source/WebCore/page/Settings.in b/Source/WebCore/page/Settings.in index b54f8d31d..24f7e40ec 100644 --- a/Source/WebCore/page/Settings.in +++ b/Source/WebCore/page/Settings.in @@ -79,6 +79,7 @@ needsSiteSpecificQuirks initial=false domTimersThrottlingEnabled initial=true webArchiveDebugModeEnabled initial=false, conditional=WEB_ARCHIVE localFileContentSniffingEnabled initial=false +offlineStorageDatabaseEnabled initial=false offlineWebApplicationCacheEnabled initial=false enforceCSSMIMETypeInNoQuirksMode initial=true usesEncodingDetector initial=false diff --git a/Source/WebCore/page/animation/AnimationController.cpp b/Source/WebCore/page/animation/AnimationController.cpp index 9bcb2fed1..e1d7f4a50 100644 --- a/Source/WebCore/page/animation/AnimationController.cpp +++ b/Source/WebCore/page/animation/AnimationController.cpp @@ -48,7 +48,7 @@ namespace WebCore { -static const double cAnimationTimerDelay = 0.025; +static const double cAnimationTimerDelay = 1.0 / 60; static const double cBeginAnimationUpdateTimeNotSet = -1; class AnimationPrivateUpdateBlock { diff --git a/Source/WebCore/platform/LengthPoint.cpp b/Source/WebCore/platform/LengthPoint.cpp new file mode 100644 index 000000000..6e6235cfc --- /dev/null +++ b/Source/WebCore/platform/LengthPoint.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LengthPoint.h" + +#include "TextStream.h" + +namespace WebCore { + +TextStream& operator<<(TextStream& ts, const LengthPoint& size) +{ + return ts << size.x() << " " << size.y(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/LengthPoint.h b/Source/WebCore/platform/LengthPoint.h new file mode 100644 index 000000000..21b1a3f47 --- /dev/null +++ b/Source/WebCore/platform/LengthPoint.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LengthPoint_h +#define LengthPoint_h + +#include "Length.h" + +namespace WebCore { + +struct LengthPoint { +public: + LengthPoint() + { + } + + LengthPoint(Length x, Length y) + : m_x(WTFMove(x)) + , m_y(WTFMove(y)) + { + } + + bool operator==(const LengthPoint& o) const + { + return m_x == o.m_x && m_y == o.m_y; + } + + bool operator!=(const LengthPoint& o) const + { + return !(*this == o); + } + + void setX(Length x) { m_x = WTFMove(x); } + const Length& x() const { return m_x; } + + void setY(Length y) { m_y = WTFMove(y); } + const Length& y() const { return m_y; } + + LengthPoint blend(const LengthPoint& from, double progress) const + { + return LengthPoint(m_x.blend(from.x(), progress), m_y.blend(from.y(), progress)); + } + +private: + // FIXME: it would be nice to pack the two Lengths together better somehow (to avoid padding between them). + Length m_x; + Length m_y; +}; + +TextStream& operator<<(TextStream&, const LengthPoint&); + +} // namespace WebCore + +#endif // LengthPoint_h diff --git a/Source/WebCore/platform/SharedBuffer.cpp b/Source/WebCore/platform/SharedBuffer.cpp index 00fcf6753..c7e05bf23 100644 --- a/Source/WebCore/platform/SharedBuffer.cpp +++ b/Source/WebCore/platform/SharedBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006-2016 Apple Inc. All rights reserved. * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. * Copyright (C) 2015 Canon Inc. All rights reserved. * @@ -144,6 +144,10 @@ const char* SharedBuffer::data() const PassRefPtr<ArrayBuffer> SharedBuffer::createArrayBuffer() const { RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::createUninitialized(static_cast<unsigned>(size()), sizeof(char)); + if (!arrayBuffer) { + WTFLogAlways("SharedBuffer::createArrayBuffer Unable to create buffer. Requested size was %d x %lu\n", size(), sizeof(char)); + return nullptr; + } const char* segment = 0; unsigned position = 0; diff --git a/Source/WebCore/platform/URL.cpp b/Source/WebCore/platform/URL.cpp index b2e1fde94..857bc7e6e 100644 --- a/Source/WebCore/platform/URL.cpp +++ b/Source/WebCore/platform/URL.cpp @@ -104,15 +104,19 @@ enum URLCharacterClasses { PathSegmentEndChar = 1 << 5, // not allowed in path - BadChar = 1 << 6 + BadChar = 1 << 6, + + // "\t" | "\n" | "\r" + TabNewline = 1 << 7 }; static const unsigned char characterClassTable[256] = { /* 0 nul */ PathSegmentEndChar, /* 1 soh */ BadChar, /* 2 stx */ BadChar, /* 3 etx */ BadChar, /* 4 eot */ BadChar, /* 5 enq */ BadChar, /* 6 ack */ BadChar, /* 7 bel */ BadChar, - /* 8 bs */ BadChar, /* 9 ht */ BadChar, /* 10 nl */ BadChar, /* 11 vt */ BadChar, - /* 12 np */ BadChar, /* 13 cr */ BadChar, /* 14 so */ BadChar, /* 15 si */ BadChar, + /* 8 bs */ BadChar, /* 9 ht */ BadChar | TabNewline, /* 10 nl */ BadChar | TabNewline, + /* 11 vt */ BadChar, /* 12 np */ BadChar, /* 13 cr */ BadChar | TabNewline, + /* 14 so */ BadChar, /* 15 si */ BadChar, /* 16 dle */ BadChar, /* 17 dc1 */ BadChar, /* 18 dc2 */ BadChar, /* 19 dc3 */ BadChar, /* 20 dc4 */ BadChar, /* 21 nak */ BadChar, /* 22 syn */ BadChar, /* 23 etb */ BadChar, /* 24 can */ BadChar, /* 25 em */ BadChar, /* 26 sub */ BadChar, /* 27 esc */ BadChar, @@ -350,6 +354,7 @@ static inline bool isIPv6Char(unsigned char c) { return characterClassTable[c] & static inline bool isPathSegmentEndChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & PathSegmentEndChar; } static inline bool isPathSegmentEndChar(UChar c) { return c <= 0xff && (characterClassTable[c] & PathSegmentEndChar); } static inline bool isBadChar(unsigned char c) { return characterClassTable[c] & BadChar; } +static inline bool isTabNewline(UChar c) { return c <= 0xff && (characterClassTable[c] & TabNewline); } static inline bool isSchemeCharacterMatchIgnoringCase(char character, char schemeCharacter) { @@ -455,7 +460,7 @@ URL::URL(const URL& base, const String& relative, const TextEncoding& encoding) init(base, relative, encoding.encodingForFormSubmission()); } -static bool shouldTrimFromURL(unsigned char c) +static bool shouldTrimFromURL(UChar c) { // Browsers ignore leading/trailing whitespace and control // characters from URLs. Note that c is an *unsigned* char here @@ -473,9 +478,14 @@ void URL::init(const URL& base, const String& relative, const TextEncoding& enco return; } + // Get rid of leading and trailing whitespace and control characters. + String rel = relative.stripWhiteSpace(shouldTrimFromURL); + + // Get rid of any tabs and newlines. + rel = rel.removeCharacters(isTabNewline); + // For compatibility with Win IE, treat backslashes as if they were slashes, // as long as we're not dealing with javascript: or data: URLs. - String rel = relative; if (rel.contains('\\') && !(protocolIsJavaScript(rel) || protocolIs(rel, "data"))) rel = substituteBackslashes(rel); @@ -500,16 +510,6 @@ void URL::init(const URL& base, const String& relative, const TextEncoding& enco len = strlen(str); } - // Get rid of leading whitespace and control characters. - while (len && shouldTrimFromURL(*str)) { - str++; - --len; - } - - // Get rid of trailing whitespace and control characters. - while (len && shouldTrimFromURL(str[len - 1])) - str[--len] = '\0'; - // According to the RFC, the reference should be interpreted as an // absolute URI if possible, using the "leftmost, longest" // algorithm. If the URI reference is absolute it will have a @@ -1934,12 +1934,26 @@ bool protocolIs(const String& url, const char* protocol) { // Do the comparison without making a new string object. assertProtocolIsGood(protocol); - for (int i = 0; ; ++i) { - if (!protocol[i]) + bool isLeading = true; + for (int i = 0, j = 0; url[i]; ++i) { + // skip leading whitespace and control characters. + if (isLeading && shouldTrimFromURL(url[i])) + continue; + isLeading = false; + + // skip any tabs and newlines. + if (isTabNewline(url[i])) + continue; + + if (!protocol[j]) return url[i] == ':'; - if (!isLetterMatchIgnoringCase(url[i], protocol[i])) + if (!isLetterMatchIgnoringCase(url[i], protocol[j])) return false; + + ++j; } + + return false; } bool isValidProtocol(const String& protocol) diff --git a/Source/WebCore/platform/URL.h b/Source/WebCore/platform/URL.h index 5fcee4880..f9bfce6dc 100644 --- a/Source/WebCore/platform/URL.h +++ b/Source/WebCore/platform/URL.h @@ -120,6 +120,9 @@ public: WEBCORE_EXPORT String fragmentIdentifier() const; WEBCORE_EXPORT bool hasFragmentIdentifier() const; + bool hasUsername() const; + bool hasPassword() const; + // Unlike user() and pass(), these functions don't decode escape sequences. // This is necessary for accurate round-tripping, because encoding doesn't encode '%' characters. String encodedUser() const; @@ -354,6 +357,16 @@ inline bool URL::hasPort() const return m_hostEnd < m_portEnd; } +inline bool URL::hasUsername() const +{ + return m_userEnd > m_userStart; +} + +inline bool URL::hasPassword() const +{ + return m_passwordEnd > (m_userEnd + 1); +} + inline bool URL::protocolIsInHTTPFamily() const { return m_protocolIsInHTTPFamily; diff --git a/Source/WebCore/platform/graphics/PlatformDisplay.cpp b/Source/WebCore/platform/graphics/PlatformDisplay.cpp index 19a6b99a8..bdae5f45f 100644 --- a/Source/WebCore/platform/graphics/PlatformDisplay.cpp +++ b/Source/WebCore/platform/graphics/PlatformDisplay.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "PlatformDisplay.h" +#include <cstdlib> #include <mutex> #include <wtf/NeverDestroyed.h> @@ -112,10 +113,8 @@ PlatformDisplay::PlatformDisplay() PlatformDisplay::~PlatformDisplay() { - // WinCairo crashes when terminating EGL on exit. - // https://bugs.webkit.org/show_bug.cgi?id=145832 -#if USE(EGL) && !PLATFORM(WIN) - terminateEGLDisplay(); +#if USE(EGL) + ASSERT(m_eglDisplay == EGL_NO_DISPLAY); #endif } @@ -159,10 +158,21 @@ void PlatformDisplay::initializeEGLDisplay() terminateEGLDisplay(); return; } + + // EGL registers atexit handlers to cleanup its global display list. + // Since the global PlatformDisplay instance is created before, + // when the PlatformDisplay destructor is called, EGL has already removed the + // display from the list, causing eglTerminate() to crash. So, here we register + // our own atexit handler, after EGL has been initialized and after the global + // instance has been created to ensure we call eglTerminate() before the other + // EGL atexit handlers and the PlatformDisplay destructor. + // See https://bugs.webkit.org/show_bug.cgi?id=157973. + std::atexit([] { PlatformDisplay::sharedDisplay().terminateEGLDisplay(); }); } void PlatformDisplay::terminateEGLDisplay() { + ASSERT(m_eglDisplayInitialized); if (m_eglDisplay == EGL_NO_DISPLAY) return; eglTerminate(m_eglDisplay); diff --git a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp index 051871ac6..61a58b904 100644 --- a/Source/WebCore/platform/graphics/WOFFFileFormat.cpp +++ b/Source/WebCore/platform/graphics/WOFFFileFormat.cpp @@ -30,6 +30,11 @@ #include "SharedBuffer.h" #include <wtf/ByteOrder.h> +#if USE(WOFF2) +#include "woff2_common.h" +#include "woff2_dec.h" +#endif + namespace WebCore { static bool readUInt32(SharedBuffer* buffer, size_t& offset, uint32_t& value) @@ -75,7 +80,14 @@ bool isWOFF(SharedBuffer* buffer) size_t offset = 0; uint32_t signature; - return readUInt32(buffer, offset, signature) && signature == woffSignature; + if (!readUInt32(buffer, offset, signature)) + return false; + +#if USE(WOFF2) + return signature == woffSignature || signature == woff2::kWoff2Signature; +#else + return signature == woffSignature; +#endif } bool convertWOFFToSfnt(SharedBuffer* woff, Vector<char>& sfnt) @@ -86,7 +98,26 @@ bool convertWOFFToSfnt(SharedBuffer* woff, Vector<char>& sfnt) // Read the WOFF header. uint32_t signature; - if (!readUInt32(woff, offset, signature) || signature != woffSignature) { + if (!readUInt32(woff, offset, signature)) { + ASSERT_NOT_REACHED(); + return false; + } + +#if USE(WOFF2) + if (signature == woff2::kWoff2Signature) { + const uint8_t* woffData = reinterpret_cast_ptr<const uint8_t*>(woff->data()); + const size_t woffSize = woff->size(); + const size_t sfntSize = woff2::ComputeWOFF2FinalSize(woffData, woffSize); + + if (!sfnt.tryReserveCapacity(sfntSize)) + return false; + sfnt.resize(sfntSize); + + return woff2::ConvertWOFF2ToTTF(reinterpret_cast<uint8_t*>(sfnt.data()), sfnt.size(), woffData, woffSize); + } +#endif + + if (signature != woffSignature) { ASSERT_NOT_REACHED(); return false; } diff --git a/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp index 1904ed91a..e50ec669d 100644 --- a/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp +++ b/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -5,7 +5,7 @@ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) 2010 Igalia, S.L. * Copyright (C) Research In Motion Limited 2010. All rights reserved. - * Copyright (C) 2015 Apple, Inc. All rights reserved. + * Copyright (C) 2015-2016 Apple, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -540,9 +540,12 @@ void FEGaussianBlur::platformApplySoftware() IntSize paintSize = absolutePaintRect().size(); paintSize.scale(filter().filterScale()); RefPtr<Uint8ClampedArray> tmpImageData = Uint8ClampedArray::createUninitialized(paintSize.width() * paintSize.height() * 4); - Uint8ClampedArray* tmpPixelArray = tmpImageData.get(); + if (!tmpImageData) { + WTFLogAlways("FEGaussianBlur::platformApplySoftware Unable to create buffer. Requested size was %d x %d\n", paintSize.width(), paintSize.height()); + return; + } - platformApply(srcPixelArray, tmpPixelArray, kernelSize.width(), kernelSize.height(), paintSize); + platformApply(srcPixelArray, tmpImageData.get(), kernelSize.width(), kernelSize.height(), paintSize); } void FEGaussianBlur::dump() diff --git a/Source/WebCore/platform/graphics/filters/FilterEffect.cpp b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp index 1dcb0cb06..515d1299b 100644 --- a/Source/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/Source/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -3,7 +3,7 @@ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * Copyright (C) 2012 University of Szeged - * Copyright (C) 2015 Apple Inc. All rights reserved. + * Copyright (C) 2015-2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -260,6 +260,9 @@ inline void FilterEffect::copyImageBytes(Uint8ClampedArray* source, Uint8Clamped IntSize scaledPaintSize(m_absolutePaintRect.size()); scaledPaintSize.scale(m_filter.filterScale()); + if (!source || !destination) + return; + // Initialize the destination to transparent black, if not entirely covered by the source. if (scaledRect.x() < 0 || scaledRect.y() < 0 || scaledRect.maxX() > scaledPaintSize.width() || scaledRect.maxY() > scaledPaintSize.height()) memset(destination->data(), 0, destination->length()); @@ -315,6 +318,10 @@ void FilterEffect::copyUnmultipliedImage(Uint8ClampedArray* destination, const I ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize)); inputSize.scale(m_filter.filterScale()); m_unmultipliedImageResult = Uint8ClampedArray::createUninitialized(inputSize.width() * inputSize.height() * 4); + if (!m_unmultipliedImageResult) { + WTFLogAlways("FilterEffect::copyUnmultipliedImage Unable to create buffer. Requested size was %d x %d\n", inputSize.width(), inputSize.height()); + return; + } unsigned char* sourceComponent = m_premultipliedImageResult->data(); unsigned char* destinationComponent = m_unmultipliedImageResult->data(); unsigned char* end = sourceComponent + (inputSize.width() * inputSize.height() * 4); @@ -351,6 +358,10 @@ void FilterEffect::copyPremultipliedImage(Uint8ClampedArray* destination, const ASSERT(!ImageBuffer::sizeNeedsClamping(inputSize)); inputSize.scale(m_filter.filterScale()); m_premultipliedImageResult = Uint8ClampedArray::createUninitialized(inputSize.width() * inputSize.height() * 4); + if (!m_premultipliedImageResult) { + WTFLogAlways("FilterEffect::copyPremultipliedImage Unable to create buffer. Requested size was %d x %d\n", inputSize.width(), inputSize.height()); + return; + } unsigned char* sourceComponent = m_unmultipliedImageResult->data(); unsigned char* destinationComponent = m_premultipliedImageResult->data(); unsigned char* end = sourceComponent + (inputSize.width() * inputSize.height() * 4); diff --git a/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp b/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp index a1a189a2b..27517db20 100644 --- a/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp +++ b/Source/WebCore/platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp @@ -91,6 +91,9 @@ bool FontCustomPlatformData::supportsFormat(const String& format) { return equalLettersIgnoringASCIICase(format, "truetype") || equalLettersIgnoringASCIICase(format, "opentype") +#if USE(WOFF2) + || equalLettersIgnoringASCIICase(format, "woff2") +#endif || equalLettersIgnoringASCIICase(format, "woff"); } diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp index 428038c08..310a02247 100644 --- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp @@ -537,11 +537,18 @@ void MediaPlayerPrivateGStreamerBase::repaint() void MediaPlayerPrivateGStreamerBase::triggerRepaint(GstSample* sample) { + bool triggerResize; { WTF::GMutexLocker<GMutex> lock(m_sampleMutex); + triggerResize = !m_sample; m_sample = sample; } + if (triggerResize) { + LOG_MEDIA_MESSAGE("First sample reached the sink, triggering video dimensions update"); + m_player->sizeChanged(); + } + #if USE(COORDINATED_GRAPHICS_THREADED) #if USE(GSTREAMER_GL) pushTextureToCompositor(); diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index d2ae28f2c..df7c46836 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -39,6 +39,8 @@ #include <gst/app/gstappsrc.h> #include <gst/gst.h> #include <gst/pbutils/missing-plugins.h> +#include <wtf/Condition.h> +#include <wtf/Lock.h> #include <wtf/MainThread.h> #include <wtf/Noncopyable.h> #include <wtf/glib/GMutexLocker.h> @@ -83,7 +85,7 @@ class CachedResourceStreamingClient final : public PlatformMediaResourceClient, class ResourceHandleStreamingClient : public ResourceHandleClient, public StreamingClient { WTF_MAKE_NONCOPYABLE(ResourceHandleStreamingClient); WTF_MAKE_FAST_ALLOCATED; public: - ResourceHandleStreamingClient(WebKitWebSrc*, const ResourceRequest&); + ResourceHandleStreamingClient(WebKitWebSrc*, ResourceRequest&&); virtual ~ResourceHandleStreamingClient(); // StreamingClient virtual methods. @@ -102,6 +104,12 @@ class ResourceHandleStreamingClient : public ResourceHandleClient, public Stream virtual void wasBlocked(ResourceHandle*); virtual void cannotShowURL(ResourceHandle*); + ThreadIdentifier m_thread { 0 }; + Lock m_initializeRunLoopConditionMutex; + Condition m_initializeRunLoopCondition; + RunLoop* m_runLoop { nullptr }; + Lock m_terminateRunLoopConditionMutex; + Condition m_terminateRunLoopCondition; RefPtr<ResourceHandle> m_resource; }; @@ -127,18 +135,19 @@ struct _WebKitWebSrcPrivate { RefPtr<PlatformMediaResourceLoader> loader; RefPtr<PlatformMediaResource> resource; - ResourceHandleStreamingClient* client; + std::unique_ptr<ResourceHandleStreamingClient> client; bool didPassAccessControlCheck; guint64 offset; guint64 size; gboolean seekable; - gboolean paused; + bool paused; bool isSeeking; guint64 requestedOffset; + bool createdInMainThread; MainThreadNotifier<MainThreadSourceNotification> notifier; GRefPtr<GstBuffer> buffer; }; @@ -172,57 +181,20 @@ static gboolean webKitWebSrcQueryWithParent(GstPad*, GstObject*, GstQuery*); static void webKitWebSrcNeedData(WebKitWebSrc*); static void webKitWebSrcEnoughData(WebKitWebSrc*); -static void webKitWebSrcSeek(WebKitWebSrc*); +static gboolean webKitWebSrcSeek(WebKitWebSrc*, guint64); static GstAppSrcCallbacks appsrcCallbacks = { // need_data [](GstAppSrc*, guint, gpointer userData) { - WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); - WebKitWebSrcPrivate* priv = src->priv; - - { - WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); - if (!priv->paused) - return; - } - - GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); - priv->notifier.notify(MainThreadSourceNotification::NeedData, [protector] { webKitWebSrcNeedData(protector.get()); }); + webKitWebSrcNeedData(WEBKIT_WEB_SRC(userData)); }, // enough_data [](GstAppSrc*, gpointer userData) { - WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); - WebKitWebSrcPrivate* priv = src->priv; - - { - WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); - if (priv->paused) - return; - } - - GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); - priv->notifier.notify(MainThreadSourceNotification::EnoughData, [protector] { webKitWebSrcEnoughData(protector.get()); }); + webKitWebSrcEnoughData(WEBKIT_WEB_SRC(userData)); }, // seek_data [](GstAppSrc*, guint64 offset, gpointer userData) -> gboolean { - WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); - WebKitWebSrcPrivate* priv = src->priv; - - { - WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); - if (offset == priv->offset && priv->requestedOffset == priv->offset) - return TRUE; - - if (!priv->seekable) - return FALSE; - - priv->isSeeking = true; - priv->requestedOffset = offset; - } - - GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); - priv->notifier.notify(MainThreadSourceNotification::Seek, [protector] { webKitWebSrcSeek(protector.get()); }); - return TRUE; + return webKitWebSrcSeek(WEBKIT_WEB_SRC(userData), offset); }, { nullptr } }; @@ -287,6 +259,8 @@ static void webkit_web_src_init(WebKitWebSrc* src) src->priv = priv; new (priv) WebKitWebSrcPrivate(); + priv->createdInMainThread = isMainThread(); + priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0)); if (!priv->appsrc) { GST_ERROR_OBJECT(src, "Failed to create appsrc"); @@ -412,28 +386,37 @@ static void webKitWebSrcStop(WebKitWebSrc* src) { WebKitWebSrcPrivate* priv = src->priv; - ASSERT(isMainThread()); + if (priv->resource || (priv->loader && !priv->keepAlive)) { + GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); + priv->notifier.cancelPendingNotifications(MainThreadSourceNotification::NeedData | MainThreadSourceNotification::EnoughData | MainThreadSourceNotification::Seek); + bool keepAlive = priv->keepAlive; + priv->notifier.notify(MainThreadSourceNotification::Stop, [protector, keepAlive] { + WebKitWebSrcPrivate* priv = protector->priv; + + WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(protector.get())); + if (priv->resource) { + priv->resource->stop(); + priv->resource->setClient(nullptr); + priv->resource = nullptr; + } + + if (!keepAlive) + priv->loader = nullptr; + }); + } WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); bool wasSeeking = std::exchange(priv->isSeeking, false); - priv->notifier.cancelPendingNotifications(MainThreadSourceNotification::NeedData | MainThreadSourceNotification::EnoughData | MainThreadSourceNotification::Seek); - - if (priv->client) { - delete priv->client; - priv->client = 0; - } - - if (!priv->keepAlive) - priv->loader = nullptr; + priv->client = nullptr; if (priv->buffer) { unmapGstBuffer(priv->buffer.get()); priv->buffer.clear(); } - priv->paused = FALSE; + priv->paused = false; priv->offset = 0; priv->seekable = FALSE; @@ -510,8 +493,6 @@ static void webKitWebSrcStart(WebKitWebSrc* src) { WebKitWebSrcPrivate* priv = src->priv; - ASSERT(isMainThread()); - WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); priv->didPassAccessControlCheck = false; @@ -576,37 +557,41 @@ static void webKitWebSrcStart(WebKitWebSrc* src) // We always request Icecast/Shoutcast metadata, just in case ... request.setHTTPHeaderField(HTTPHeaderName::IcyMetadata, "1"); - bool loadFailed = true; - if (priv->player && !priv->loader) - priv->loader = priv->player->createResourceLoader(); + if (!priv->player || !priv->createdInMainThread) { + priv->client = std::make_unique<ResourceHandleStreamingClient>(src, WTFMove(request)); + if (priv->client->loadFailed()) { + GST_ERROR_OBJECT(src, "Failed to setup streaming client"); + priv->client = nullptr; + locker.unlock(); + webKitWebSrcStop(src); + } else + GST_DEBUG_OBJECT(src, "Started request"); + return; + } + + locker.unlock(); + GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); + priv->notifier.notify(MainThreadSourceNotification::Start, [protector, request] { + WebKitWebSrcPrivate* priv = protector->priv; + + WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(protector.get())); + if (!priv->loader) + priv->loader = priv->player->createResourceLoader(); - if (priv->loader) { PlatformMediaResourceLoader::LoadOptions loadOptions = 0; if (request.url().protocolIsBlob()) loadOptions |= PlatformMediaResourceLoader::LoadOption::BufferData; priv->resource = priv->loader->requestResource(request, loadOptions); - loadFailed = !priv->resource; - - if (priv->resource) - priv->resource->setClient(std::make_unique<CachedResourceStreamingClient>(src)); - } else { - priv->client = new ResourceHandleStreamingClient(src, request); - loadFailed = priv->client->loadFailed(); - } - - if (loadFailed) { - GST_ERROR_OBJECT(src, "Failed to setup streaming client"); - if (priv->client) { - delete priv->client; - priv->client = nullptr; + if (priv->resource) { + priv->resource->setClient(std::make_unique<CachedResourceStreamingClient>(protector.get())); + GST_DEBUG_OBJECT(protector.get(), "Started request"); + } else { + GST_ERROR_OBJECT(protector.get(), "Failed to setup streaming client"); + priv->loader = nullptr; + locker.unlock(); + webKitWebSrcStop(protector.get()); } - priv->loader = nullptr; - priv->resource = nullptr; - locker.unlock(); - webKitWebSrcStop(src); - return; - } - GST_DEBUG_OBJECT(src, "Started request"); + }); } static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition) @@ -638,16 +623,13 @@ static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStat case GST_STATE_CHANGE_READY_TO_PAUSED: { GST_DEBUG_OBJECT(src, "READY->PAUSED"); - GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); - priv->notifier.notify(MainThreadSourceNotification::Start, [protector] { webKitWebSrcStart(protector.get()); }); + webKitWebSrcStart(src); break; } case GST_STATE_CHANGE_PAUSED_TO_READY: { GST_DEBUG_OBJECT(src, "PAUSED->READY"); - priv->notifier.cancelPendingNotifications(); - GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); - priv->notifier.notify(MainThreadSourceNotification::Stop, [protector] { webKitWebSrcStop(protector.get()); }); + webKitWebSrcStop(src); break; } default: @@ -772,59 +754,91 @@ static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer) iface->set_uri = webKitWebSrcSetUri; } -// appsrc callbacks - static void webKitWebSrcNeedData(WebKitWebSrc* src) { WebKitWebSrcPrivate* priv = src->priv; - ASSERT(isMainThread()); - GST_DEBUG_OBJECT(src, "Need more data"); { WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); - priv->paused = FALSE; + if (!priv->paused) + return; + priv->paused = false; + if (priv->client) { + priv->client->setDefersLoading(false); + return; + } } - if (priv->client) - priv->client->setDefersLoading(false); - if (priv->resource) - priv->resource->setDefersLoading(false); + GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); + priv->notifier.notify(MainThreadSourceNotification::NeedData, [protector] { + WebKitWebSrcPrivate* priv = protector->priv; + if (priv->resource) + priv->resource->setDefersLoading(false); + }); } static void webKitWebSrcEnoughData(WebKitWebSrc* src) { WebKitWebSrcPrivate* priv = src->priv; - ASSERT(isMainThread()); - GST_DEBUG_OBJECT(src, "Have enough data"); { WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); - priv->paused = TRUE; + if (priv->paused) + return; + priv->paused = true; + if (priv->client) { + priv->client->setDefersLoading(true); + return; + } } - if (priv->client) - priv->client->setDefersLoading(true); - if (priv->resource) - priv->resource->setDefersLoading(true); + GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); + priv->notifier.notify(MainThreadSourceNotification::EnoughData, [protector] { + WebKitWebSrcPrivate* priv = protector->priv; + if (priv->resource) + priv->resource->setDefersLoading(true); + }); } -static void webKitWebSrcSeek(WebKitWebSrc* src) +static gboolean webKitWebSrcSeek(WebKitWebSrc* src, guint64 offset) { - ASSERT(isMainThread()); + WebKitWebSrcPrivate* priv = src->priv; + + { + WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); + if (offset == priv->offset && priv->requestedOffset == priv->offset) + return TRUE; + + if (!priv->seekable) + return FALSE; + + priv->isSeeking = true; + priv->requestedOffset = offset; + } GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, src->priv->requestedOffset); + if (priv->client) { + webKitWebSrcStop(src); + webKitWebSrcStart(src); + return TRUE; + } - webKitWebSrcStop(src); - webKitWebSrcStart(src); + GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); + priv->notifier.notify(MainThreadSourceNotification::Seek, [protector] { + webKitWebSrcStop(protector.get()); + webKitWebSrcStart(protector.get()); + }); + return TRUE; } void webKitWebSrcSetMediaPlayer(WebKitWebSrc* src, WebCore::MediaPlayer* player) { ASSERT(player); + ASSERT(src->priv->createdInMainThread); WTF::GMutexLocker<GMutex> locker(*GST_OBJECT_GET_LOCK(src)); src->priv->player = player; } @@ -1051,17 +1065,47 @@ void CachedResourceStreamingClient::loadFinished(PlatformMediaResource&) handleNotifyFinished(); } -ResourceHandleStreamingClient::ResourceHandleStreamingClient(WebKitWebSrc* src, const ResourceRequest& request) +ResourceHandleStreamingClient::ResourceHandleStreamingClient(WebKitWebSrc* src, ResourceRequest&& request) : StreamingClient(src) { - m_resource = ResourceHandle::create(0 /*context*/, request, this, false, false); + LockHolder locker(m_initializeRunLoopConditionMutex); + m_thread = createThread("ResourceHandleStreamingClient", [this, request] { + { + LockHolder locker(m_initializeRunLoopConditionMutex); + m_runLoop = &RunLoop::current(); + m_resource = ResourceHandle::create(nullptr /*context*/, request, this, true, false); + m_initializeRunLoopCondition.notifyOne(); + } + if (!m_resource) + return; + + m_runLoop->dispatch([this] { m_resource->setDefersLoading(false); }); + m_runLoop->run(); + { + LockHolder locker(m_terminateRunLoopConditionMutex); + m_runLoop = nullptr; + m_resource->clearClient(); + m_resource->cancel(); + m_resource = nullptr; + m_terminateRunLoopCondition.notifyOne(); + } + }); + m_initializeRunLoopCondition.wait(m_initializeRunLoopConditionMutex); } ResourceHandleStreamingClient::~ResourceHandleStreamingClient() { - if (m_resource) { - m_resource->cancel(); - m_resource = nullptr; + if (m_thread) { + detachThread(m_thread); + m_thread = 0; + } + + if (m_runLoop == &RunLoop::current()) + m_runLoop->stop(); + else { + LockHolder locker(m_terminateRunLoopConditionMutex); + m_runLoop->stop(); + m_terminateRunLoopCondition.wait(m_terminateRunLoopConditionMutex); } } @@ -1072,8 +1116,10 @@ bool ResourceHandleStreamingClient::loadFailed() const void ResourceHandleStreamingClient::setDefersLoading(bool defers) { - if (m_resource) - m_resource->setDefersLoading(defers); + m_runLoop->dispatch([this, defers] { + if (m_resource) + m_resource->setDefersLoading(defers); + }); } char* ResourceHandleStreamingClient::getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize) diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp index 39cd47ce2..78e159aa0 100644 --- a/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp +++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp @@ -24,9 +24,7 @@ #include "FontPlatformData.h" #include "SharedBuffer.h" -#if USE(ZLIB) #include "WOFFFileFormat.h" -#endif #include <QStringList> namespace WebCore { @@ -41,7 +39,6 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(const FontDescription& std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffer& buffer) { -#if USE(ZLIB) SharedBuffer* fontBuffer = &buffer; RefPtr<SharedBuffer> sfntBuffer; if (isWOFF(&buffer)) { @@ -52,15 +49,9 @@ std::unique_ptr<FontCustomPlatformData> createFontCustomPlatformData(SharedBuffe sfntBuffer = SharedBuffer::adoptVector(sfnt); fontBuffer = sfntBuffer.get(); } -#endif // USE(ZLIB) const QByteArray fontData(fontBuffer->data(), fontBuffer->size()); -#if !USE(ZLIB) - if (fontData.startsWith("wOFF")) { - qWarning("WOFF support requires QtWebKit to be built with zlib support."); - return 0; - } -#endif // !USE(ZLIB) + // Pixel size doesn't matter at this point, it is set in FontCustomPlatformData::fontPlatformData. QRawFont rawFont(fontData, /*pixelSize = */0, QFont::PreferDefaultHinting); if (!rawFont.isValid()) @@ -75,8 +66,9 @@ bool FontCustomPlatformData::supportsFormat(const String& format) { return equalLettersIgnoringASCIICase(format, "truetype") || equalLettersIgnoringASCIICase(format, "opentype") -#if USE(ZLIB) || equalLettersIgnoringASCIICase(format, "woff") +#if USE(WOFF2) + || equalLettersIgnoringASCIICase(format, "woff2") #endif ; } diff --git a/Source/WebCore/platform/graphics/qt/FontPlatformData.h b/Source/WebCore/platform/graphics/qt/FontPlatformData.h index 14e36f018..c8375ebcd 100644 --- a/Source/WebCore/platform/graphics/qt/FontPlatformData.h +++ b/Source/WebCore/platform/graphics/qt/FontPlatformData.h @@ -34,6 +34,8 @@ namespace WebCore { +class SharedBuffer; + class FontPlatformDataPrivate : public RefCounted<FontPlatformDataPrivate> { WTF_MAKE_NONCOPYABLE(FontPlatformDataPrivate); WTF_MAKE_FAST_ALLOCATED; public: @@ -117,6 +119,7 @@ public: FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. void setOrientation(FontOrientation) { } // FIXME: Implement. + PassRefPtr<SharedBuffer> openTypeTable(uint32_t table) const; unsigned hash() const; diff --git a/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp index a239d643d..2ed4a98c3 100644 --- a/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp +++ b/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -25,6 +25,7 @@ #include "FontPlatformData.h" #include "FontCascade.h" +#include "SharedBuffer.h" #include <wtf/text/WTFString.h> namespace WebCore { @@ -139,6 +140,20 @@ bool FontPlatformData::operator==(const FontPlatformData& other) const return equals; } +PassRefPtr<SharedBuffer> FontPlatformData::openTypeTable(uint32_t table) const +{ + const char tag[4] = { + char(table & 0xff), + char((table & 0xff00) >> 8), + char((table & 0xff0000) >> 16), + char(table >> 24) + }; + QByteArray tableData = m_data->rawFont.fontTable(tag); + + // TODO: Wrap SharedBuffer around QByteArray when it's possible + return SharedBuffer::create(tableData.data(), tableData.size()); +} + unsigned FontPlatformData::hash() const { if (!m_data) diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 618bf63ae..9e992381c 100644 --- a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -362,7 +362,7 @@ void GraphicsContext3DPrivate::createGraphicsSurfaces(const IntSize& size) { #if USE(GRAPHICS_SURFACE) if (size.isEmpty()) - m_graphicsSurface.clear(); + m_graphicsSurface = nullptr; else m_graphicsSurface = GraphicsSurface::create(size, m_surfaceFlags, m_platformContext); #endif diff --git a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 2ff7df102..306f99e0e 100644 --- a/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/Source/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -606,7 +606,7 @@ void QNetworkReplyHandler::sendResponseIfNeeded() // Add remaining headers. foreach (const QNetworkReply::RawHeaderPair& pair, m_replyWrapper->reply()->rawHeaderPairs()) - response.setHTTPHeaderField(QString::fromLatin1(pair.first), QString::fromLatin1(pair.second)); + response.setHTTPHeaderField(String(pair.first.constData(), pair.first.size()), String(pair.second.constData(), pair.second.size())); } QUrl redirection = m_replyWrapper->reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); diff --git a/Source/WebCore/platform/network/qt/ResourceRequest.h b/Source/WebCore/platform/network/qt/ResourceRequest.h index 1e4911f4b..e74d9024c 100644 --- a/Source/WebCore/platform/network/qt/ResourceRequest.h +++ b/Source/WebCore/platform/network/qt/ResourceRequest.h @@ -59,7 +59,7 @@ class NetworkingContext; { } - void updateFromDelegatePreservingOldHTTPBody(const ResourceRequest& delegateProvidedRequest) { *this = delegateProvidedRequest; } + void updateFromDelegatePreservingOldProperties(const ResourceRequest& delegateProvidedRequest) { *this = delegateProvidedRequest; } QNetworkRequest toNetworkRequest(NetworkingContext* = 0) const; diff --git a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp index 46229027e..83c50062d 100644 --- a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp +++ b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp @@ -89,6 +89,13 @@ static void resolveBlobUrl(const QUrl& url, QUrl& resolvedUrl) } #endif +static inline QByteArray stringToByteArray(const String& string) +{ + if (string.is8Bit()) + return QByteArray(reinterpret_cast<const char*>(string.characters8()), string.length()); + return QString(string).toLatin1(); +} + QNetworkRequest ResourceRequest::toNetworkRequest(NetworkingContext *context) const { QNetworkRequest request; @@ -105,14 +112,13 @@ QNetworkRequest ResourceRequest::toNetworkRequest(NetworkingContext *context) co const HTTPHeaderMap &headers = httpHeaderFields(); for (HTTPHeaderMap::const_iterator it = headers.begin(), end = headers.end(); it != end; ++it) { - QByteArray name = QString(it->key).toLatin1(); - QByteArray value = QString(it->value).toLatin1(); + QByteArray name = stringToByteArray(it->key); // QNetworkRequest::setRawHeader() would remove the header if the value is null // Make sure to set an empty header instead of null header. - if (!value.isNull()) - request.setRawHeader(name, value); + if (!it->value.isNull()) + request.setRawHeader(name, stringToByteArray(it->value)); else - request.setRawHeader(name, ""); + request.setRawHeader(name, QByteArrayLiteral("")); } // Make sure we always have an Accept header; some sites require this to diff --git a/Source/WebCore/platform/qt/RenderThemeQtMobile.cpp b/Source/WebCore/platform/qt/RenderThemeQtMobile.cpp index 977e42c9a..6ac59a5b8 100644 --- a/Source/WebCore/platform/qt/RenderThemeQtMobile.cpp +++ b/Source/WebCore/platform/qt/RenderThemeQtMobile.cpp @@ -275,9 +275,13 @@ QSizeF StylePainterMobile::sizeForPainterScale(const QRectF& rect) const void StylePainterMobile::drawChecker(QPainter* painter, const QRect& rect, const QColor& color) const { painter->setRenderHint(QPainter::Antialiasing, true); - QPen pen(Qt::darkGray); + int minSideSize = qMin(rect.width(), rect.height()); + QPen pen(minSideSize < 12 ? color : Qt::darkGray); pen.setCosmetic(true); - painter->setPen(pen); + if (minSideSize < 12 || minSideSize >= 16) + painter->setPen(pen); + else + painter->setPen(Qt::NoPen); painter->scale(rect.width(), rect.height()); QPainterPath path; path.moveTo(0.18, 0.47); diff --git a/Source/WebCore/rendering/AutoTableLayout.cpp b/Source/WebCore/rendering/AutoTableLayout.cpp index 3b93a5118..27330f7b0 100644 --- a/Source/WebCore/rendering/AutoTableLayout.cpp +++ b/Source/WebCore/rendering/AutoTableLayout.cpp @@ -181,9 +181,27 @@ void AutoTableLayout::fullRecalc() recalcColumn(i); } +static bool shouldScaleColumnsForParent(const RenderTable& table) +{ + RenderBlock* containingBlock = table.containingBlock(); + while (containingBlock && !is<RenderView>(containingBlock)) { + // It doesn't matter if our table is auto or fixed: auto means we don't + // scale. Fixed doesn't care if we do or not because it doesn't depend + // on the cell contents' preferred widths. + if (is<RenderTableCell>(containingBlock)) + return false; + containingBlock = containingBlock->containingBlock(); + } + return true; +} + // FIXME: This needs to be adapted for vertical writing modes. -static bool shouldScaleColumns(RenderTable* table) +static bool shouldScaleColumnsForSelf(RenderTable* table) { + // Normally, scale all columns to satisfy this from CSS2.2: + // "A percentage value for a column width is relative to the table width. + // If the table has 'width: auto', a percentage represents a constraint on the column's width" + // A special case. If this table is not fixed width and contained inside // a cell, then don't bloat the maxwidth by examining percentage growth. bool scale = true; @@ -220,7 +238,7 @@ void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, Layout maxWidth = 0; float maxPercent = 0; float maxNonPercent = 0; - bool scaleColumns = shouldScaleColumns(m_table); + bool scaleColumnsForSelf = shouldScaleColumnsForSelf(m_table); // We substitute 0 percent by (epsilon / percentScaleFactor) percent in two places below to avoid division by zero. // FIXME: Handle the 0% cases properly. @@ -230,7 +248,7 @@ void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, Layout for (size_t i = 0; i < m_layoutStruct.size(); ++i) { minWidth += m_layoutStruct[i].effectiveMinLogicalWidth; maxWidth += m_layoutStruct[i].effectiveMaxLogicalWidth; - if (scaleColumns) { + if (scaleColumnsForSelf) { if (m_layoutStruct[i].effectiveLogicalWidth.isPercent()) { float percent = std::min(m_layoutStruct[i].effectiveLogicalWidth.percent(), remainingPercent); float logicalWidth = m_layoutStruct[i].effectiveMaxLogicalWidth * 100 / std::max(percent, epsilon); @@ -241,10 +259,12 @@ void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, Layout } } - if (scaleColumns) { + if (scaleColumnsForSelf) { maxNonPercent = maxNonPercent * 100 / std::max(remainingPercent, epsilon); - maxWidth = std::max(maxWidth, LayoutUnit(std::min<float>(maxNonPercent, tableMaxWidth))); - maxWidth = std::max(maxWidth, LayoutUnit(std::min<float>(maxPercent, tableMaxWidth))); + m_scaledWidthFromPercentColumns = LayoutUnit(std::min<float>(maxNonPercent, tableMaxWidth)); + m_scaledWidthFromPercentColumns = std::max(m_scaledWidthFromPercentColumns, LayoutUnit(std::min<float>(maxPercent, tableMaxWidth))); + if (m_scaledWidthFromPercentColumns > maxWidth && shouldScaleColumnsForParent(*m_table)) + maxWidth = m_scaledWidthFromPercentColumns; } maxWidth = std::max(maxWidth, LayoutUnit(spanMaxLogicalWidth)); diff --git a/Source/WebCore/rendering/AutoTableLayout.h b/Source/WebCore/rendering/AutoTableLayout.h index ce108ad90..f73f62cf8 100644 --- a/Source/WebCore/rendering/AutoTableLayout.h +++ b/Source/WebCore/rendering/AutoTableLayout.h @@ -36,9 +36,10 @@ public: explicit AutoTableLayout(RenderTable*); virtual ~AutoTableLayout(); - virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) override; - virtual void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const override; - virtual void layout() override; + void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) override; + LayoutUnit scaledWidthFromPercentColumns() const override { return m_scaledWidthFromPercentColumns; } + void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const override; + void layout() override; private: void fullRecalc(); @@ -63,6 +64,7 @@ private: Vector<RenderTableCell*, 4> m_spanCells; bool m_hasPercent : 1; mutable bool m_effectiveLogicalWidthDirty : 1; + LayoutUnit m_scaledWidthFromPercentColumns; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/InlineIterator.h b/Source/WebCore/rendering/InlineIterator.h index 0c8fb3827..4dc5b4f21 100644 --- a/Source/WebCore/rendering/InlineIterator.h +++ b/Source/WebCore/rendering/InlineIterator.h @@ -492,7 +492,7 @@ static inline unsigned numberOfIsolateAncestors(const InlineIterator& iter) // of BidiResolver which knows nothing about RenderObjects. static inline void addPlaceholderRunForIsolatedInline(InlineBidiResolver& resolver, RenderObject& obj, unsigned pos, RenderElement& root) { - BidiRun* isolatedRun = new BidiRun(pos, 0, obj, resolver.context(), resolver.dir()); + BidiRun* isolatedRun = new BidiRun(pos, pos, obj, resolver.context(), resolver.dir()); resolver.runs().addRun(isolatedRun); // FIXME: isolatedRuns() could be a hash of object->run and then we could cheaply // ASSERT here that we didn't create multiple objects for the same inline. diff --git a/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h b/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h index aefe10738..cb48a3642 100644 --- a/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h +++ b/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h @@ -38,7 +38,8 @@ public: void setBlock(RenderBlock* block, const LogicalSelectionOffsetCaches* cache, bool parentCacheHasFloatsOrFlowThreads = false) { m_block = block; - m_hasFloatsOrFlowThreads = parentCacheHasFloatsOrFlowThreads || m_hasFloatsOrFlowThreads || m_block->containsFloats() || m_block->flowThreadContainingBlock(); + bool blockHasFloatsOrFlowThreads = m_block ? (m_block->containsFloats() || m_block->flowThreadContainingBlock()) : false; + m_hasFloatsOrFlowThreads = parentCacheHasFloatsOrFlowThreads || m_hasFloatsOrFlowThreads || blockHasFloatsOrFlowThreads; m_cache = cache; m_cachedLogicalLeftSelectionOffset = false; m_cachedLogicalRightSelectionOffset = false; @@ -49,9 +50,9 @@ public: ASSERT(m_cache); if (m_hasFloatsOrFlowThreads || !m_cachedLogicalLeftSelectionOffset) { m_cachedLogicalLeftSelectionOffset = true; - m_logicalLeftSelectionOffset = m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache); + m_logicalLeftSelectionOffset = m_block ? m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache) : LayoutUnit::fromPixel(0); } else - ASSERT(m_logicalLeftSelectionOffset == m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache)); + ASSERT(m_logicalLeftSelectionOffset == (m_block ? m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache) : LayoutUnit::fromPixel(0))); return m_logicalLeftSelectionOffset; } @@ -60,9 +61,9 @@ public: ASSERT(m_cache); if (m_hasFloatsOrFlowThreads || !m_cachedLogicalRightSelectionOffset) { m_cachedLogicalRightSelectionOffset = true; - m_logicalRightSelectionOffset = m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache); + m_logicalRightSelectionOffset = m_block ? m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache) : LayoutUnit::fromPixel(0); } else - ASSERT(m_logicalRightSelectionOffset == m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache)); + ASSERT(m_logicalRightSelectionOffset == (m_block ? m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache) : LayoutUnit::fromPixel(0))); return m_logicalRightSelectionOffset; } diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 3ffdef97d..bf1a78a7f 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -92,11 +92,136 @@ struct SameSizeAsRenderBlock : public RenderBox { COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small); -static TrackedDescendantsMap* gPositionedDescendantsMap; -static TrackedDescendantsMap* gPercentHeightDescendantsMap; +typedef HashMap<const RenderBlock*, std::unique_ptr<TrackedRendererListHashSet>> TrackedDescendantsMap; +typedef HashMap<const RenderBox*, std::unique_ptr<HashSet<const RenderBlock*>>> TrackedContainerMap; -static TrackedContainerMap* gPositionedContainerMap; -static TrackedContainerMap* gPercentHeightContainerMap; +static TrackedDescendantsMap* percentHeightDescendantsMap; +static TrackedContainerMap* percentHeightContainerMap; + +static void insertIntoTrackedRendererMaps(const RenderBlock& container, RenderBox& descendant) +{ + if (!percentHeightDescendantsMap) { + percentHeightDescendantsMap = new TrackedDescendantsMap; + percentHeightContainerMap = new TrackedContainerMap; + } + + auto& descendantSet = percentHeightDescendantsMap->ensure(&container, [] { + return std::make_unique<TrackedRendererListHashSet>(); + }).iterator->value; + + bool added = descendantSet->add(&descendant).isNewEntry; + if (!added) { + ASSERT(percentHeightContainerMap->get(&descendant)); + ASSERT(percentHeightContainerMap->get(&descendant)->contains(&container)); + return; + } + + auto& containerSet = percentHeightContainerMap->ensure(&descendant, [] { + return std::make_unique<HashSet<const RenderBlock*>>(); + }).iterator->value; + + ASSERT(!containerSet->contains(&container)); + containerSet->add(&container); +} + +static void removeFromTrackedRendererMaps(RenderBox& descendant) +{ + if (!percentHeightDescendantsMap) + return; + + std::unique_ptr<HashSet<const RenderBlock*>> containerSet = percentHeightContainerMap->take(&descendant); + if (!containerSet) + return; + + for (auto* container : *containerSet) { + // FIXME: Disabling this assert temporarily until we fix the layout + // bugs associated with positioned objects not properly cleared from + // their ancestor chain before being moved. See webkit bug 93766. + // ASSERT(descendant->isDescendantOf(container)); + auto descendantsMapIterator = percentHeightDescendantsMap->find(container); + ASSERT(descendantsMapIterator != percentHeightDescendantsMap->end()); + if (descendantsMapIterator == percentHeightDescendantsMap->end()) + continue; + auto& descendantSet = descendantsMapIterator->value; + ASSERT(descendantSet->contains(&descendant)); + descendantSet->remove(&descendant); + if (descendantSet->isEmpty()) + percentHeightDescendantsMap->remove(descendantsMapIterator); + } +} + +class PositionedDescendantsMap { +public: + enum class MoveDescendantToEnd { No, Yes }; + void addDescendant(const RenderBlock& containingBlock, RenderBox& positionedDescendant, MoveDescendantToEnd moveDescendantToEnd) + { + // Protect against double insert where a descendant would end up with multiple containing blocks. + auto* previousContainingBlock = m_containerMap.get(&positionedDescendant); + if (previousContainingBlock && previousContainingBlock != &containingBlock) { + if (auto* descendants = m_descendantsMap.get(previousContainingBlock)) + descendants->remove(&positionedDescendant); + } + + auto& descendants = m_descendantsMap.ensure(&containingBlock, [] { + return std::make_unique<TrackedRendererListHashSet>(); + }).iterator->value; + + bool isNewEntry = moveDescendantToEnd == MoveDescendantToEnd::Yes ? descendants->appendOrMoveToLast(&positionedDescendant).isNewEntry + : descendants->add(&positionedDescendant).isNewEntry; + if (!isNewEntry) { + ASSERT(m_containerMap.contains(&positionedDescendant)); + return; + } + m_containerMap.set(&positionedDescendant, &containingBlock); + } + + void removeDescendant(const RenderBox& positionedDescendant) + { + auto* containingBlock = m_containerMap.take(&positionedDescendant); + if (!containingBlock) + return; + + auto descendantsIterator = m_descendantsMap.find(containingBlock); + ASSERT(descendantsIterator != m_descendantsMap.end()); + if (descendantsIterator == m_descendantsMap.end()) + return; + + auto& descendants = descendantsIterator->value; + ASSERT(descendants->contains(const_cast<RenderBox*>(&positionedDescendant))); + + descendants->remove(const_cast<RenderBox*>(&positionedDescendant)); + if (descendants->isEmpty()) + m_descendantsMap.remove(descendantsIterator); + } + + void removeContainingBlock(const RenderBlock& containingBlock) + { + auto descendants = m_descendantsMap.take(&containingBlock); + if (!descendants) + return; + + for (auto* renderer : *descendants) + m_containerMap.remove(renderer); + } + + TrackedRendererListHashSet* positionedRenderers(const RenderBlock& containingBlock) const + { + return m_descendantsMap.get(&containingBlock); + } + +private: + using DescendantsMap = HashMap<const RenderBlock*, std::unique_ptr<TrackedRendererListHashSet>>; + using ContainerMap = HashMap<const RenderBox*, const RenderBlock*>; + + DescendantsMap m_descendantsMap; + ContainerMap m_containerMap; +}; + +static PositionedDescendantsMap& positionedDescendantsMap() +{ + static NeverDestroyed<PositionedDescendantsMap> mapForPositionedDescendants; + return mapForPositionedDescendants; +} typedef HashMap<RenderBlock*, std::unique_ptr<ListHashSet<RenderInline*>>> ContinuationOutlineTableMap; @@ -192,21 +317,24 @@ RenderBlock::RenderBlock(Document& document, Ref<RenderStyle>&& style, BaseTypeF { } -static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap) +static void removeBlockFromPercentageDescendantAndContainerMaps(RenderBlock* block) { - if (std::unique_ptr<TrackedRendererListHashSet> descendantSet = descendantMap->take(block)) { - TrackedRendererListHashSet::iterator end = descendantSet->end(); - for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) { - TrackedContainerMap::iterator it = containerMap->find(*descendant); - ASSERT(it != containerMap->end()); - if (it == containerMap->end()) - continue; - HashSet<RenderBlock*>* containerSet = it->value.get(); - ASSERT(containerSet->contains(block)); - containerSet->remove(block); - if (containerSet->isEmpty()) - containerMap->remove(it); - } + if (!percentHeightDescendantsMap) + return; + std::unique_ptr<TrackedRendererListHashSet> descendantSet = percentHeightDescendantsMap->take(block); + if (!descendantSet) + return; + + for (auto* descendant : *descendantSet) { + auto it = percentHeightContainerMap->find(descendant); + ASSERT(it != percentHeightContainerMap->end()); + if (it == percentHeightContainerMap->end()) + continue; + auto* containerSet = it->value.get(); + ASSERT(containerSet->contains(block)); + containerSet->remove(block); + if (containerSet->isEmpty()) + percentHeightContainerMap->remove(it); } } @@ -216,10 +344,8 @@ RenderBlock::~RenderBlock() if (gRareDataMap) gRareDataMap->remove(this); - if (gPercentHeightDescendantsMap) - removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap); - if (gPositionedDescendantsMap) - removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap); + removeBlockFromPercentageDescendantAndContainerMaps(this); + positionedDescendantsMap().removeContainingBlock(*this); } void RenderBlock::willBeDestroyed() @@ -244,14 +370,20 @@ void RenderBlock::removePositionedObjectsIfNeeded(const RenderStyle& oldStyle, c if (oldStyle.position() == newStyle.position() && hadTransform == willHaveTransform) return; - // We are no longer a containing block. + // We are no longer the containing block for fixed descendants. + if (hadTransform && !willHaveTransform) { + // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout. + removePositionedObjects(nullptr, NewContainingBlock); + return; + } + + // We are no longer the containing block for absolute positioned descendants. if (newStyle.position() == StaticPosition && !willHaveTransform) { - // Clear our positioned objects list. Our absolutely positioned descendants will be - // inserted into our containing block's positioned objects list during layout. + // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout. removePositionedObjects(nullptr, NewContainingBlock); return; } - + // We are a new containing block. if (oldStyle.position() == StaticPosition && !hadTransform) { // Remove our absolutely positioned descendants from their current containing block. @@ -1157,10 +1289,10 @@ void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, R void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants() { - if (!gPercentHeightDescendantsMap) + if (!percentHeightDescendantsMap) return; - TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this); + TrackedRendererListHashSet* descendants = percentHeightDescendantsMap->get(this); if (!descendants) return; @@ -1264,34 +1396,33 @@ bool RenderBlock::simplifiedLayout() return true; } -void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject& child) +void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderBox& positionedChild) { - if (child.style().position() != FixedPosition) + if (positionedChild.style().position() != FixedPosition) return; - bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontalWritingMode()); - bool hasStaticInlinePosition = child.style().hasStaticInlinePosition(isHorizontalWritingMode()); + bool hasStaticBlockPosition = positionedChild.style().hasStaticBlockPosition(isHorizontalWritingMode()); + bool hasStaticInlinePosition = positionedChild.style().hasStaticInlinePosition(isHorizontalWritingMode()); if (!hasStaticBlockPosition && !hasStaticInlinePosition) return; - auto o = child.parent(); - while (o && !is<RenderView>(*o) && o->style().position() != AbsolutePosition) - o = o->parent(); - if (o->style().position() != AbsolutePosition) + auto* parent = positionedChild.parent(); + while (parent && !is<RenderView>(*parent) && parent->style().position() != AbsolutePosition) + parent = parent->parent(); + if (!parent || parent->style().position() != AbsolutePosition) return; - auto& box = downcast<RenderBox>(child); if (hasStaticInlinePosition) { LogicalExtentComputedValues computedValues; - box.computeLogicalWidthInRegion(computedValues); + positionedChild.computeLogicalWidthInRegion(computedValues); LayoutUnit newLeft = computedValues.m_position; - if (newLeft != box.logicalLeft()) - box.setChildNeedsLayout(MarkOnlyThis); + if (newLeft != positionedChild.logicalLeft()) + positionedChild.setChildNeedsLayout(MarkOnlyThis); } else if (hasStaticBlockPosition) { - LayoutUnit oldTop = box.logicalTop(); - box.updateLogicalHeight(); - if (box.logicalTop() != oldTop) - box.setChildNeedsLayout(MarkOnlyThis); + LayoutUnit oldTop = positionedChild.logicalTop(); + positionedChild.updateLogicalHeight(); + if (positionedChild.logicalTop() != oldTop) + positionedChild.setChildNeedsLayout(MarkOnlyThis); } } @@ -2049,6 +2180,8 @@ LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock& rootBlock, Layou ASSERT(currentCache); auto info = currentCache->containingBlockInfo(*cb); cb = info.block(); + if (!cb) + break; currentCache = info.cache(); } return logicalLeft; @@ -2071,6 +2204,8 @@ LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock& rootBlock, Layo ASSERT(currentCache); auto info = currentCache->containingBlockInfo(*cb); cb = info.block(); + if (!cb) + break; currentCache = info.cache(); } return logicalRight; @@ -2108,148 +2243,79 @@ RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) con return beforeBlock; } -void RenderBlock::insertIntoTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap, bool forceNewEntry) -{ - if (!descendantsMap) { - descendantsMap = new TrackedDescendantsMap; - containerMap = new TrackedContainerMap; - } - - TrackedRendererListHashSet* descendantSet = descendantsMap->get(this); - if (!descendantSet) { - descendantSet = new TrackedRendererListHashSet; - descendantsMap->set(this, std::unique_ptr<TrackedRendererListHashSet>(descendantSet)); - } - - if (forceNewEntry) { - descendantSet->remove(&descendant); - containerMap->remove(&descendant); - } - - bool added = descendantSet->add(&descendant).isNewEntry; - if (!added) { - ASSERT(containerMap->get(&descendant)); - ASSERT(containerMap->get(&descendant)->contains(this)); - return; - } - - HashSet<RenderBlock*>* containerSet = containerMap->get(&descendant); - if (!containerSet) { - containerSet = new HashSet<RenderBlock*>; - containerMap->set(&descendant, std::unique_ptr<HashSet<RenderBlock*>>(containerSet)); - } - ASSERT(!containerSet->contains(this)); - containerSet->add(this); -} - -void RenderBlock::removeFromTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap) -{ - if (!descendantsMap) - return; - - std::unique_ptr<HashSet<RenderBlock*>> containerSet = containerMap->take(&descendant); - if (!containerSet) - return; - - for (auto it = containerSet->begin(), end = containerSet->end(); it != end; ++it) { - RenderBlock* container = *it; - - // FIXME: Disabling this assert temporarily until we fix the layout - // bugs associated with positioned objects not properly cleared from - // their ancestor chain before being moved. See webkit bug 93766. - // ASSERT(descendant->isDescendantOf(container)); - - TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container); - ASSERT(descendantsMapIterator != descendantsMap->end()); - if (descendantsMapIterator == descendantsMap->end()) - continue; - TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get(); - ASSERT(descendantSet->contains(&descendant)); - descendantSet->remove(&descendant); - if (descendantSet->isEmpty()) - descendantsMap->remove(descendantsMapIterator); - } -} - TrackedRendererListHashSet* RenderBlock::positionedObjects() const { - if (gPositionedDescendantsMap) - return gPositionedDescendantsMap->get(this); - return nullptr; + return positionedDescendantsMap().positionedRenderers(*this); } -void RenderBlock::insertPositionedObject(RenderBox& o) +void RenderBlock::insertPositionedObject(RenderBox& positioned) { ASSERT(!isAnonymousBlock()); - if (o.isRenderFlowThread()) + if (positioned.isRenderFlowThread()) return; - - insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap, isRenderView()); + + positionedDescendantsMap().addDescendant(*this, positioned, isRenderView() ? PositionedDescendantsMap::MoveDescendantToEnd::Yes + : PositionedDescendantsMap::MoveDescendantToEnd::No); } -void RenderBlock::removePositionedObject(RenderBox& o) +void RenderBlock::removePositionedObject(const RenderBox& rendererToRemove) { - removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap); + positionedDescendantsMap().removeDescendant(rendererToRemove); } -void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState) +void RenderBlock::removePositionedObjects(const RenderBlock* newContainingBlockCandidate, ContainingBlockState containingBlockState) { - TrackedRendererListHashSet* positionedDescendants = positionedObjects(); + auto* positionedDescendants = positionedObjects(); if (!positionedDescendants) return; - Vector<RenderBox*, 16> deadObjects; - - for (auto it = positionedDescendants->begin(), end = positionedDescendants->end(); it != end; ++it) { - RenderBox* r = *it; - if (!o || r->isDescendantOf(o)) { - if (containingBlockState == NewContainingBlock) - r->setChildNeedsLayout(MarkOnlyThis); - - // It is parent blocks job to add positioned child to positioned objects list of its containing block - // Parent layout needs to be invalidated to ensure this happens. - RenderElement* p = r->parent(); - while (p && !p->isRenderBlock()) - p = p->parent(); - if (p) - p->setChildNeedsLayout(); - - deadObjects.append(r); - } + Vector<RenderBox*, 16> renderersToRemove; + for (auto* renderer : *positionedDescendants) { + if (newContainingBlockCandidate && !renderer->isDescendantOf(newContainingBlockCandidate)) + continue; + renderersToRemove.append(renderer); + if (containingBlockState == NewContainingBlock) + renderer->setChildNeedsLayout(MarkOnlyThis); + // It is the parent block's job to add positioned children to positioned objects list of its containing block. + // Dirty the parent to ensure this happens. + auto* parent = renderer->parent(); + while (parent && !parent->isRenderBlock()) + parent = parent->parent(); + if (parent) + parent->setChildNeedsLayout(); } - - for (unsigned i = 0; i < deadObjects.size(); i++) - removePositionedObject(*deadObjects.at(i)); + for (auto* renderer : renderersToRemove) + removePositionedObject(*renderer); } void RenderBlock::addPercentHeightDescendant(RenderBox& descendant) { - insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap); + insertIntoTrackedRendererMaps(*this, descendant); } void RenderBlock::removePercentHeightDescendant(RenderBox& descendant) { - removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap); + removeFromTrackedRendererMaps(descendant); } TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const { - return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; + return percentHeightDescendantsMap ? percentHeightDescendantsMap->get(this) : nullptr; } bool RenderBlock::hasPercentHeightContainerMap() { - return gPercentHeightContainerMap; + return percentHeightContainerMap; } bool RenderBlock::hasPercentHeightDescendant(RenderBox& descendant) { - // We don't null check gPercentHeightContainerMap since the caller + // We don't null check percentHeightContainerMap since the caller // already ensures this and we need to call this function on every // descendant in clearPercentHeightDescendantsFrom(). - ASSERT(gPercentHeightContainerMap); - return gPercentHeightContainerMap->contains(&descendant); + ASSERT(percentHeightContainerMap); + return percentHeightContainerMap->contains(&descendant); } void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox& descendant) @@ -2268,7 +2334,7 @@ void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox& descendant) void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox& parent) { - ASSERT(gPercentHeightContainerMap); + ASSERT(percentHeightContainerMap); for (RenderObject* child = parent.firstChild(); child; child = child->nextInPreOrder(&parent)) { if (!is<RenderBox>(*child)) continue; @@ -3768,17 +3834,12 @@ RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const Rend #ifndef NDEBUG void RenderBlock::checkPositionedObjectsNeedLayout() { - if (!gPositionedDescendantsMap) - return; - - TrackedRendererListHashSet* positionedDescendantSet = positionedObjects(); - if (!positionedDescendantSet) + auto* positionedDescendants = positionedObjects(); + if (!positionedDescendants) return; - for (auto it = positionedDescendantSet->begin(), end = positionedDescendantSet->end(); it != end; ++it) { - RenderBox* currBox = *it; - ASSERT(!currBox->needsLayout()); - } + for (auto* renderer : *positionedDescendants) + ASSERT(!renderer->needsLayout()); } #endif diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index bb618e486..49468c586 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -42,8 +42,6 @@ struct BidiRun; struct PaintInfo; typedef WTF::ListHashSet<RenderBox*> TrackedRendererListHashSet; -typedef WTF::HashMap<const RenderBlock*, std::unique_ptr<TrackedRendererListHashSet>> TrackedDescendantsMap; -typedef WTF::HashMap<const RenderBox*, std::unique_ptr<HashSet<RenderBlock*>>> TrackedContainerMap; enum CaretType { CursorCaret, DragCaret }; enum ContainingBlockState { NewContainingBlock, SameContainingBlock }; @@ -83,8 +81,8 @@ public: virtual void invalidateLineLayoutPath() { } void insertPositionedObject(RenderBox&); - static void removePositionedObject(RenderBox&); - void removePositionedObjects(RenderBlock*, ContainingBlockState = SameContainingBlock); + static void removePositionedObject(const RenderBox&); + void removePositionedObjects(const RenderBlock*, ContainingBlockState = SameContainingBlock); TrackedRendererListHashSet* positionedObjects() const; bool hasPositionedObjects() const @@ -316,7 +314,7 @@ protected: void layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly = false); virtual void layoutPositionedObject(RenderBox&, bool relayoutChildren, bool fixedPositionObjectsOnly); - void markFixedPositionObjectForLayoutIfNeeded(RenderObject& child); + void markFixedPositionObjectForLayoutIfNeeded(RenderBox& child); LayoutUnit marginIntrinsicLogicalWidthForChild(RenderBox&) const; @@ -417,12 +415,6 @@ private: virtual bool isSelfCollapsingBlock() const override; virtual bool childrenPreventSelfCollapsing() const; - // FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to RenderBlockFlow - virtual bool hasLines() const { return false; } - - void insertIntoTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*&, TrackedContainerMap*&, bool forceNewEntry = false); - static void removeFromTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*&, TrackedContainerMap*&); - void createFirstLetterRenderer(RenderElement* firstLetterBlock, RenderText* currentTextChild); void updateFirstLetterStyle(RenderElement* firstLetterBlock, RenderObject* firstLetterContainer); diff --git a/Source/WebCore/rendering/RenderBlockFlow.cpp b/Source/WebCore/rendering/RenderBlockFlow.cpp index 33bce4025..53ff0b6c7 100644 --- a/Source/WebCore/rendering/RenderBlockFlow.cpp +++ b/Source/WebCore/rendering/RenderBlockFlow.cpp @@ -1648,7 +1648,15 @@ static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox) return false; } - + +static void clearShouldBreakAtLineToAvoidWidowIfNeeded(RenderBlockFlow& blockFlow) +{ + if (!blockFlow.shouldBreakAtLineToAvoidWidow()) + return; + blockFlow.clearShouldBreakAtLineToAvoidWidow(); + blockFlow.setDidBreakAtLineToAvoidWidow(); +} + void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread) { // FIXME: Ignore anonymous inline blocks. Handle the delta already having been set because of @@ -1702,8 +1710,11 @@ void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, La logicalBottom = intMinForLayoutUnit; lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom); lineHeight = logicalBottom - logicalOffset; - if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight) - return; // Give up. We're genuinely too big even after excluding blank space and overflow. + if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight) { + // Give up. We're genuinely too big even after excluding blank space and overflow. + clearShouldBreakAtLineToAvoidWidowIfNeeded(*this); + return; + } pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); } @@ -1712,10 +1723,8 @@ void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, La int lineIndex = lineCount(lineBox); if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) { - if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) { - clearShouldBreakAtLineToAvoidWidow(); - setDidBreakAtLineToAvoidWidow(); - } + if (lineBreakToAvoidWidow() == lineIndex) + clearShouldBreakAtLineToAvoidWidowIfNeeded(*this); // If we have a non-uniform page height, then we have to shift further possibly. if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight)) return; @@ -3528,7 +3537,8 @@ bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher) bool RenderBlockFlow::hasLines() const { - ASSERT(childrenInline()); + if (!childrenInline()) + return false; if (auto simpleLineLayout = this->simpleLineLayout()) return simpleLineLayout->lineCount(); diff --git a/Source/WebCore/rendering/RenderBlockFlow.h b/Source/WebCore/rendering/RenderBlockFlow.h index 3b9d81268..84766c45b 100644 --- a/Source/WebCore/rendering/RenderBlockFlow.h +++ b/Source/WebCore/rendering/RenderBlockFlow.h @@ -345,8 +345,8 @@ public: RootInlineBox* firstRootBox() const { return downcast<RootInlineBox>(m_lineBoxes.firstLineBox()); } RootInlineBox* lastRootBox() const { return downcast<RootInlineBox>(m_lineBoxes.lastLineBox()); } - virtual bool hasLines() const override final; - virtual void invalidateLineLayoutPath() override final; + bool hasLines() const; + void invalidateLineLayoutPath() final; enum LineLayoutPath { UndeterminedPath = 0, SimpleLinesPath, LineBoxesPath, ForceLineBoxesPath }; LineLayoutPath lineLayoutPath() const { return static_cast<LineLayoutPath>(renderBlockFlowLineLayoutPath()); } diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index 451de09c9..d67c38daa 100644 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -2250,6 +2250,10 @@ void RenderBlockFlow::marginCollapseLinesFromStart(LineLayoutState& layoutState, if (!stopLine->hasAnonymousInlineBlock()) return; + // We already handled top of block with startLine. + if (stopLine == firstRootBox()) + return; + // Re-run margin collapsing on the block sequence that stopLine is a part of. // First go backwards to get the entire sequence. RootInlineBox* prev = stopLine; diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index c437851c0..e4809d288 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -120,18 +120,12 @@ static bool skipBodyBackground(const RenderBox* bodyElementRenderer) RenderBox::RenderBox(Element& element, Ref<RenderStyle>&& style, BaseTypeFlags baseTypeFlags) : RenderBoxModelObject(element, WTFMove(style), baseTypeFlags) - , m_minPreferredLogicalWidth(-1) - , m_maxPreferredLogicalWidth(-1) - , m_inlineBoxWrapper(nullptr) { setIsBox(); } RenderBox::RenderBox(Document& document, Ref<RenderStyle>&& style, BaseTypeFlags baseTypeFlags) : RenderBoxModelObject(document, WTFMove(style), baseTypeFlags) - , m_minPreferredLogicalWidth(-1) - , m_maxPreferredLogicalWidth(-1) - , m_inlineBoxWrapper(nullptr) { setIsBox(); } @@ -516,17 +510,19 @@ void RenderBox::updateFromStyle() boxHasOverflowClip = false; } } - // Check for overflow clip. // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value. if (boxHasOverflowClip) { - if (!s_hadOverflowClip) - // Erase the overflow - repaint(); + if (!s_hadOverflowClip && hasRenderOverflow()) { + // Erase the overflow. + // Overflow changes have to result in immediate repaints of the entire layout overflow area because + // repaints issued by removal of descendants get clipped using the updated style when they shouldn't. + repaintRectangle(visualOverflowRect()); + repaintRectangle(layoutOverflowRect()); + } setHasOverflowClip(); } } - setHasTransformRelatedProperty(styleToUse.hasTransformRelatedProperty()); setHasReflection(styleToUse.boxReflect()); } @@ -2121,13 +2117,14 @@ std::unique_ptr<InlineElementBox> RenderBox::createInlineBox() void RenderBox::dirtyLineBoxes(bool fullLayout) { - if (m_inlineBoxWrapper) { - if (fullLayout) { - delete m_inlineBoxWrapper; - m_inlineBoxWrapper = nullptr; - } else - m_inlineBoxWrapper->dirtyLineBoxes(); - } + if (!m_inlineBoxWrapper) + return; + + if (fullLayout) { + delete m_inlineBoxWrapper; + m_inlineBoxWrapper = nullptr; + } else + m_inlineBoxWrapper->dirtyLineBoxes(); } void RenderBox::positionLineBox(InlineElementBox& box) @@ -2163,12 +2160,13 @@ void RenderBox::positionLineBox(InlineElementBox& box) void RenderBox::deleteLineBoxWrapper() { - if (m_inlineBoxWrapper) { - if (!documentBeingDestroyed()) - m_inlineBoxWrapper->removeFromParent(); - delete m_inlineBoxWrapper; - m_inlineBoxWrapper = nullptr; - } + if (!m_inlineBoxWrapper) + return; + + if (!documentBeingDestroyed()) + m_inlineBoxWrapper->removeFromParent(); + delete m_inlineBoxWrapper; + m_inlineBoxWrapper = nullptr; } LayoutRect RenderBox::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index 508ba3d28..8e63a2c82 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -740,7 +740,7 @@ protected: LayoutUnit m_maxPreferredLogicalWidth; // For inline replaced elements, the inline box that owns us. - InlineElementBox* m_inlineBoxWrapper; + InlineElementBox* m_inlineBoxWrapper { nullptr }; // Our overflow information. RefPtr<RenderOverflow> m_overflow; diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp index 98e9f2d06..5b0a83de7 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp @@ -363,7 +363,7 @@ LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning() return std::max(clientLogicalBottom(), maxChildLogicalBottom); } -bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox& child) const +bool RenderFlexibleBox::hasOrthogonalFlow(const RenderBox& child) const { // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow. return isHorizontalFlow() != child.isHorizontalWritingMode(); @@ -450,14 +450,14 @@ LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHei return contentLogicalWidth(); } -Optional<LayoutUnit> RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox& child, SizeType sizeType, const Length& size) +Optional<LayoutUnit> RenderFlexibleBox::computeMainAxisExtentForChild(const RenderBox& child, SizeType sizeType, const Length& size) { // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order // to figure out the logical height/width. if (isColumnFlow()) { // We don't have to check for "auto" here - computeContentLogicalHeight will just return Nullopt for that case anyway. if (size.isIntrinsic()) - child.layoutIfNeeded(); + const_cast<RenderBox&>(child).layoutIfNeeded(); // FIXME: Should not need to do a layout here. return child.computeContentLogicalHeight(sizeType, size, child.logicalHeight() - child.borderAndPaddingLogicalHeight()); } // FIXME: Figure out how this should work for regions and pass in the appropriate values. @@ -648,15 +648,14 @@ LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox& { return isHorizontalFlow() ? child.horizontalBorderAndPaddingExtent() : child.verticalBorderAndPaddingExtent(); } - -bool RenderFlexibleBox::mainAxisExtentIsDefinite() const -{ - return isColumnFlow() ? hasDefiniteLogicalHeight() : hasDefiniteLogicalWidth(); -} - -bool RenderFlexibleBox::mainAxisLengthIsIndefinite(const Length& flexBasis) const + +bool RenderFlexibleBox::mainAxisLengthIsDefinite(const RenderBox& child, const Length& flexBasis) const { - return flexBasis.isAuto() || (flexBasis.isPercentOrCalculated() && !mainAxisExtentIsDefinite()); + if (flexBasis.isAuto()) + return false; + if (flexBasis.isPercentOrCalculated()) + return isColumnFlow() ? bool(child.computePercentageLogicalHeight(flexBasis)) : hasDefiniteLogicalWidth(); + return true; } LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox& child) const @@ -855,7 +854,72 @@ void RenderFlexibleBox::prepareOrderIteratorAndMargins() } } -LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox& child, LayoutUnit childSize) +bool RenderFlexibleBox::crossAxisLengthIsDefinite(const RenderBox& child, const Length& length) const +{ + if (length.isAuto()) + return false; + if (length.isPercentOrCalculated()) + return hasOrthogonalFlow(child) ? hasDefiniteLogicalWidth() : bool(child.computePercentageLogicalHeight(length)); + return length.isFixed(); +} + + +Optional<LayoutUnit> RenderFlexibleBox::computeMainSizeFromAspectRatioUsing(const RenderBox& child, Length crossSizeLength) const +{ + ASSERT(child.hasAspectRatio()); + ASSERT(child.intrinsicSize().height() > 0); + + Optional<LayoutUnit> crossSize; + if (crossSizeLength.isFixed()) + crossSize = LayoutUnit(crossSizeLength.value()); + else { + ASSERT(crossSizeLength.isPercentOrCalculated()); + crossSize = hasOrthogonalFlow(child) ? + adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(crossSizeLength, contentWidth())) : + child.computePercentageLogicalHeight(crossSizeLength); + } + + if (!crossSize) + return crossSize; + + const LayoutSize& childIntrinsicSize = child.intrinsicSize(); + double ratio = childIntrinsicSize.width().toFloat() / childIntrinsicSize.height().toFloat(); + if (isHorizontalFlow()) + return LayoutUnit(crossSize.value() * ratio); + return LayoutUnit(crossSize.value() / ratio); +} + +LayoutUnit RenderFlexibleBox::adjustChildSizeForAspectRatioCrossAxisMinAndMax(const RenderBox& child, LayoutUnit childSize) +{ + Length crossMin = isHorizontalFlow() ? child.style().minHeight() : child.style().minWidth(); + Length crossMax = isHorizontalFlow() ? child.style().maxHeight() : child.style().maxWidth(); + + if (crossAxisLengthIsDefinite(child, crossMax)) { + Optional<LayoutUnit> maxValue = computeMainSizeFromAspectRatioUsing(child, crossMax); + if (maxValue) + childSize = std::min(maxValue.value(), childSize); + } + + if (crossAxisLengthIsDefinite(child, crossMin)) { + Optional<LayoutUnit> minValue = computeMainSizeFromAspectRatioUsing(child, crossMin); + if (minValue) + childSize = std::max(minValue.value(), childSize); + } + + return childSize; +} + +bool RenderFlexibleBox::useChildAspectRatio(const RenderBox& child) const +{ + if (!child.hasAspectRatio()) + return false; + if (!child.intrinsicSize().height()) + return false; + Length crossSize = isHorizontalFlow() ? child.style().height() : child.style().width(); + return crossAxisLengthIsDefinite(child, crossSize); +} + +LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(const RenderBox& child, LayoutUnit childSize) { Length max = isHorizontalFlow() ? child.style().maxWidth() : child.style().maxHeight(); Optional<LayoutUnit> maxExtent = Nullopt; @@ -863,26 +927,36 @@ LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox& child, Layo maxExtent = computeMainAxisExtentForChild(child, MaxSize, max); childSize = std::min(childSize, maxExtent.valueOr(childSize)); } - + Length min = isHorizontalFlow() ? child.style().minWidth() : child.style().minHeight(); if (min.isSpecifiedOrIntrinsic()) return std::max(childSize, computeMainAxisExtentForChild(child, MinSize, min).valueOr(childSize)); - - if (!isFlexibleBoxImpl() && min.isAuto() && mainAxisOverflowForChild(child) == OVISIBLE) { + + if (!isFlexibleBoxImpl() && min.isAuto() && mainAxisOverflowForChild(child) == OVISIBLE && !(isColumnFlow() && is<RenderFlexibleBox>(child))) { // This is the implementation of CSS flexbox section 4.5 which defines the minimum size of "pure" flex // items. For any other item the value should be 0, this also includes RenderFlexibleBox's derived clases // (RenderButton, RenderFullScreen...) because that's just an implementation detail. + // FIXME: For now we don't handle nested column flexboxes. Need to implement better intrinsic + // size handling from the flex box spec first (4.5). LayoutUnit contentSize = computeMainAxisExtentForChild(child, MinSize, Length(MinContent)).value(); ASSERT(contentSize >= 0); + if (child.hasAspectRatio() && child.intrinsicSize().height() > 0) + contentSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, contentSize); contentSize = std::min(contentSize, maxExtent.valueOr(contentSize)); - + Length mainSize = isHorizontalFlow() ? child.style().width() : child.style().height(); - if (!mainAxisLengthIsIndefinite(mainSize)) { + if (mainAxisLengthIsDefinite(child, mainSize)) { LayoutUnit resolvedMainSize = computeMainAxisExtentForChild(child, MainOrPreferredSize, mainSize).value(); ASSERT(resolvedMainSize >= 0); LayoutUnit specifiedSize = std::min(resolvedMainSize, maxExtent.valueOr(resolvedMainSize)); - return std::max(childSize, std::min(specifiedSize, contentSize)); + } else if (useChildAspectRatio(child)) { + Length crossSizeLength = isHorizontalFlow() ? child.style().height() : child.style().width(); + Optional<LayoutUnit> transferredSize = computeMainSizeFromAspectRatioUsing(child, crossSizeLength); + if (transferredSize) { + transferredSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, transferredSize.value()); + return std::max(childSize, std::min(transferredSize.value(), contentSize)); + } } return std::max(childSize, contentSize); } @@ -1085,7 +1159,7 @@ void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox& chil child.updateLogicalHeight(); } -EOverflow RenderFlexibleBox::mainAxisOverflowForChild(RenderBox& child) const +EOverflow RenderFlexibleBox::mainAxisOverflowForChild(const RenderBox& child) const { if (isHorizontalFlow()) return child.style().overflowX(); diff --git a/Source/WebCore/rendering/RenderFlexibleBox.h b/Source/WebCore/rendering/RenderFlexibleBox.h index 9bae316aa..f2e5d1760 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.h +++ b/Source/WebCore/rendering/RenderFlexibleBox.h @@ -85,8 +85,8 @@ private: // Use an inline capacity of 8, since flexbox containers usually have less than 8 children. typedef Vector<LayoutRect, 8> ChildFrameRects; - virtual bool isFlexibleBox() const override final { return true; } - bool hasOrthogonalFlow(RenderBox& child) const; + bool isFlexibleBox() const final { return true; } + bool hasOrthogonalFlow(const RenderBox& child) const; bool isColumnFlow() const; bool isLeftToRightFlow() const; bool isMultiline() const; @@ -98,7 +98,7 @@ private: LayoutUnit mainAxisExtent() const; LayoutUnit crossAxisContentExtent() const; LayoutUnit mainAxisContentExtent(LayoutUnit contentLogicalHeight); - Optional<LayoutUnit> computeMainAxisExtentForChild(RenderBox& child, SizeType, const Length& size); + Optional<LayoutUnit> computeMainAxisExtentForChild(const RenderBox& child, SizeType, const Length& size); WritingMode transformedWritingMode() const; LayoutUnit flowAwareBorderStart() const; LayoutUnit flowAwareBorderEnd() const; @@ -122,7 +122,7 @@ private: LayoutUnit mainAxisBorderAndPaddingExtentForChild(RenderBox& child) const; LayoutUnit mainAxisScrollbarExtentForChild(RenderBox& child) const; LayoutUnit preferredMainAxisContentExtentForChild(RenderBox& child, bool hasInfiniteLineLength); - EOverflow mainAxisOverflowForChild(RenderBox&) const; + EOverflow mainAxisOverflowForChild(const RenderBox&) const; void layoutFlexItems(bool relayoutChildren, Vector<LineContext>&); LayoutUnit autoMarginOffsetInMainAxis(const OrderedFlexItemList&, LayoutUnit& availableFreeSpace); @@ -139,7 +139,8 @@ private: LayoutUnit computeChildMarginValue(const Length& margin); void prepareOrderIteratorAndMargins(); - LayoutUnit adjustChildSizeForMinAndMax(RenderBox&, LayoutUnit childSize); + LayoutUnit adjustChildSizeForMinAndMax(const RenderBox&, LayoutUnit childSize); + LayoutUnit adjustChildSizeForAspectRatioCrossAxisMinAndMax(const RenderBox&, LayoutUnit childSize); bool computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent, bool& hasInfiniteLineLength); bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength); @@ -158,9 +159,11 @@ private: void flipForRightToLeftColumn(); void flipForWrapReverse(const Vector<LineContext>&, LayoutUnit crossAxisStartEdge); - bool mainAxisExtentIsDefinite() const; - bool mainAxisLengthIsIndefinite(const Length& flexBasis) const; - + bool mainAxisLengthIsDefinite(const RenderBox&, const Length&) const; + bool crossAxisLengthIsDefinite(const RenderBox&, const Length&) const; + bool useChildAspectRatio(const RenderBox&) const; + Optional<LayoutUnit> computeMainSizeFromAspectRatioUsing(const RenderBox& child, Length crossSizeLength) const; + virtual bool isFlexibleBoxImpl() const { return false; }; mutable OrderIterator m_orderIterator; diff --git a/Source/WebCore/rendering/RenderHTMLCanvas.cpp b/Source/WebCore/rendering/RenderHTMLCanvas.cpp index f2de75d52..199f903b4 100644 --- a/Source/WebCore/rendering/RenderHTMLCanvas.cpp +++ b/Source/WebCore/rendering/RenderHTMLCanvas.cpp @@ -101,18 +101,7 @@ void RenderHTMLCanvas::canvasSizeChanged() if (!parent()) return; - - if (!preferredLogicalWidthsDirty()) - setPreferredLogicalWidthsDirty(true); - - LayoutSize oldSize = size(); - updateLogicalWidth(); - updateLogicalHeight(); - if (oldSize == size()) - return; - - if (!selfNeedsLayout()) - setNeedsLayout(); + setNeedsLayoutIfNeededAfterIntrinsicSizeChange(); } } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp index d8ee8150b..00d907829 100644 --- a/Source/WebCore/rendering/RenderImage.cpp +++ b/Source/WebCore/rendering/RenderImage.cpp @@ -294,29 +294,8 @@ void RenderImage::repaintOrMarkForLayout(ImageSizeChangeType imageSizeChange, co bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize || imageSizeChange != ImageSizeChangeNone; - if (imageSourceHasChangedSize) { - setPreferredLogicalWidthsDirty(true); - - // If the actual area occupied by the image has changed and it is not constrained by style then a layout is required. - bool imageSizeIsConstrained = style().logicalWidth().isSpecified() && style().logicalHeight().isSpecified(); - - // FIXME: We only need to recompute the containing block's preferred size - // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing). - // There's no easy way to detect that shrink-to-fit is needed, always force a layout. - bool containingBlockNeedsToRecomputePreferredSize = - style().logicalWidth().isPercentOrCalculated() - || style().logicalMaxWidth().isPercentOrCalculated() - || style().logicalMinWidth().isPercentOrCalculated(); - - bool layoutSizeDependsOnIntrinsicSize = style().aspectRatioType() == AspectRatioFromIntrinsic; - - if (!imageSizeIsConstrained || containingBlockNeedsToRecomputePreferredSize || layoutSizeDependsOnIntrinsicSize) { - // FIXME: It's not clear that triggering a layout guarantees a repaint in all cases. - // But many callers do depend on this code causing a layout. - setNeedsLayout(); - return; - } - } + if (imageSourceHasChangedSize && setNeedsLayoutIfNeededAfterIntrinsicSizeChange()) + return; if (everHadLayout() && !selfNeedsLayout()) { // The inner content rectangle is calculated during layout, but may need an update now @@ -574,6 +553,11 @@ bool RenderImage::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, ObjectFit objectFit = style().objectFit(); if (objectFit != ObjectFitFill && objectFit != ObjectFitCover) return false; + + LengthPoint objectPosition = style().objectPosition(); + if (objectPosition != RenderStyle::initialObjectPosition()) + return false; + // Check for image with alpha. return imageResource().cachedImage() && imageResource().cachedImage()->currentFrameKnownToBeOpaque(this); } diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 3125c62f6..749099044 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -1206,7 +1206,7 @@ LayoutRect RenderInline::linesVisualOverflowBoundingBoxInRegion(const RenderRegi LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const { // Only first-letter renderers are allowed in here during layout. They mutate the tree triggering repaints. - ASSERT(!view().layoutStateEnabled() || style().styleType() == FIRST_LETTER); + ASSERT(!view().layoutStateEnabled() || style().styleType() == FIRST_LETTER || hasSelfPaintingLayer()); if (!firstLineBoxIncludingCulling() && !continuation()) return LayoutRect(); @@ -1807,8 +1807,7 @@ void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) if (!container) container = this; - region.clip = region.bounds; - container->computeAbsoluteRepaintRect(region.clip); + region.clip = container->computeAbsoluteRepaintRect(region.bounds); if (region.clip.height() < 0) { region.clip.setHeight(0); region.clip.setWidth(0); diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index d0cba5316..dae97f749 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -1805,15 +1805,15 @@ void RenderLayer::beginTransparencyLayers(GraphicsContext& context, const LayerP context.clip(pixelSnappedClipRect); #if ENABLE(CSS_COMPOSITING) - // RenderSVGRoot takes care of its blend mode. - if (!renderer().isSVGRoot() && hasBlendMode()) + bool usesCompositeOperation = hasBlendMode() && !(renderer().isSVGRoot() && parent() && parent()->isRootLayer()); + if (usesCompositeOperation) context.setCompositeOperation(context.compositeOperation(), blendMode()); #endif context.beginTransparencyLayer(renderer().opacity()); #if ENABLE(CSS_COMPOSITING) - if (!renderer().isSVGRoot() && hasBlendMode()) + if (usesCompositeOperation) context.setCompositeOperation(context.compositeOperation(), BlendModeNormal); #endif @@ -6423,6 +6423,19 @@ void RenderLayer::repaintIncludingNonCompositingDescendants(RenderLayerModelObje } } +static bool mayCreateGraphicalGroup(const RenderElement& renderer) +{ + bool createsGraphicalGroup = renderer.hasClipPath() + || renderer.hasFilter() + || renderer.hasBackdropFilter() +#if ENABLE(CSS_COMPOSITING) + || renderer.hasBlendMode() +#endif + || renderer.isTransparent() + || renderer.hasMask(); + return createsGraphicalGroup || (renderer.style().willChange() && renderer.style().willChange()->canCreateGraphicalGroup()); +} + bool RenderLayer::shouldBeNormalFlowOnly() const { return (renderer().hasOverflowClip() @@ -6434,20 +6447,14 @@ bool RenderLayer::shouldBeNormalFlowOnly() const || renderer().isRenderIFrame() || (renderer().style().specifiesColumns() && !isRootLayer()) || renderer().isInFlowRenderFlowThread()) - && !renderer().isPositioned() && !renderer().hasTransformRelatedProperty() - && !renderer().hasClipPath() - && !renderer().hasFilter() - && !renderer().hasBackdropFilter() + && !renderer().isPositioned() + && !needsCompositedScrolling() + && !renderer().style().hasFlowFrom() #if PLATFORM(IOS) && !hasAcceleratedTouchScrolling() #endif -#if ENABLE(CSS_COMPOSITING) - && !renderer().hasBlendMode() -#endif - && !isTransparent() - && !needsCompositedScrolling() - && !renderer().style().hasFlowFrom(); + && !mayCreateGraphicalGroup(renderer()); } bool RenderLayer::shouldBeSelfPaintingLayer() const diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index edb4f3398..df2cd277d 100644 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -1924,8 +1924,7 @@ void RenderObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value()); region.type = styleRegion.type; - region.clip = region.bounds; - computeAbsoluteRepaintRect(region.clip); + region.clip = computeAbsoluteRepaintRect(region.bounds); if (region.clip.height() < 0) { region.clip.setHeight(0); region.clip.setWidth(0); diff --git a/Source/WebCore/rendering/RenderReplaced.cpp b/Source/WebCore/rendering/RenderReplaced.cpp index a818ad0fa..6b36b13e3 100644 --- a/Source/WebCore/rendering/RenderReplaced.cpp +++ b/Source/WebCore/rendering/RenderReplaced.cpp @@ -287,6 +287,31 @@ bool RenderReplaced::hasReplacedLogicalHeight() const return false; } +bool RenderReplaced::setNeedsLayoutIfNeededAfterIntrinsicSizeChange() +{ + setPreferredLogicalWidthsDirty(true); + + // If the actual area occupied by the image has changed and it is not constrained by style then a layout is required. + bool imageSizeIsConstrained = style().logicalWidth().isSpecified() && style().logicalHeight().isSpecified(); + + // FIXME: We only need to recompute the containing block's preferred size + // if the containing block's size depends on the image's size (i.e., the container uses shrink-to-fit sizing). + // There's no easy way to detect that shrink-to-fit is needed, always force a layout. + bool containingBlockNeedsToRecomputePreferredSize = + style().logicalWidth().isPercentOrCalculated() + || style().logicalMaxWidth().isPercentOrCalculated() + || style().logicalMinWidth().isPercentOrCalculated(); + + bool layoutSizeDependsOnIntrinsicSize = style().aspectRatioType() == AspectRatioFromIntrinsic; + + if (!imageSizeIsConstrained || containingBlockNeedsToRecomputePreferredSize || layoutSizeDependsOnIntrinsicSize) { + setNeedsLayout(); + return true; + } + + return false; +} + void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& constrainedSize, double& intrinsicRatio) const { FloatSize intrinsicSize; @@ -338,8 +363,6 @@ LayoutRect RenderReplaced::replacedContentRect(const LayoutSize& intrinsicSize) return contentRect; ObjectFit objectFit = style().objectFit(); - if (objectFit == ObjectFitFill) - return contentRect; LayoutRect finalRect = contentRect; switch (objectFit) { @@ -354,13 +377,14 @@ LayoutRect RenderReplaced::replacedContentRect(const LayoutSize& intrinsicSize) finalRect.setSize(intrinsicSize); break; case ObjectFitFill: - ASSERT_NOT_REACHED(); + break; } - // FIXME: This is where object-position should be taken into account, but since it's not - // implemented yet, assume the initial value of "50% 50%". - LayoutUnit xOffset = (contentRect.width() - finalRect.width()) / 2; - LayoutUnit yOffset = (contentRect.height() - finalRect.height()) / 2; + LengthPoint objectPosition = style().objectPosition(); + + LayoutUnit xOffset = minimumValueForLength(objectPosition.x(), contentRect.width() - finalRect.width()); + LayoutUnit yOffset = minimumValueForLength(objectPosition.y(), contentRect.height() - finalRect.height()); + finalRect.move(xOffset, yOffset); return finalRect; diff --git a/Source/WebCore/rendering/RenderReplaced.h b/Source/WebCore/rendering/RenderReplaced.h index 9f7dfc571..72dbb81d1 100644 --- a/Source/WebCore/rendering/RenderReplaced.h +++ b/Source/WebCore/rendering/RenderReplaced.h @@ -37,6 +37,7 @@ public: bool hasReplacedLogicalWidth() const; bool hasReplacedLogicalHeight() const; + bool setNeedsLayoutIfNeededAfterIntrinsicSizeChange(); protected: RenderReplaced(Element&, Ref<RenderStyle>&&); diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp index 05325314a..b3be2de98 100644 --- a/Source/WebCore/rendering/RenderTable.cpp +++ b/Source/WebCore/rendering/RenderTable.cpp @@ -300,6 +300,13 @@ void RenderTable::updateLogicalWidth() // Ensure we aren't bigger than our available width. setLogicalWidth(std::min(availableContentLogicalWidth, maxPreferredLogicalWidth())); + LayoutUnit maxWidth = maxPreferredLogicalWidth(); + // scaledWidthFromPercentColumns depends on m_layoutStruct in TableLayoutAlgorithmAuto, which + // maxPreferredLogicalWidth fills in. So scaledWidthFromPercentColumns has to be called after + // maxPreferredLogicalWidth. + LayoutUnit scaledWidth = m_tableLayout->scaledWidthFromPercentColumns() + bordersPaddingAndSpacingInRowDirection(); + maxWidth = std::max(scaledWidth, maxWidth); + setLogicalWidth(std::min(availableContentLogicalWidth, maxWidth)); } // Ensure we aren't smaller than our min preferred width. diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp index efd90c18c..35e5e0b88 100644 --- a/Source/WebCore/rendering/RenderTableCell.cpp +++ b/Source/WebCore/rendering/RenderTableCell.cpp @@ -404,6 +404,13 @@ LayoutUnit RenderTableCell::cellBaselinePosition() const return firstLineBaseline().valueOr(borderAndPaddingBefore() + contentLogicalHeight()); } +static inline void markCellDirtyWhenCollapsedBorderChanges(RenderTableCell* cell) +{ + if (!cell) + return; + cell->setNeedsLayoutAndPrefWidthsRecalc(); +} + void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { ASSERT(style().display() == TABLE_CELL); @@ -422,8 +429,15 @@ void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* ol // If border was changed, notify table. RenderTable* table = this->table(); - if (table && oldStyle && oldStyle->border() != style().border()) + if (table && oldStyle && oldStyle->border() != style().border()) { table->invalidateCollapsedBorders(this); + if (table->collapseBorders() && diff == StyleDifferenceLayout) { + markCellDirtyWhenCollapsedBorderChanges(table->cellBelow(this)); + markCellDirtyWhenCollapsedBorderChanges(table->cellAbove(this)); + markCellDirtyWhenCollapsedBorderChanges(table->cellBefore(this)); + markCellDirtyWhenCollapsedBorderChanges(table->cellAfter(this)); + } + } } // The following rules apply for resolving conflicts and figuring out which border diff --git a/Source/WebCore/rendering/RenderTableCell.h b/Source/WebCore/rendering/RenderTableCell.h index bd69f09e3..17a0171a0 100644 --- a/Source/WebCore/rendering/RenderTableCell.h +++ b/Source/WebCore/rendering/RenderTableCell.h @@ -284,6 +284,8 @@ inline LayoutUnit RenderTableCell::logicalHeightForRowSizing() const { // FIXME: This function does too much work, and is very hot during table layout! LayoutUnit adjustedLogicalHeight = logicalHeight() - (intrinsicPaddingBefore() + intrinsicPaddingAfter()); + if (!style().logicalHeight().isSpecified()) + return adjustedLogicalHeight; LayoutUnit styleLogicalHeight = valueForLength(style().logicalHeight(), 0); // In strict mode, box-sizing: content-box do the right thing and actually add in the border and padding. // Call computedCSSPadding* directly to avoid including implicitPadding. diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index 1907657e9..7f9100b6e 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -251,6 +251,15 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) cell->setCol(table()->effColToCol(col)); } +static LayoutUnit resolveLogicalHeightForRow(const Length& rowLogicalHeight) +{ + if (rowLogicalHeight.isFixed()) + return rowLogicalHeight.value(); + if (rowLogicalHeight.isCalculated()) + return rowLogicalHeight.nonNanCalculatedValue(0); + return 0; +} + LayoutUnit RenderTableSection::calcRowLogicalHeight() { #ifndef NDEBUG @@ -278,7 +287,7 @@ LayoutUnit RenderTableSection::calcRowLogicalHeight() LayoutUnit baselineDescent = 0; // Our base size is the biggest logical height from our cells' styles (excluding row spanning cells). - m_rowPos[r + 1] = std::max(m_rowPos[r] + minimumValueForLength(m_grid[r].logicalHeight, 0), LayoutUnit::fromPixel(0)); + m_rowPos[r + 1] = std::max(m_rowPos[r] + resolveLogicalHeightForRow(m_grid[r].logicalHeight), LayoutUnit::fromPixel(0)); Row& row = m_grid[r].row; unsigned totalCols = row.size(); @@ -372,6 +381,7 @@ void RenderTableSection::layout() ASSERT(!needsCellRecalc()); ASSERT(!table()->needsSectionRecalc()); + m_forceSlowPaintPathWithOverflowingCell = false; // addChild may over-grow m_grid but we don't want to throw away the memory too early as addChild // can be called in a loop (e.g during parsing). Doing it now ensures we have a stable-enough structure. m_grid.shrinkToFit(); diff --git a/Source/WebCore/rendering/TableLayout.h b/Source/WebCore/rendering/TableLayout.h index 23169aa65..6c0b32d24 100644 --- a/Source/WebCore/rendering/TableLayout.h +++ b/Source/WebCore/rendering/TableLayout.h @@ -21,6 +21,7 @@ #ifndef TableLayout_h #define TableLayout_h +#include "LayoutUnit.h" #include <wtf/FastMalloc.h> #include <wtf/Noncopyable.h> @@ -39,6 +40,7 @@ public: virtual ~TableLayout() { } virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) = 0; + virtual LayoutUnit scaledWidthFromPercentColumns() const { return LayoutUnit(0); } virtual void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const = 0; virtual void layout() = 0; diff --git a/Source/WebCore/rendering/line/BreakingContext.h b/Source/WebCore/rendering/line/BreakingContext.h index c1f947689..799d2c063 100644 --- a/Source/WebCore/rendering/line/BreakingContext.h +++ b/Source/WebCore/rendering/line/BreakingContext.h @@ -559,9 +559,9 @@ inline void BreakingContext::handleReplaced() m_ignoringSpaces = true; } if (downcast<RenderListMarker>(*m_current.renderer()).isInside()) - m_width.addUncommittedReplacedWidth(replacedLogicalWidth); + m_width.addUncommittedWidth(replacedLogicalWidth); } else - m_width.addUncommittedReplacedWidth(replacedLogicalWidth); + m_width.addUncommittedWidth(replacedLogicalWidth); if (is<RenderRubyRun>(*m_current.renderer())) { m_width.applyOverhang(downcast<RenderRubyRun>(m_current.renderer()), m_lastObject, m_nextObject); downcast<RenderRubyRun>(m_current.renderer())->updatePriorContextFromCachedBreakIterator(m_renderTextInfo.lineBreakIterator); @@ -747,7 +747,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool float charWidth = 0; bool breakNBSP = m_autoWrap && m_currentStyle->nbspMode() == SPACE; // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word, - // which is only possible if the word is the first thing on the line, that is, if |w| is zero. + // which is only possible if the word is the first thing on the line. bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.hasCommitted()) || m_currWS == PRE); bool midWordBreak = false; bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap; diff --git a/Source/WebCore/rendering/line/LineWidth.cpp b/Source/WebCore/rendering/line/LineWidth.cpp index f3b12b3ef..71e05cb23 100644 --- a/Source/WebCore/rendering/line/LineWidth.cpp +++ b/Source/WebCore/rendering/line/LineWidth.cpp @@ -37,14 +37,6 @@ namespace WebCore { LineWidth::LineWidth(RenderBlockFlow& block, bool isFirstLine, IndentTextOrNot shouldIndentText) : m_block(block) - , m_uncommittedWidth(0) - , m_committedWidth(0) - , m_overhangWidth(0) - , m_trailingWhitespaceWidth(0) - , m_trailingCollapsedWhitespaceWidth(0) - , m_left(0) - , m_right(0) - , m_availableWidth(0) , m_isFirstLine(isFirstLine) , m_shouldIndentText(shouldIndentText) { @@ -136,10 +128,7 @@ void LineWidth::commit() { m_committedWidth += m_uncommittedWidth; m_uncommittedWidth = 0; - if (m_hasUncommittedReplaced) { - m_hasCommittedReplaced = true; - m_hasUncommittedReplaced = false; - } + m_hasCommitted = true; } void LineWidth::applyOverhang(RenderRubyRun* rubyRun, RenderObject* startRenderer, RenderObject* endRenderer) diff --git a/Source/WebCore/rendering/line/LineWidth.h b/Source/WebCore/rendering/line/LineWidth.h index 949d2c392..370b3a0f8 100644 --- a/Source/WebCore/rendering/line/LineWidth.h +++ b/Source/WebCore/rendering/line/LineWidth.h @@ -59,7 +59,7 @@ public: float availableWidth() const { return m_availableWidth; } float logicalLeftOffset() const { return m_left; } - bool hasCommitted() const { return m_committedWidth > 0 || m_hasCommittedReplaced; } + bool hasCommitted() const { return m_hasCommitted; } void updateAvailableWidth(LayoutUnit minimumHeight = 0); void shrinkAvailableWidthForNewFloatIfNeeded(const FloatingObject&); @@ -67,11 +67,6 @@ public: { m_uncommittedWidth += delta; } - void addUncommittedReplacedWidth(float delta) - { - addUncommittedWidth(delta); - m_hasUncommittedReplaced = true; - } void commit(); void applyOverhang(RenderRubyRun*, RenderObject* startRenderer, RenderObject* endRenderer); void fitBelowFloats(bool isFirstLine = false); @@ -87,17 +82,16 @@ private: #endif RenderBlockFlow& m_block; - float m_uncommittedWidth; - float m_committedWidth; - float m_overhangWidth; // The amount by which |m_availableWidth| has been inflated to account for possible contraction due to ruby overhang. - float m_trailingWhitespaceWidth; - float m_trailingCollapsedWhitespaceWidth; - float m_left; - float m_right; - float m_availableWidth; - bool m_isFirstLine; - bool m_hasUncommittedReplaced { false }; - bool m_hasCommittedReplaced { false }; + float m_uncommittedWidth { 0 }; + float m_committedWidth { 0 }; + float m_overhangWidth { 0 }; // The amount by which |m_availableWidth| has been inflated to account for possible contraction due to ruby overhang. + float m_trailingWhitespaceWidth { 0 }; + float m_trailingCollapsedWhitespaceWidth { 0 }; + float m_left { 0 }; + float m_right { 0 }; + float m_availableWidth { 0 }; + bool m_isFirstLine { true }; + bool m_hasCommitted { false }; IndentTextOrNot m_shouldIndentText; }; diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp index ebd4c9142..39c43ee15 100644 --- a/Source/WebCore/rendering/style/RenderStyle.cpp +++ b/Source/WebCore/rendering/style/RenderStyle.cpp @@ -811,6 +811,7 @@ bool RenderStyle::changeRequiresRepaint(const RenderStyle& other, unsigned& chan || rareNonInheritedData->userDrag != other.rareNonInheritedData->userDrag || rareNonInheritedData->m_borderFit != other.rareNonInheritedData->m_borderFit || rareNonInheritedData->m_objectFit != other.rareNonInheritedData->m_objectFit + || rareNonInheritedData->m_objectPosition != other.rareNonInheritedData->m_objectPosition || rareInheritedData->m_imageRendering != other.rareInheritedData->m_imageRendering) return true; diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index 559df8182..7f84a0754 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -40,6 +40,7 @@ #include "Length.h" #include "LengthBox.h" #include "LengthFunctions.h" +#include "LengthPoint.h" #include "LengthSize.h" #include "LineClampValue.h" #include "NinePieceImage.h" @@ -1035,8 +1036,9 @@ public: TextOrientation textOrientation() const { return static_cast<TextOrientation>(rareInheritedData->m_textOrientation); } ObjectFit objectFit() const { return static_cast<ObjectFit>(rareNonInheritedData->m_objectFit); } - - // Return true if any transform related property (currently transform, transformStyle3D or perspective) + LengthPoint objectPosition() const { return rareNonInheritedData->m_objectPosition; } + + // Return true if any transform related property (currently transform, transformStyle3D or perspective) // indicates that we are transforming bool hasTransformRelatedProperty() const { return hasTransform() || preserves3D() || hasPerspective(); } @@ -1606,6 +1608,7 @@ public: bool setTextOrientation(TextOrientation); void setObjectFit(ObjectFit fit) { SET_VAR(rareNonInheritedData, m_objectFit, fit); } + void setObjectPosition(const LengthPoint& position) { SET_VAR(rareNonInheritedData, m_objectPosition, position); } void setRubyPosition(RubyPosition position) { SET_VAR(rareInheritedData, m_rubyPosition, position); } @@ -1896,6 +1899,7 @@ public: static TextOrientation initialTextOrientation() { return TextOrientation:: Mixed; } static ObjectFit initialObjectFit() { return ObjectFitFill; } + static LengthPoint initialObjectPosition() { return LengthPoint(Length(50.0f, Percent), Length(50.0f, Percent)); } static EEmptyCell initialEmptyCells() { return SHOW; } static EListStylePosition initialListStylePosition() { return OUTSIDE; } static EListStyleType initialListStyleType() { return Disc; } diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp index 24ae59cf2..120bd5f5a 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp @@ -63,6 +63,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() #endif , m_willChange(RenderStyle::initialWillChange()) , m_mask(FillLayer(MaskFillLayer)) + , m_objectPosition(RenderStyle::initialObjectPosition()) #if ENABLE(CSS_SHAPES) , m_shapeOutside(RenderStyle::initialShapeOutside()) , m_shapeMargin(RenderStyle::initialShapeMargin()) @@ -149,6 +150,7 @@ inline StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonIn , m_mask(o.m_mask) , m_maskBoxImage(o.m_maskBoxImage) , m_pageSize(o.m_pageSize) + , m_objectPosition(o.m_objectPosition) #if ENABLE(CSS_SHAPES) , m_shapeOutside(o.m_shapeOutside) , m_shapeMargin(o.m_shapeMargin) @@ -253,6 +255,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_mask == o.m_mask && m_maskBoxImage == o.m_maskBoxImage && m_pageSize == o.m_pageSize + && m_objectPosition == o.m_objectPosition #if ENABLE(CSS_SHAPES) && arePointingToEqualData(m_shapeOutside, o.m_shapeOutside) && m_shapeMargin == o.m_shapeMargin diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h index 9b1b2ad53..069b92878 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -32,6 +32,7 @@ #include "CursorData.h" #include "DataRef.h" #include "FillLayer.h" +#include "LengthPoint.h" #include "LineClampValue.h" #include "NinePieceImage.h" #include "ShapeValue.h" @@ -154,6 +155,7 @@ public: NinePieceImage m_maskBoxImage; LengthSize m_pageSize; + LengthPoint m_objectPosition; #if ENABLE(CSS_SHAPES) RefPtr<ShapeValue> m_shapeOutside; diff --git a/Source/WebCore/rendering/style/StyleScrollSnapPoints.cpp b/Source/WebCore/rendering/style/StyleScrollSnapPoints.cpp index 8d8858f84..854c3e25f 100644 --- a/Source/WebCore/rendering/style/StyleScrollSnapPoints.cpp +++ b/Source/WebCore/rendering/style/StyleScrollSnapPoints.cpp @@ -31,8 +31,8 @@ namespace WebCore { ScrollSnapPoints::ScrollSnapPoints() - : repeatOffset(100, Percent) - , hasRepeat(true) + : repeatOffset(0, Fixed) + , hasRepeat(false) , usesElements(false) { } diff --git a/Source/WebCore/rendering/style/WillChangeData.cpp b/Source/WebCore/rendering/style/WillChangeData.cpp index 77d4aa871..cff2e7cd3 100644 --- a/Source/WebCore/rendering/style/WillChangeData.cpp +++ b/Source/WebCore/rendering/style/WillChangeData.cpp @@ -99,6 +99,30 @@ static bool propertyCreatesStackingContext(CSSPropertyID property) } } +static bool propertyCreatesGraphicalGroup(CSSPropertyID property) +{ + switch (property) { + case CSSPropertyClipPath: + case CSSPropertyWebkitClipPath: + case CSSPropertyMask: + case CSSPropertyOpacity: +#if ENABLE(CSS_COMPOSITING) + case CSSPropertyMixBlendMode: + case CSSPropertyIsolation: +#endif + case CSSPropertyFilter: +#if ENABLE(FILTERS_LEVEL_2) + case CSSPropertyWebkitBackdropFilter: +#endif + case CSSPropertyWebkitMask: + case CSSPropertyWebkitMaskImage: + case CSSPropertyWebkitMaskBoxImage: + return true; + default: + return false; + } +} + static bool propertyTriggersCompositing(CSSPropertyID property) { switch (property) { @@ -137,6 +161,8 @@ void WillChangeData::addFeature(Feature feature, CSSPropertyID propertyID) m_canTriggerCompositingOnInline |= propertyTriggersCompositing(propertyID); m_canTriggerCompositing |= m_canTriggerCompositingOnInline | propertyTriggersCompositingOnBoxesOnly(propertyID); + + m_canCreateGraphicalGroup |= propertyCreatesGraphicalGroup(propertyID); } WillChangeData::FeaturePropertyPair WillChangeData::featureAt(size_t index) const diff --git a/Source/WebCore/rendering/style/WillChangeData.h b/Source/WebCore/rendering/style/WillChangeData.h index 49e76089d..6bab28da6 100644 --- a/Source/WebCore/rendering/style/WillChangeData.h +++ b/Source/WebCore/rendering/style/WillChangeData.h @@ -57,6 +57,7 @@ public: bool canCreateStackingContext() const { return m_canCreateStackingContext; } bool canTriggerCompositing() const { return m_canTriggerCompositing; } bool canTriggerCompositingOnInline() const { return m_canTriggerCompositingOnInline; } + bool canCreateGraphicalGroup() const { return m_canCreateGraphicalGroup; } enum Feature { ScrollPosition, @@ -124,6 +125,7 @@ private: bool m_canCreateStackingContext { false }; bool m_canTriggerCompositing { false }; bool m_canTriggerCompositingOnInline { false }; + bool m_canCreateGraphicalGroup { false }; }; diff --git a/Source/WebCore/svg/SVGLengthContext.cpp b/Source/WebCore/svg/SVGLengthContext.cpp index fe4b66994..1bd857b9d 100644 --- a/Source/WebCore/svg/SVGLengthContext.cpp +++ b/Source/WebCore/svg/SVGLengthContext.cpp @@ -91,7 +91,7 @@ float SVGLengthContext::valueForLength(const Length& length, SVGLengthMode mode) { if (length.isPercent()) return convertValueFromPercentageToUserUnits(length.value() / 100, mode, IGNORE_EXCEPTION); - if (length.isAuto()) + if (length.isAuto() || !length.isSpecified()) return 0; FloatSize viewportSize; diff --git a/Source/WebCore/svg/SVGSVGElement.cpp b/Source/WebCore/svg/SVGSVGElement.cpp index e5fbd7465..7990139b3 100644 --- a/Source/WebCore/svg/SVGSVGElement.cpp +++ b/Source/WebCore/svg/SVGSVGElement.cpp @@ -64,7 +64,7 @@ inline SVGSVGElement::SVGSVGElement(const QualifiedName& tagName, Document& docu , m_y(LengthModeHeight) , m_width(LengthModeWidth, ASCIILiteral("100%")) , m_height(LengthModeHeight, ASCIILiteral("100%")) - , m_timeContainer(RefPtr<SMILTimeContainer>(SMILTimeContainer::create(this)).releaseNonNull()) + , m_timeContainer(SMILTimeContainer::create(this)) { ASSERT(hasTagName(SVGNames::svgTag)); registerAnimatedPropertiesForSVGSVGElement(); diff --git a/Source/WebCore/svg/animation/SMILTime.h b/Source/WebCore/svg/animation/SMILTime.h index 60d1301a0..3047d97af 100644 --- a/Source/WebCore/svg/animation/SMILTime.h +++ b/Source/WebCore/svg/animation/SMILTime.h @@ -31,6 +31,8 @@ namespace WebCore { +const double SMILAnimationFrameDelay = 1.0 / 60; + class SMILTime { public: SMILTime() : m_time(0) { } diff --git a/Source/WebCore/svg/animation/SMILTimeContainer.cpp b/Source/WebCore/svg/animation/SMILTimeContainer.cpp index 57d9c7f7f..cbf3b7ba5 100644 --- a/Source/WebCore/svg/animation/SMILTimeContainer.cpp +++ b/Source/WebCore/svg/animation/SMILTimeContainer.cpp @@ -35,8 +35,6 @@ namespace WebCore { -static const double animationFrameDelay = 0.025; - SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner) : m_beginTime(0) , m_pauseTime(0) @@ -100,7 +98,7 @@ void SMILTimeContainer::notifyIntervalsChanged() { // Schedule updateAnimations() to be called asynchronously so multiple intervals // can change with updateAnimations() only called once at the end. - startTimer(0); + startTimer(elapsed(), 0); } SMILTime SMILTimeContainer::elapsed() const @@ -161,7 +159,7 @@ void SMILTimeContainer::resume() m_resumeTime = monotonicallyIncreasingTime(); m_pauseTime = 0; - startTimer(0); + startTimer(elapsed(), 0); } void SMILTimeContainer::setElapsed(SMILTime time) @@ -198,7 +196,7 @@ void SMILTimeContainer::setElapsed(SMILTime time) updateAnimations(time, true); } -void SMILTimeContainer::startTimer(SMILTime fireTime, SMILTime minimumDelay) +void SMILTimeContainer::startTimer(SMILTime elapsed, SMILTime fireTime, SMILTime minimumDelay) { if (!m_beginTime || isPaused()) return; @@ -206,7 +204,7 @@ void SMILTimeContainer::startTimer(SMILTime fireTime, SMILTime minimumDelay) if (!fireTime.isFinite()) return; - SMILTime delay = std::max(fireTime - elapsed(), minimumDelay); + SMILTime delay = std::max(fireTime - elapsed, minimumDelay); m_timer.startOneShot(delay.value()); } @@ -309,7 +307,7 @@ void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) #ifndef NDEBUG m_preventScheduledAnimationsChanges = false; #endif - startTimer(earliestFireTime, animationFrameDelay); + startTimer(elapsed, earliestFireTime, SMILAnimationFrameDelay); return; } @@ -321,7 +319,7 @@ void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) m_preventScheduledAnimationsChanges = false; #endif - startTimer(earliestFireTime, animationFrameDelay); + startTimer(elapsed, earliestFireTime, SMILAnimationFrameDelay); } } diff --git a/Source/WebCore/svg/animation/SMILTimeContainer.h b/Source/WebCore/svg/animation/SMILTimeContainer.h index d2856027a..ae4cba4d9 100644 --- a/Source/WebCore/svg/animation/SMILTimeContainer.h +++ b/Source/WebCore/svg/animation/SMILTimeContainer.h @@ -67,7 +67,7 @@ private: SMILTimeContainer(SVGSVGElement* owner); void timerFired(); - void startTimer(SMILTime fireTime, SMILTime minimumDelay = 0); + void startTimer(SMILTime elapsed, SMILTime fireTime, SMILTime minimumDelay = 0); void updateAnimations(SMILTime elapsed, bool seekToTime = false); void updateDocumentOrderIndexes(); diff --git a/Source/WebCore/svg/animation/SVGSMILElement.cpp b/Source/WebCore/svg/animation/SVGSMILElement.cpp index 4410b5bd3..f75f945a5 100644 --- a/Source/WebCore/svg/animation/SVGSMILElement.cpp +++ b/Source/WebCore/svg/animation/SVGSMILElement.cpp @@ -1042,7 +1042,7 @@ SMILTime SVGSMILElement::calculateNextProgressTime(SMILTime elapsed) const return repeatingDurationEnd; return m_intervalEnd; } - return elapsed + 0.025; + return elapsed + SMILAnimationFrameDelay; } return m_intervalBegin >= elapsed ? m_intervalBegin : SMILTime::unresolved(); } diff --git a/Source/WebCore/workers/WorkerGlobalScope.idl b/Source/WebCore/workers/WorkerGlobalScope.idl index e12d26514..2a703764c 100644 --- a/Source/WebCore/workers/WorkerGlobalScope.idl +++ b/Source/WebCore/workers/WorkerGlobalScope.idl @@ -33,9 +33,9 @@ ] interface WorkerGlobalScope : EventTarget { #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT - [Replaceable] readonly attribute WorkerGlobalScope self; + readonly attribute WorkerGlobalScope self; #endif - [Replaceable] readonly attribute WorkerLocation location; + readonly attribute WorkerLocation location; void close(); attribute EventHandler onerror; @@ -45,7 +45,7 @@ // WorkerUtils [Custom] void importScripts(/*[Variadic] DOMString urls */); - [Replaceable] readonly attribute WorkerNavigator navigator; + readonly attribute WorkerNavigator navigator; // Additional constructors |