зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to central, a=merge
MozReview-Commit-ID: Ano2O7fFKEW
This commit is contained in:
Коммит
8a82c900f8
|
@ -184,6 +184,12 @@ mobile/android/modules/HomeProvider.jsm
|
|||
# Uses `#filter substitution`
|
||||
services/sync/modules/constants.js
|
||||
|
||||
# Third party services
|
||||
services/sync/tps/extensions/mozmill/resource/stdlib/json2.js
|
||||
services/common/kinto-http-client.js
|
||||
services/common/kinto-offline-client.js
|
||||
services/sync/tps/extensions/mozmill
|
||||
|
||||
# toolkit/ exclusions
|
||||
|
||||
# Not part of the default build
|
||||
|
|
|
@ -85,15 +85,15 @@
|
|||
#else
|
||||
<vbox>
|
||||
#endif
|
||||
<label accesskey="&overridePageColors.accesskey;"
|
||||
control="useDocumentColors">&overridePageColors.label;</label>
|
||||
<label accesskey="&overrideDefaultPageColors.accesskey;"
|
||||
control="useDocumentColors">&overrideDefaultPageColors.label;</label>
|
||||
<menulist id="useDocumentColors" preference="browser.display.document_color_use">
|
||||
<menupopup>
|
||||
<menuitem label="&overridePageColors.always.label;"
|
||||
<menuitem label="&overrideDefaultPageColors.always.label;"
|
||||
value="2" id="documentColorAlways"/>
|
||||
<menuitem label="&overridePageColors.auto.label;"
|
||||
<menuitem label="&overrideDefaultPageColors.auto.label;"
|
||||
value="0" id="documentColorAutomatic"/>
|
||||
<menuitem label="&overridePageColors.never.label;"
|
||||
<menuitem label="&overrideDefaultPageColors.never.label;"
|
||||
value="1" id="documentColorNever"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
|
|
|
@ -238,7 +238,7 @@
|
|||
<separator class="groove"/>
|
||||
<hbox>
|
||||
<checkbox id="useDocumentFonts"
|
||||
label="&allowPagesToUse.label;" accesskey="&allowPagesToUse.accesskey;"
|
||||
label="&allowPagesToUseOwn.label;" accesskey="&allowPagesToUseOwn.accesskey;"
|
||||
preference="browser.display.use_document_fonts"
|
||||
onsyncfrompreference="return gFontsDialog.readUseDocumentFonts();"
|
||||
onsynctopreference="return gFontsDialog.writeUseDocumentFonts();"/>
|
||||
|
|
|
@ -167,12 +167,12 @@
|
|||
accesskey="&useCursorNavigation.accesskey;"
|
||||
preference="accessibility.browsewithcaret"/>
|
||||
<checkbox id="searchStartTyping"
|
||||
label="&searchStartTyping.label;"
|
||||
accesskey="&searchStartTyping.accesskey;"
|
||||
label="&searchOnStartTyping.label;"
|
||||
accesskey="&searchOnStartTyping.accesskey;"
|
||||
preference="accessibility.typeaheadfind"/>
|
||||
<checkbox id="blockAutoRefresh"
|
||||
label="&blockAutoRefresh.label;"
|
||||
accesskey="&blockAutoRefresh.accesskey;"
|
||||
label="&blockAutoReload.label;"
|
||||
accesskey="&blockAutoReload.accesskey;"
|
||||
preference="accessibility.blockautorefresh"/>
|
||||
</groupbox>
|
||||
<!-- Browsing -->
|
||||
|
@ -192,8 +192,8 @@
|
|||
accesskey="&allowHWAccel.accesskey;"
|
||||
preference="layers.acceleration.disabled"/>
|
||||
<checkbox id="checkSpelling"
|
||||
label="&checkSpelling.label;"
|
||||
accesskey="&checkSpelling.accesskey;"
|
||||
label="&checkUserSpelling.label;"
|
||||
accesskey="&checkUserSpelling.accesskey;"
|
||||
onsyncfrompreference="return gAdvancedPane.readCheckSpelling();"
|
||||
onsynctopreference="return gAdvancedPane.writeCheckSpelling();"
|
||||
preference="layout.spellcheckDefault"/>
|
||||
|
@ -301,13 +301,13 @@
|
|||
</hbox>
|
||||
<hbox align="center">
|
||||
<checkbox id="offlineNotify"
|
||||
label="&offlineNotify.label;" accesskey="&offlineNotify.accesskey;"
|
||||
label="&offlineStorageNotify.label;" accesskey="&offlineStorageNotify.accesskey;"
|
||||
preference="browser.offline-apps.notify"
|
||||
onsyncfrompreference="return gAdvancedPane.readOfflineNotify();"/>
|
||||
<spacer flex="1"/>
|
||||
<button id="offlineNotifyExceptions"
|
||||
label="&offlineNotifyExceptions.label;"
|
||||
accesskey="&offlineNotifyExceptions.accesskey;"/>
|
||||
label="&offlineStorageNotifyExceptions.label;"
|
||||
accesskey="&offlineStorageNotifyExceptions.accesskey;"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<vbox flex="1">
|
||||
|
@ -354,8 +354,8 @@
|
|||
label="&updateAuto1.label;"
|
||||
accesskey="&updateAuto1.accesskey;"/>
|
||||
<radio value="checkOnly"
|
||||
label="&updateCheck.label;"
|
||||
accesskey="&updateCheck.accesskey;"/>
|
||||
label="&updateCheckChoose.label;"
|
||||
accesskey="&updateCheckChoose.accesskey;"/>
|
||||
<radio value="manual"
|
||||
label="&updateManual.label;"
|
||||
accesskey="&updateManual.accesskey;"/>
|
||||
|
@ -388,8 +388,8 @@
|
|||
<!-- Certificates -->
|
||||
<tabpanel id="encryptionPanel" orient="vertical">
|
||||
<groupbox id="certSelection" align="start">
|
||||
<caption><label>&certSelection.label;</label></caption>
|
||||
<description id="CertSelectionDesc" control="certSelection">&certSelection.description;</description>
|
||||
<caption><label>&certPersonal.label;</label></caption>
|
||||
<description id="CertSelectionDesc" control="certSelection">&certPersonal.description;</description>
|
||||
|
||||
<!--
|
||||
The values on these radio buttons may look like l12y issues, but
|
||||
|
@ -400,11 +400,11 @@
|
|||
preftype="string"
|
||||
preference="security.default_personal_cert"
|
||||
aria-labelledby="CertSelectionDesc">
|
||||
<radio label="&certs.auto;"
|
||||
accesskey="&certs.auto.accesskey;"
|
||||
<radio label="&selectCerts.auto;"
|
||||
accesskey="&selectCerts.auto.accesskey;"
|
||||
value="Select Automatically"/>
|
||||
<radio label="&certs.ask;"
|
||||
accesskey="&certs.ask.accesskey;"
|
||||
<radio label="&selectCerts.ask;"
|
||||
accesskey="&selectCerts.ask.accesskey;"
|
||||
value="Ask Every Time"/>
|
||||
</radiogroup>
|
||||
</groupbox>
|
||||
|
|
|
@ -172,13 +172,13 @@
|
|||
class="content-cell-item"
|
||||
preference="browser.startup.page">
|
||||
<menupopup>
|
||||
<menuitem label="&startupHomePage.label;"
|
||||
<menuitem label="&startupUserHomePage.label;"
|
||||
value="1"
|
||||
id="browserStartupHomePage"/>
|
||||
<menuitem label="&startupBlankPage.label;"
|
||||
value="0"
|
||||
id="browserStartupBlank"/>
|
||||
<menuitem label="&startupLastSession.label;"
|
||||
<menuitem label="&startupPrevSession.label;"
|
||||
value="3"
|
||||
id="browserStartupLastSession"/>
|
||||
</menupopup>
|
||||
|
@ -260,8 +260,8 @@
|
|||
<hbox>
|
||||
<radio id="alwaysAsk"
|
||||
value="false"
|
||||
label="&alwaysAsk.label;"
|
||||
accesskey="&alwaysAsk.accesskey;"/>
|
||||
label="&alwaysAskWhere.label;"
|
||||
accesskey="&alwaysAskWhere.accesskey;"/>
|
||||
</hbox>
|
||||
</radiogroup>
|
||||
</groupbox>
|
||||
|
@ -281,16 +281,16 @@
|
|||
onsyncfrompreference="return gMainPane.readLinkTarget();"
|
||||
onsynctopreference="return gMainPane.writeLinkTarget();"/>
|
||||
|
||||
<checkbox id="warnCloseMultiple" label="&warnCloseMultipleTabs.label;"
|
||||
accesskey="&warnCloseMultipleTabs.accesskey;"
|
||||
<checkbox id="warnCloseMultiple" label="&warnOnCloseMultipleTabs.label;"
|
||||
accesskey="&warnOnCloseMultipleTabs.accesskey;"
|
||||
preference="browser.tabs.warnOnClose"/>
|
||||
|
||||
<checkbox id="warnOpenMany" label="&warnOpenManyTabs.label;"
|
||||
accesskey="&warnOpenManyTabs.accesskey;"
|
||||
<checkbox id="warnOpenMany" label="&warnOnOpenManyTabs.label;"
|
||||
accesskey="&warnOnOpenManyTabs.accesskey;"
|
||||
preference="browser.tabs.warnOnOpen"/>
|
||||
|
||||
<checkbox id="switchToNewTabs" label="&switchToNewTabs.label;"
|
||||
accesskey="&switchToNewTabs.accesskey;"
|
||||
<checkbox id="switchToNewTabs" label="&switchLinksToNewTabs.label;"
|
||||
accesskey="&switchLinksToNewTabs.accesskey;"
|
||||
preference="browser.tabs.loadInBackground"/>
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
|
|
@ -62,8 +62,8 @@
|
|||
|
||||
<hbox id="addonInstallBox">
|
||||
<checkbox id="warnAddonInstall"
|
||||
label="&warnAddonInstall.label;"
|
||||
accesskey="&warnAddonInstall.accesskey;"
|
||||
label="&warnOnAddonInstall.label;"
|
||||
accesskey="&warnOnAddonInstall.accesskey;"
|
||||
preference="xpinstall.whitelist.required"
|
||||
onsyncfrompreference="return gSecurityPane.readWarnAddonInstall();"/>
|
||||
<spacer flex="1"/>
|
||||
|
@ -82,8 +82,8 @@
|
|||
label="&blockDownloads.label;"
|
||||
accesskey="&blockDownloads.accesskey;" />
|
||||
<checkbox id="blockUncommonUnwanted"
|
||||
label="&blockUncommonUnwanted.label;"
|
||||
accesskey="&blockUncommonUnwanted.accesskey;" />
|
||||
label="&blockUncommonAndUnwanted.label;"
|
||||
accesskey="&blockUncommonAndUnwanted.accesskey;" />
|
||||
</vbox>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
|
||||
<!ENTITY useCursorNavigation.label "Always use the cursor keys to navigate within pages">
|
||||
<!ENTITY useCursorNavigation.accesskey "c">
|
||||
<!ENTITY searchStartTyping.label "Search for text when I start typing">
|
||||
<!ENTITY searchStartTyping.accesskey "x">
|
||||
<!ENTITY blockAutoRefresh.label "Warn me when websites try to redirect or reload the page">
|
||||
<!ENTITY blockAutoRefresh.accesskey "b">
|
||||
<!ENTITY searchOnStartTyping.label "Search for text when you start typing">
|
||||
<!ENTITY searchOnStartTyping.accesskey "x">
|
||||
<!ENTITY blockAutoReload.label "Warn you when websites try to redirect or reload the page">
|
||||
<!ENTITY blockAutoReload.accesskey "b">
|
||||
<!ENTITY useOnScreenKeyboard.label "Show a touch keyboard when necessary">
|
||||
<!ENTITY useOnScreenKeyboard.accesskey "k">
|
||||
|
||||
|
@ -25,8 +25,8 @@
|
|||
<!ENTITY useSmoothScrolling.accesskey "m">
|
||||
<!ENTITY allowHWAccel.label "Use hardware acceleration when available">
|
||||
<!ENTITY allowHWAccel.accesskey "r">
|
||||
<!ENTITY checkSpelling.label "Check my spelling as I type">
|
||||
<!ENTITY checkSpelling.accesskey "t">
|
||||
<!ENTITY checkUserSpelling.label "Check your spelling as you type">
|
||||
<!ENTITY checkUserSpelling.accesskey "t">
|
||||
|
||||
<!ENTITY dataChoicesTab.label "Data Choices">
|
||||
|
||||
|
@ -85,8 +85,8 @@
|
|||
<!ENTITY updateApplication.label "&brandShortName; updates">
|
||||
<!ENTITY updateAuto1.label "Automatically install updates (recommended: improved security)">
|
||||
<!ENTITY updateAuto1.accesskey "A">
|
||||
<!ENTITY updateCheck.label "Check for updates, but let me choose whether to install them">
|
||||
<!ENTITY updateCheck.accesskey "C">
|
||||
<!ENTITY updateCheckChoose.label "Check for updates, but let you choose whether to install them">
|
||||
<!ENTITY updateCheckChoose.accesskey "C">
|
||||
<!ENTITY updateManual.label "Never check for updates (not recommended: security risk)">
|
||||
<!ENTITY updateManual.accesskey "N">
|
||||
|
||||
|
@ -100,10 +100,10 @@
|
|||
<!ENTITY enableSearchUpdate.label "Search Engines">
|
||||
<!ENTITY enableSearchUpdate.accesskey "E">
|
||||
|
||||
<!ENTITY offlineNotify.label "Tell me when a website asks to store data for offline use">
|
||||
<!ENTITY offlineNotify.accesskey "T">
|
||||
<!ENTITY offlineNotifyExceptions.label "Exceptions…">
|
||||
<!ENTITY offlineNotifyExceptions.accesskey "x">
|
||||
<!ENTITY offlineStorageNotify.label "Tell you when a website asks to store data for offline use">
|
||||
<!ENTITY offlineStorageNotify.accesskey "T">
|
||||
<!ENTITY offlineStorageNotifyExceptions.label "Exceptions…">
|
||||
<!ENTITY offlineStorageNotifyExceptions.accesskey "x">
|
||||
|
||||
<!ENTITY offlineAppsList2.label "The following websites are allowed to store data for offline use:">
|
||||
<!ENTITY offlineAppsList.height "7em">
|
||||
|
@ -112,12 +112,12 @@
|
|||
<!ENTITY offlineAppRemove.confirm "Remove offline data">
|
||||
|
||||
<!ENTITY certificateTab.label "Certificates">
|
||||
<!ENTITY certSelection.label "Requests">
|
||||
<!ENTITY certSelection.description "When a server requests my personal certificate:">
|
||||
<!ENTITY certs.auto "Select one automatically">
|
||||
<!ENTITY certs.auto.accesskey "S">
|
||||
<!ENTITY certs.ask "Ask me every time">
|
||||
<!ENTITY certs.ask.accesskey "A">
|
||||
<!ENTITY certPersonal.label "Requests">
|
||||
<!ENTITY certPersonal.description "When a server requests your personal certificate:">
|
||||
<!ENTITY selectCerts.auto "Select one automatically">
|
||||
<!ENTITY selectCerts.auto.accesskey "S">
|
||||
<!ENTITY selectCerts.ask "Ask you every time">
|
||||
<!ENTITY selectCerts.ask.accesskey "A">
|
||||
<!ENTITY enableOCSP.label "Query OCSP responder servers to confirm the current validity of certificates">
|
||||
<!ENTITY enableOCSP.accesskey "Q">
|
||||
<!ENTITY viewCerts.label "View Certificates">
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
<!ENTITY window.width "38em">
|
||||
<!ENTITY window.macWidth "41em">
|
||||
|
||||
<!ENTITY overridePageColors.label "Override the colors specified by the page with my selections above:">
|
||||
<!ENTITY overridePageColors.accesskey "O">
|
||||
<!ENTITY overrideDefaultPageColors.label "Override the colors specified by the page with your selections above:">
|
||||
<!ENTITY overrideDefaultPageColors.accesskey "O">
|
||||
|
||||
<!ENTITY overridePageColors.always.label "Always">
|
||||
<!ENTITY overridePageColors.auto.label "Only with High Contrast themes">
|
||||
<!ENTITY overridePageColors.never.label "Never">
|
||||
<!ENTITY overrideDefaultPageColors.always.label "Always">
|
||||
<!ENTITY overrideDefaultPageColors.auto.label "Only with High Contrast themes">
|
||||
<!ENTITY overrideDefaultPageColors.never.label "Never">
|
||||
|
||||
<!ENTITY color "Text and Background">
|
||||
<!ENTITY textColor.label "Text:">
|
||||
|
|
|
@ -61,8 +61,8 @@
|
|||
<!ENTITY useDefaultFontSerif.label "Serif">
|
||||
<!ENTITY useDefaultFontSansSerif.label "Sans Serif">
|
||||
|
||||
<!ENTITY allowPagesToUse.label "Allow pages to choose their own fonts, instead of my selections above">
|
||||
<!ENTITY allowPagesToUse.accesskey "A">
|
||||
<!ENTITY allowPagesToUseOwn.label "Allow pages to choose their own fonts, instead of your selections above">
|
||||
<!ENTITY allowPagesToUseOwn.accesskey "A">
|
||||
|
||||
<!ENTITY languages.customize.Fallback2.grouplabel "Text Encoding for Legacy Content">
|
||||
<!ENTITY languages.customize.Fallback2.label "Fallback Text Encoding:">
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
<!ENTITY startupPage.label "When &brandShortName; starts:">
|
||||
<!ENTITY startupPage.accesskey "s">
|
||||
<!ENTITY startupHomePage.label "Show my home page">
|
||||
<!ENTITY startupUserHomePage.label "Show your home page">
|
||||
<!ENTITY startupBlankPage.label "Show a blank page">
|
||||
<!ENTITY startupLastSession.label "Show my windows and tabs from last time">
|
||||
<!ENTITY startupPrevSession.label "Show your windows and tabs from last time">
|
||||
|
||||
<!ENTITY homepage.label "Home Page:">
|
||||
<!ENTITY homepage.accesskey "P">
|
||||
|
@ -28,8 +28,8 @@
|
|||
<!ENTITY chooseFolderWin.accesskey "o">
|
||||
<!ENTITY chooseFolderMac.label "Choose…">
|
||||
<!ENTITY chooseFolderMac.accesskey "e">
|
||||
<!ENTITY alwaysAsk.label "Always ask me where to save files">
|
||||
<!ENTITY alwaysAsk.accesskey "A">
|
||||
<!ENTITY alwaysAskWhere.label "Always ask you where to save files">
|
||||
<!ENTITY alwaysAskWhere.accesskey "A">
|
||||
|
||||
<!ENTITY alwaysCheckDefault2.label "Always check if &brandShortName; is your default browser">
|
||||
<!ENTITY alwaysCheckDefault2.accesskey "y">
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
<!ENTITY general.label "General">
|
||||
|
||||
<!ENTITY warnAddonInstall.label "Warn me when sites try to install add-ons">
|
||||
<!ENTITY warnAddonInstall.accesskey "W">
|
||||
<!ENTITY warnOnAddonInstall.label "Warn you when sites try to install add-ons">
|
||||
<!ENTITY warnOnAddonInstall.accesskey "W">
|
||||
|
||||
<!-- LOCALIZATION NOTE (enableSafeBrowsing.label, blockDownloads.label, blockUncommonUnwanted.label):
|
||||
It is important that wording follows the guidelines outlined on this page:
|
||||
|
@ -17,8 +17,8 @@
|
|||
<!ENTITY blockDownloads.label "Block dangerous downloads">
|
||||
<!ENTITY blockDownloads.accesskey "D">
|
||||
|
||||
<!ENTITY blockUncommonUnwanted.label "Warn me about unwanted and uncommon software">
|
||||
<!ENTITY blockUncommonUnwanted.accesskey "C">
|
||||
<!ENTITY blockUncommonAndUnwanted.label "Warn you about unwanted and uncommon software">
|
||||
<!ENTITY blockUncommonAndUnwanted.accesskey "C">
|
||||
|
||||
<!ENTITY addonExceptions.label "Exceptions…">
|
||||
<!ENTITY addonExceptions.accesskey "E">
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
<!ENTITY newWindowsAsTabs.label "Open new windows in a new tab instead">
|
||||
<!ENTITY newWindowsAsTabs.accesskey "w">
|
||||
|
||||
<!ENTITY warnCloseMultipleTabs.label "Warn me when closing multiple tabs">
|
||||
<!ENTITY warnCloseMultipleTabs.accesskey "m">
|
||||
<!ENTITY warnOnCloseMultipleTabs.label "Warn you when closing multiple tabs">
|
||||
<!ENTITY warnOnCloseMultipleTabs.accesskey "m">
|
||||
|
||||
<!ENTITY warnOpenManyTabs.label "Warn me when opening multiple tabs might slow down &brandShortName;">
|
||||
<!ENTITY warnOpenManyTabs.accesskey "d">
|
||||
<!ENTITY warnOnOpenManyTabs.label "Warn you when opening multiple tabs might slow down &brandShortName;">
|
||||
<!ENTITY warnOnOpenManyTabs.accesskey "d">
|
||||
|
||||
<!ENTITY switchToNewTabs.label "When I open a link in a new tab, switch to it immediately">
|
||||
<!ENTITY switchToNewTabs.accesskey "h">
|
||||
<!ENTITY switchLinksToNewTabs.label "When you open a link in a new tab, switch to it immediately">
|
||||
<!ENTITY switchLinksToNewTabs.accesskey "h">
|
||||
|
||||
<!ENTITY showTabsInTaskbar.label "Show tab previews in the Windows taskbar">
|
||||
<!ENTITY showTabsInTaskbar.accesskey "k">
|
||||
|
|
|
@ -1,455 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import datetime
|
||||
import mozcrash
|
||||
import threading
|
||||
import os
|
||||
import posixpath
|
||||
import Queue
|
||||
import re
|
||||
import shutil
|
||||
import signal
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
import zipfile
|
||||
|
||||
from automation import Automation
|
||||
from mozlog import get_default_logger
|
||||
from mozprocess import ProcessHandlerMixin
|
||||
|
||||
|
||||
class StdOutProc(ProcessHandlerMixin):
|
||||
"""Process handler for b2g which puts all output in a Queue.
|
||||
"""
|
||||
|
||||
def __init__(self, cmd, queue, **kwargs):
|
||||
self.queue = queue
|
||||
kwargs.setdefault('processOutputLine', []).append(self.handle_output)
|
||||
ProcessHandlerMixin.__init__(self, cmd, **kwargs)
|
||||
|
||||
def handle_output(self, line):
|
||||
self.queue.put_nowait(line)
|
||||
|
||||
|
||||
class B2GRemoteAutomation(Automation):
|
||||
_devicemanager = None
|
||||
|
||||
def __init__(self, deviceManager, appName='', remoteLog=None,
|
||||
marionette=None):
|
||||
self._devicemanager = deviceManager
|
||||
self._appName = appName
|
||||
self._remoteProfile = None
|
||||
self._remoteLog = remoteLog
|
||||
self.marionette = marionette
|
||||
self._is_emulator = False
|
||||
self.test_script = None
|
||||
self.test_script_args = None
|
||||
|
||||
# Default our product to b2g
|
||||
self._product = "b2g"
|
||||
self.lastTestSeen = "b2gautomation.py"
|
||||
# Default log finish to mochitest standard
|
||||
self.logFinish = 'INFO SimpleTest FINISHED'
|
||||
Automation.__init__(self)
|
||||
|
||||
def setEmulator(self, is_emulator):
|
||||
self._is_emulator = is_emulator
|
||||
|
||||
def setDeviceManager(self, deviceManager):
|
||||
self._devicemanager = deviceManager
|
||||
|
||||
def setAppName(self, appName):
|
||||
self._appName = appName
|
||||
|
||||
def setRemoteProfile(self, remoteProfile):
|
||||
self._remoteProfile = remoteProfile
|
||||
|
||||
def setProduct(self, product):
|
||||
self._product = product
|
||||
|
||||
def setRemoteLog(self, logfile):
|
||||
self._remoteLog = logfile
|
||||
|
||||
def getExtensionIDFromRDF(self, rdfSource):
|
||||
"""
|
||||
Retrieves the extension id from an install.rdf file (or string).
|
||||
"""
|
||||
from xml.dom.minidom import parse, parseString, Node
|
||||
|
||||
if isinstance(rdfSource, file):
|
||||
document = parse(rdfSource)
|
||||
else:
|
||||
document = parseString(rdfSource)
|
||||
|
||||
# Find the <em:id> element. There can be multiple <em:id> tags
|
||||
# within <em:targetApplication> tags, so we have to check this way.
|
||||
for rdfChild in document.documentElement.childNodes:
|
||||
if rdfChild.nodeType == Node.ELEMENT_NODE and rdfChild.tagName == "Description":
|
||||
for descChild in rdfChild.childNodes:
|
||||
if descChild.nodeType == Node.ELEMENT_NODE and descChild.tagName == "em:id":
|
||||
return descChild.childNodes[0].data
|
||||
return None
|
||||
|
||||
def installExtension(self, extensionSource, profileDir, extensionID=None):
|
||||
# Bug 827504 - installing special-powers extension separately causes problems in B2G
|
||||
if extensionID != "special-powers@mozilla.org":
|
||||
if not os.path.isdir(profileDir):
|
||||
self.log.info("INFO | automation.py | Cannot install extension, invalid profileDir at: %s", profileDir)
|
||||
return
|
||||
|
||||
installRDFFilename = "install.rdf"
|
||||
|
||||
extensionsRootDir = os.path.join(profileDir, "extensions", "staged")
|
||||
if not os.path.isdir(extensionsRootDir):
|
||||
os.makedirs(extensionsRootDir)
|
||||
|
||||
if os.path.isfile(extensionSource):
|
||||
reader = zipfile.ZipFile(extensionSource, "r")
|
||||
|
||||
for filename in reader.namelist():
|
||||
# Sanity check the zip file.
|
||||
if os.path.isabs(filename):
|
||||
self.log.info("INFO | automation.py | Cannot install extension, bad files in xpi")
|
||||
return
|
||||
|
||||
# We may need to dig the extensionID out of the zip file...
|
||||
if extensionID is None and filename == installRDFFilename:
|
||||
extensionID = self.getExtensionIDFromRDF(reader.read(filename))
|
||||
|
||||
# We must know the extensionID now.
|
||||
if extensionID is None:
|
||||
self.log.info("INFO | automation.py | Cannot install extension, missing extensionID")
|
||||
return
|
||||
|
||||
# Make the extension directory.
|
||||
extensionDir = os.path.join(extensionsRootDir, extensionID)
|
||||
os.mkdir(extensionDir)
|
||||
|
||||
# Extract all files.
|
||||
reader.extractall(extensionDir)
|
||||
|
||||
elif os.path.isdir(extensionSource):
|
||||
if extensionID is None:
|
||||
filename = os.path.join(extensionSource, installRDFFilename)
|
||||
if os.path.isfile(filename):
|
||||
with open(filename, "r") as installRDF:
|
||||
extensionID = self.getExtensionIDFromRDF(installRDF)
|
||||
|
||||
if extensionID is None:
|
||||
self.log.info("INFO | automation.py | Cannot install extension, missing extensionID")
|
||||
return
|
||||
|
||||
# Copy extension tree into its own directory.
|
||||
# "destination directory must not already exist".
|
||||
shutil.copytree(extensionSource, os.path.join(extensionsRootDir, extensionID))
|
||||
|
||||
else:
|
||||
self.log.info("INFO | automation.py | Cannot install extension, invalid extensionSource at: %s", extensionSource)
|
||||
|
||||
# Set up what we need for the remote environment
|
||||
def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False):
|
||||
# Because we are running remote, we don't want to mimic the local env
|
||||
# so no copying of os.environ
|
||||
if env is None:
|
||||
env = {}
|
||||
|
||||
if crashreporter:
|
||||
env['MOZ_CRASHREPORTER'] = '1'
|
||||
env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
|
||||
|
||||
# We always hide the results table in B2G; it's much slower if we don't.
|
||||
env['MOZ_HIDE_RESULTS_TABLE'] = '1'
|
||||
return env
|
||||
|
||||
def waitForNet(self):
|
||||
active = False
|
||||
time_out = 0
|
||||
while not active and time_out < 40:
|
||||
data = self._devicemanager._runCmd(['shell', '/system/bin/netcfg']).stdout.readlines()
|
||||
data.pop(0)
|
||||
for line in data:
|
||||
if (re.search(r'UP\s+(?:[0-9]{1,3}\.){3}[0-9]{1,3}', line)):
|
||||
active = True
|
||||
break
|
||||
time_out += 1
|
||||
time.sleep(1)
|
||||
return active
|
||||
|
||||
def checkForCrashes(self, directory, symbolsPath):
|
||||
crashed = False
|
||||
remote_dump_dir = self._remoteProfile + '/minidumps'
|
||||
print "checking for crashes in '%s'" % remote_dump_dir
|
||||
if self._devicemanager.dirExists(remote_dump_dir):
|
||||
local_dump_dir = tempfile.mkdtemp()
|
||||
self._devicemanager.getDirectory(remote_dump_dir, local_dump_dir)
|
||||
try:
|
||||
logger = get_default_logger()
|
||||
if logger is not None:
|
||||
crashed = mozcrash.log_crashes(logger, local_dump_dir, symbolsPath, test=self.lastTestSeen)
|
||||
else:
|
||||
crashed = mozcrash.check_for_crashes(local_dump_dir, symbolsPath, test_name=self.lastTestSeen)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
shutil.rmtree(local_dump_dir)
|
||||
self._devicemanager.removeDir(remote_dump_dir)
|
||||
return crashed
|
||||
|
||||
def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
|
||||
# if remote profile is specified, use that instead
|
||||
if (self._remoteProfile):
|
||||
profileDir = self._remoteProfile
|
||||
|
||||
cmd, args = Automation.buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs)
|
||||
|
||||
return app, args
|
||||
|
||||
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime,
|
||||
debuggerInfo, symbolsPath, outputHandler=None):
|
||||
""" Wait for tests to finish (as evidenced by a signature string
|
||||
in logcat), or for a given amount of time to elapse with no
|
||||
output.
|
||||
"""
|
||||
timeout = timeout or 120
|
||||
while True:
|
||||
lines = proc.getStdoutLines(timeout)
|
||||
if lines:
|
||||
currentlog = '\n'.join(lines)
|
||||
|
||||
if outputHandler:
|
||||
for line in lines:
|
||||
outputHandler(line)
|
||||
else:
|
||||
print(currentlog)
|
||||
|
||||
# Match the test filepath from the last TEST-START line found in the new
|
||||
# log content. These lines are in the form:
|
||||
# ... INFO TEST-START | /filepath/we/wish/to/capture.html\n
|
||||
testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", currentlog)
|
||||
if testStartFilenames:
|
||||
self.lastTestSeen = testStartFilenames[-1]
|
||||
if (outputHandler and outputHandler.suite_finished) or (
|
||||
hasattr(self, 'logFinish') and self.logFinish in currentlog):
|
||||
return 0
|
||||
else:
|
||||
self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed "
|
||||
"out after %d seconds with no output",
|
||||
self.lastTestSeen, int(timeout))
|
||||
self._devicemanager.killProcess('/system/b2g/b2g', sig=signal.SIGABRT)
|
||||
|
||||
timeout = 10 # seconds
|
||||
starttime = datetime.datetime.now()
|
||||
while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
|
||||
if not self._devicemanager.processExist('/system/b2g/b2g'):
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
print "timed out after %d seconds waiting for b2g process to exit" % timeout
|
||||
return 1
|
||||
|
||||
self.checkForCrashes(None, symbolsPath)
|
||||
return 1
|
||||
|
||||
def getDeviceStatus(self, serial=None):
|
||||
# Get the current status of the device. If we know the device
|
||||
# serial number, we look for that, otherwise we use the (presumably
|
||||
# only) device shown in 'adb devices'.
|
||||
serial = serial or self._devicemanager._deviceSerial
|
||||
status = 'unknown'
|
||||
|
||||
for line in self._devicemanager._runCmd(['devices']).stdout.readlines():
|
||||
result = re.match('(.*?)\t(.*)', line)
|
||||
if result:
|
||||
thisSerial = result.group(1)
|
||||
if not serial or thisSerial == serial:
|
||||
serial = thisSerial
|
||||
status = result.group(2)
|
||||
|
||||
return (serial, status)
|
||||
|
||||
def restartB2G(self):
|
||||
# TODO hangs in subprocess.Popen without this delay
|
||||
time.sleep(5)
|
||||
self._devicemanager._checkCmd(['shell', 'stop', 'b2g'])
|
||||
# Wait for a bit to make sure B2G has completely shut down.
|
||||
time.sleep(10)
|
||||
self._devicemanager._checkCmd(['shell', 'start', 'b2g'])
|
||||
if self._is_emulator:
|
||||
self.marionette.emulator.wait_for_port(self.marionette.port)
|
||||
|
||||
def rebootDevice(self):
|
||||
# find device's current status and serial number
|
||||
serial, status = self.getDeviceStatus()
|
||||
|
||||
# reboot!
|
||||
self._devicemanager._runCmd(['shell', '/system/bin/reboot'])
|
||||
|
||||
# The above command can return while adb still thinks the device is
|
||||
# connected, so wait a little bit for it to disconnect from adb.
|
||||
time.sleep(10)
|
||||
|
||||
# wait for device to come back to previous status
|
||||
print 'waiting for device to come back online after reboot'
|
||||
start = time.time()
|
||||
rserial, rstatus = self.getDeviceStatus(serial)
|
||||
while rstatus != 'device':
|
||||
if time.time() - start > 120:
|
||||
# device hasn't come back online in 2 minutes, something's wrong
|
||||
raise Exception("Device %s (status: %s) not back online after reboot" % (serial, rstatus))
|
||||
time.sleep(5)
|
||||
rserial, rstatus = self.getDeviceStatus(serial)
|
||||
print 'device:', serial, 'status:', rstatus
|
||||
|
||||
def Process(self, cmd, stdout=None, stderr=None, env=None, cwd=None):
|
||||
# On a desktop or fennec run, the Process method invokes a gecko
|
||||
# process in which to the tests. For B2G, we simply
|
||||
# reboot the device (which was configured with a test profile
|
||||
# already), wait for B2G to start up, and then navigate to the
|
||||
# test url using Marionette. There doesn't seem to be any way
|
||||
# to pass env variables into the B2G process, but this doesn't
|
||||
# seem to matter.
|
||||
|
||||
# reboot device so it starts up with the mochitest profile
|
||||
# XXX: We could potentially use 'stop b2g' + 'start b2g' to achieve
|
||||
# a similar effect; will see which is more stable while attempting
|
||||
# to bring up the continuous integration.
|
||||
if not self._is_emulator:
|
||||
self.rebootDevice()
|
||||
time.sleep(5)
|
||||
#wait for wlan to come up
|
||||
if not self.waitForNet():
|
||||
raise Exception("network did not come up, please configure the network" +
|
||||
" prior to running before running the automation framework")
|
||||
|
||||
# stop b2g
|
||||
self._devicemanager._runCmd(['shell', 'stop', 'b2g'])
|
||||
time.sleep(5)
|
||||
|
||||
# For some reason user.js in the profile doesn't get picked up.
|
||||
# Manually copy it over to prefs.js. See bug 1009730 for more details.
|
||||
self._devicemanager.moveTree(posixpath.join(self._remoteProfile, 'user.js'),
|
||||
posixpath.join(self._remoteProfile, 'prefs.js'))
|
||||
|
||||
# relaunch b2g inside b2g instance
|
||||
instance = self.B2GInstance(self._devicemanager, env=env)
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
# Set up port forwarding again for Marionette, since any that
|
||||
# existed previously got wiped out by the reboot.
|
||||
if not self._is_emulator:
|
||||
self._devicemanager._checkCmd(['forward',
|
||||
'tcp:%s' % self.marionette.port,
|
||||
'tcp:%s' % self.marionette.port])
|
||||
|
||||
if self._is_emulator:
|
||||
self.marionette.emulator.wait_for_port(self.marionette.port)
|
||||
else:
|
||||
time.sleep(5)
|
||||
|
||||
# start a marionette session
|
||||
session = self.marionette.start_session()
|
||||
if 'b2g' not in session:
|
||||
raise Exception("bad session value %s returned by start_session" % session)
|
||||
|
||||
with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
|
||||
self.marionette.execute_script("""
|
||||
let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Services.prefs.setBoolPref(SECURITY_PREF, true);
|
||||
|
||||
if (!testUtils.hasOwnProperty("specialPowersObserver")) {
|
||||
let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm",
|
||||
testUtils);
|
||||
testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver();
|
||||
testUtils.specialPowersObserver.init();
|
||||
}
|
||||
""")
|
||||
|
||||
# run the script that starts the tests
|
||||
if self.test_script:
|
||||
if os.path.isfile(self.test_script):
|
||||
script = open(self.test_script, 'r')
|
||||
self.marionette.execute_script(script.read(), script_args=self.test_script_args)
|
||||
script.close()
|
||||
elif isinstance(self.test_script, basestring):
|
||||
self.marionette.execute_script(self.test_script, script_args=self.test_script_args)
|
||||
else:
|
||||
# assumes the tests are started on startup automatically
|
||||
pass
|
||||
|
||||
return instance
|
||||
|
||||
# be careful here as this inner class doesn't have access to outer class members
|
||||
class B2GInstance(object):
|
||||
"""Represents a B2G instance running on a device, and exposes
|
||||
some process-like methods/properties that are expected by the
|
||||
automation.
|
||||
"""
|
||||
|
||||
def __init__(self, dm, env=None):
|
||||
self.dm = dm
|
||||
self.env = env or {}
|
||||
self.stdout_proc = None
|
||||
self.queue = Queue.Queue()
|
||||
|
||||
# Launch b2g in a separate thread, and dump all output lines
|
||||
# into a queue. The lines in this queue are
|
||||
# retrieved and returned by accessing the stdout property of
|
||||
# this class.
|
||||
cmd = [self.dm._adbPath]
|
||||
if self.dm._deviceSerial:
|
||||
cmd.extend(['-s', self.dm._deviceSerial])
|
||||
cmd.append('shell')
|
||||
for k, v in self.env.iteritems():
|
||||
cmd.append("%s=%s" % (k, v))
|
||||
cmd.append('/system/bin/b2g.sh')
|
||||
proc = threading.Thread(target=self._save_stdout_proc, args=(cmd, self.queue))
|
||||
proc.daemon = True
|
||||
proc.start()
|
||||
|
||||
def _save_stdout_proc(self, cmd, queue):
|
||||
self.stdout_proc = StdOutProc(cmd, queue)
|
||||
self.stdout_proc.run()
|
||||
if hasattr(self.stdout_proc, 'processOutput'):
|
||||
self.stdout_proc.processOutput()
|
||||
self.stdout_proc.wait()
|
||||
self.stdout_proc = None
|
||||
|
||||
@property
|
||||
def pid(self):
|
||||
# a dummy value to make the automation happy
|
||||
return 0
|
||||
|
||||
def getStdoutLines(self, timeout):
|
||||
# Return any lines in the queue used by the
|
||||
# b2g process handler.
|
||||
lines = []
|
||||
# get all of the lines that are currently available
|
||||
while True:
|
||||
try:
|
||||
lines.append(self.queue.get_nowait())
|
||||
except Queue.Empty:
|
||||
break
|
||||
|
||||
# wait 'timeout' for any additional lines
|
||||
if not lines:
|
||||
try:
|
||||
lines.append(self.queue.get(True, timeout))
|
||||
except Queue.Empty:
|
||||
pass
|
||||
return lines
|
||||
|
||||
def wait(self, timeout=None):
|
||||
# this should never happen
|
||||
raise Exception("'wait' called on B2GInstance")
|
||||
|
||||
def kill(self):
|
||||
# this should never happen
|
||||
raise Exception("'kill' called on B2GInstance")
|
||||
|
|
@ -5,8 +5,8 @@
|
|||
"use strict";
|
||||
|
||||
const {
|
||||
TOGGLE_REQUEST_FILTER_TYPE,
|
||||
ENABLE_REQUEST_FILTER_TYPE_ONLY,
|
||||
TOGGLE_REQUEST_FILTER_TYPE,
|
||||
SET_REQUEST_FILTER_TEXT,
|
||||
} = require("../constants");
|
||||
|
||||
|
@ -40,7 +40,7 @@ function enableRequestFilterTypeOnly(filter) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set filter text.
|
||||
* Set filter text in toolbar.
|
||||
*
|
||||
* @param {string} text - A filter text is going to be set
|
||||
*/
|
||||
|
@ -52,7 +52,7 @@ function setRequestFilterText(text) {
|
|||
}
|
||||
|
||||
module.exports = {
|
||||
toggleRequestFilterType,
|
||||
enableRequestFilterTypeOnly,
|
||||
toggleRequestFilterType,
|
||||
setRequestFilterText,
|
||||
};
|
||||
|
|
|
@ -8,18 +8,16 @@ const { connect } = require("devtools/client/shared/vendor/react-redux");
|
|||
const SearchBox = require("devtools/client/shared/components/search-box");
|
||||
const { L10N } = require("../l10n");
|
||||
const Actions = require("../actions/index");
|
||||
const { FREETEXT_FILTER_SEARCH_DELAY } = require("../constants");
|
||||
const { FILTER_SEARCH_DELAY } = require("../constants");
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
delay: FREETEXT_FILTER_SEARCH_DELAY,
|
||||
delay: FILTER_SEARCH_DELAY,
|
||||
keyShortcut: L10N.getStr("netmonitor.toolbar.filterFreetext.key"),
|
||||
placeholder: L10N.getStr("netmonitor.toolbar.filterFreetext.label"),
|
||||
type: "filter",
|
||||
}),
|
||||
(dispatch) => ({
|
||||
onChange: (url) => {
|
||||
dispatch(Actions.setRequestFilterText(url));
|
||||
},
|
||||
onChange: (text) => dispatch(Actions.setRequestFilterText(text)),
|
||||
})
|
||||
)(SearchBox);
|
||||
|
|
|
@ -10,7 +10,7 @@ const {
|
|||
} = require("devtools/client/shared/vendor/react");
|
||||
const ClearButton = createFactory(require("./clear-button"));
|
||||
const FilterButtons = createFactory(require("./filter-buttons"));
|
||||
const SearchBox = createFactory(require("./search-box"));
|
||||
const ToolbarSearchBox = createFactory(require("./search-box"));
|
||||
const SummaryButton = createFactory(require("./summary-button"));
|
||||
const ToggleButton = createFactory(require("./toggle-button"));
|
||||
|
||||
|
@ -28,7 +28,7 @@ function Toolbar() {
|
|||
),
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
SummaryButton(),
|
||||
SearchBox(),
|
||||
ToolbarSearchBox(),
|
||||
ToggleButton()
|
||||
)
|
||||
);
|
||||
|
|
|
@ -3,22 +3,20 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* eslint-disable mozilla/reject-some-requires */
|
||||
/* globals window, dumpn, $, gNetwork */
|
||||
/* globals window, dumpn, $ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const promise = require("promise");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { ToolSidebar } = require("devtools/client/framework/sidebar");
|
||||
const { VariablesView } = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
|
||||
const { EVENTS } = require("./events");
|
||||
const { L10N } = require("./l10n");
|
||||
const { Filters } = require("./filter-predicates");
|
||||
const { createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
||||
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
|
||||
const CookiesPanel = createFactory(require("./shared/components/cookies-panel"));
|
||||
const HeadersPanel = createFactory(require("./shared/components/headers-panel"));
|
||||
const ParamsPanel = createFactory(require("./shared/components/params-panel"));
|
||||
const PreviewPanel = createFactory(require("./shared/components/preview-panel"));
|
||||
|
@ -26,18 +24,6 @@ const ResponsePanel = createFactory(require("./shared/components/response-panel"
|
|||
const SecurityPanel = createFactory(require("./shared/components/security-panel"));
|
||||
const TimingsPanel = createFactory(require("./shared/components/timings-panel"));
|
||||
|
||||
const GENERIC_VARIABLES_VIEW_SETTINGS = {
|
||||
lazyEmpty: true,
|
||||
// ms
|
||||
lazyEmptyDelay: 10,
|
||||
searchEnabled: true,
|
||||
editableValueTooltip: "",
|
||||
editableNameTooltip: "",
|
||||
preventDisableOnChange: true,
|
||||
preventDescriptorModifiers: true,
|
||||
eval: () => {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Functions handling the requests details view.
|
||||
*/
|
||||
|
@ -70,6 +56,13 @@ DetailsView.prototype = {
|
|||
initialize: function (store) {
|
||||
dumpn("Initializing the DetailsView");
|
||||
|
||||
this._cookiesPanelNode = $("#react-cookies-tabpanel-hook");
|
||||
|
||||
ReactDOM.render(Provider(
|
||||
{ store },
|
||||
CookiesPanel()
|
||||
), this._cookiesPanelNode);
|
||||
|
||||
this._headersPanelNode = $("#react-headers-tabpanel-hook");
|
||||
|
||||
ReactDOM.render(Provider(
|
||||
|
@ -117,16 +110,6 @@ DetailsView.prototype = {
|
|||
disableTelemetry: true,
|
||||
showAllTabsMenu: true
|
||||
});
|
||||
|
||||
this._cookies = new VariablesView($("#all-cookies"),
|
||||
Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
|
||||
emptyText: L10N.getStr("cookiesEmptyText"),
|
||||
searchPlaceholder: L10N.getStr("cookiesFilterText")
|
||||
}));
|
||||
|
||||
this._requestCookies = L10N.getStr("requestCookies");
|
||||
this._responseCookies = L10N.getStr("responseCookies");
|
||||
|
||||
$("tabpanels", this.widget).addEventListener("select", this._onTabSelect);
|
||||
},
|
||||
|
||||
|
@ -135,8 +118,9 @@ DetailsView.prototype = {
|
|||
*/
|
||||
destroy: function () {
|
||||
dumpn("Destroying the DetailsView");
|
||||
ReactDOM.unmountComponentAtNode(this._paramsPanelNode);
|
||||
ReactDOM.unmountComponentAtNode(this._cookiesPanelNode);
|
||||
ReactDOM.unmountComponentAtNode(this._headersPanelNode);
|
||||
ReactDOM.unmountComponentAtNode(this._paramsPanelNode);
|
||||
ReactDOM.unmountComponentAtNode(this._previewPanelNode);
|
||||
ReactDOM.unmountComponentAtNode(this._responsePanelNode);
|
||||
ReactDOM.unmountComponentAtNode(this._securityPanelNode);
|
||||
|
@ -177,8 +161,6 @@ DetailsView.prototype = {
|
|||
this.widget.selectedIndex = 0;
|
||||
}
|
||||
|
||||
this._cookies.empty();
|
||||
|
||||
this._dataSrc = { src: data, populated: [] };
|
||||
this._onTabSelect();
|
||||
window.emit(EVENTS.NETWORKDETAILSVIEW_POPULATED);
|
||||
|
@ -211,14 +193,6 @@ DetailsView.prototype = {
|
|||
}
|
||||
|
||||
Task.spawn(function* () {
|
||||
viewState.updating[tab] = true;
|
||||
switch (tab) {
|
||||
// "Cookies"
|
||||
case 1:
|
||||
yield view._setResponseCookies(src.responseCookies);
|
||||
yield view._setRequestCookies(src.requestCookies);
|
||||
break;
|
||||
}
|
||||
viewState.updating[tab] = false;
|
||||
}).then(() => {
|
||||
if (tab == this.widget.selectedIndex) {
|
||||
|
@ -239,78 +213,7 @@ DetailsView.prototype = {
|
|||
}, e => console.error(e));
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the network request cookies shown in this view.
|
||||
*
|
||||
* @param object response
|
||||
* The message received from the server.
|
||||
* @return object
|
||||
* A promise that is resolved when the request cookies are set.
|
||||
*/
|
||||
_setRequestCookies: Task.async(function* (response) {
|
||||
if (response && response.cookies.length) {
|
||||
response.cookies.sort((a, b) => a.name > b.name);
|
||||
yield this._addCookies(this._requestCookies, response);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Sets the network response cookies shown in this view.
|
||||
*
|
||||
* @param object response
|
||||
* The message received from the server.
|
||||
* @return object
|
||||
* A promise that is resolved when the response cookies are set.
|
||||
*/
|
||||
_setResponseCookies: Task.async(function* (response) {
|
||||
if (response && response.cookies.length) {
|
||||
yield this._addCookies(this._responseCookies, response);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Populates the cookies container in this view with the specified data.
|
||||
*
|
||||
* @param string name
|
||||
* The type of cookies to populate (request or response).
|
||||
* @param object response
|
||||
* The message received from the server.
|
||||
* @return object
|
||||
* Returns a promise that resolves upon the adding of cookies.
|
||||
*/
|
||||
_addCookies: Task.async(function* (name, response) {
|
||||
let cookiesScope = this._cookies.addScope(name);
|
||||
cookiesScope.expanded = true;
|
||||
|
||||
for (let cookie of response.cookies) {
|
||||
let cookieVar = cookiesScope.addItem(cookie.name, {}, {relaxed: true});
|
||||
let cookieValue = yield gNetwork.getString(cookie.value);
|
||||
cookieVar.setGrip(cookieValue);
|
||||
|
||||
// By default the cookie name and value are shown. If this is the only
|
||||
// information available, then nothing else is to be displayed.
|
||||
let cookieProps = Object.keys(cookie);
|
||||
if (cookieProps.length == 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Display any other information other than the cookie name and value
|
||||
// which may be available.
|
||||
let rawObject = Object.create(null);
|
||||
let otherProps = cookieProps.filter(e => e != "name" && e != "value");
|
||||
for (let prop of otherProps) {
|
||||
rawObject[prop] = cookie[prop];
|
||||
}
|
||||
cookieVar.populate(rawObject);
|
||||
cookieVar.twisty = true;
|
||||
cookieVar.expanded = true;
|
||||
}
|
||||
}),
|
||||
|
||||
_dataSrc: null,
|
||||
_cookies: null,
|
||||
_requestCookies: "",
|
||||
_responseCookies: ""
|
||||
};
|
||||
|
||||
exports.DetailsView = DetailsView;
|
||||
|
|
|
@ -129,7 +129,8 @@
|
|||
<tabpanel id="cookies-tabpanel"
|
||||
class="tabpanel-content">
|
||||
<vbox flex="1">
|
||||
<vbox id="all-cookies" flex="1"/>
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-cookies-tabpanel-hook"/>
|
||||
</vbox>
|
||||
</tabpanel>
|
||||
<tabpanel id="params-tabpanel"
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
const I = require("devtools/client/shared/vendor/immutable");
|
||||
const {
|
||||
TOGGLE_REQUEST_FILTER_TYPE,
|
||||
ENABLE_REQUEST_FILTER_TYPE_ONLY,
|
||||
TOGGLE_REQUEST_FILTER_TYPE,
|
||||
SET_REQUEST_FILTER_TEXT,
|
||||
} = require("../constants");
|
||||
|
||||
|
@ -67,12 +67,12 @@ function enableRequestFilterTypeOnly(state, action) {
|
|||
|
||||
function filters(state = new Filters(), action) {
|
||||
switch (action.type) {
|
||||
case TOGGLE_REQUEST_FILTER_TYPE:
|
||||
return state.set("requestFilterTypes",
|
||||
toggleRequestFilterType(state.requestFilterTypes, action));
|
||||
case ENABLE_REQUEST_FILTER_TYPE_ONLY:
|
||||
return state.set("requestFilterTypes",
|
||||
enableRequestFilterTypeOnly(state.requestFilterTypes, action));
|
||||
case TOGGLE_REQUEST_FILTER_TYPE:
|
||||
return state.set("requestFilterTypes",
|
||||
toggleRequestFilterType(state.requestFilterTypes, action));
|
||||
case SET_REQUEST_FILTER_TEXT:
|
||||
return state.set("requestFilterText", action.text);
|
||||
default:
|
||||
|
|
|
@ -28,10 +28,10 @@ const {
|
|||
|
||||
const {
|
||||
getActiveFilters,
|
||||
getSortedRequests,
|
||||
getDisplayedRequests,
|
||||
getRequestById,
|
||||
getSelectedRequest,
|
||||
getSortedRequests,
|
||||
} = require("./selectors/index");
|
||||
|
||||
// ms
|
||||
|
@ -224,7 +224,7 @@ RequestsMenuView.prototype = {
|
|||
isXHR,
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker
|
||||
fromServiceWorker,
|
||||
},
|
||||
true
|
||||
);
|
||||
|
@ -235,13 +235,15 @@ RequestsMenuView.prototype = {
|
|||
updateRequest: Task.async(function* (id, data) {
|
||||
const action = Actions.updateRequest(id, data, true);
|
||||
yield this.store.dispatch(action);
|
||||
|
||||
let {
|
||||
responseContent,
|
||||
responseCookies,
|
||||
responseHeaders,
|
||||
requestCookies,
|
||||
requestHeaders,
|
||||
requestPostData,
|
||||
responseContent,
|
||||
responseHeaders,
|
||||
} = action.data;
|
||||
let request = getRequestById(this.store.getState(), action.id);
|
||||
|
||||
if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
|
||||
let headers = yield fetchHeaders(
|
||||
|
@ -267,26 +269,23 @@ RequestsMenuView.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
if (responseContent && responseContent.content) {
|
||||
let request = getRequestById(this.store.getState(), action.id);
|
||||
if (request) {
|
||||
let { mimeType } = request;
|
||||
let { text, encoding } = responseContent.content;
|
||||
let response = yield gNetwork.getString(text);
|
||||
let payload = {};
|
||||
if (request && responseContent && responseContent.content) {
|
||||
let { mimeType } = request;
|
||||
let { text, encoding } = responseContent.content;
|
||||
let response = yield gNetwork.getString(text);
|
||||
let payload = {};
|
||||
|
||||
if (mimeType.includes("image/")) {
|
||||
payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
|
||||
}
|
||||
if (mimeType.includes("image/")) {
|
||||
payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
|
||||
}
|
||||
|
||||
responseContent.content.text = response;
|
||||
payload.responseContent = responseContent;
|
||||
responseContent.content.text = response;
|
||||
payload.responseContent = responseContent;
|
||||
|
||||
yield this.store.dispatch(Actions.updateRequest(action.id, payload, true));
|
||||
yield this.store.dispatch(Actions.updateRequest(action.id, payload, true));
|
||||
|
||||
if (mimeType.includes("image/")) {
|
||||
window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
|
||||
}
|
||||
if (mimeType.includes("image/")) {
|
||||
window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,6 +305,51 @@ RequestsMenuView.prototype = {
|
|||
|
||||
yield this.store.dispatch(Actions.updateRequest(action.id, payload, true));
|
||||
}
|
||||
|
||||
// Fetch request and response cookies long value.
|
||||
// Actor does not provide full sized cookie value when the value is too long
|
||||
// To display values correctly, we need fetch them in each request.
|
||||
if (requestCookies) {
|
||||
let reqCookies = [];
|
||||
// request store cookies in requestCookies or requestCookies.cookies
|
||||
let cookies = requestCookies.cookies ?
|
||||
requestCookies.cookies : requestCookies;
|
||||
// make sure cookies is iterable
|
||||
if (typeof cookies[Symbol.iterator] === "function") {
|
||||
for (let cookie of cookies) {
|
||||
reqCookies.push(Object.assign({}, cookie, {
|
||||
value: yield gNetwork.getString(cookie.value),
|
||||
}));
|
||||
}
|
||||
if (reqCookies.length) {
|
||||
yield this.store.dispatch(Actions.updateRequest(
|
||||
action.id,
|
||||
{ requestCookies: reqCookies },
|
||||
true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (responseCookies) {
|
||||
let resCookies = [];
|
||||
// response store cookies in responseCookies or responseCookies.cookies
|
||||
let cookies = responseCookies.cookies ?
|
||||
responseCookies.cookies : responseCookies;
|
||||
// make sure cookies is iterable
|
||||
if (typeof cookies[Symbol.iterator] === "function") {
|
||||
for (let cookie of cookies) {
|
||||
resCookies.push(Object.assign({}, cookie, {
|
||||
value: yield gNetwork.getString(cookie.value),
|
||||
}));
|
||||
}
|
||||
if (resCookies.length) {
|
||||
yield this.store.dispatch(Actions.updateRequest(
|
||||
action.id,
|
||||
{ responseCookies: resCookies },
|
||||
true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
|
|
|
@ -97,6 +97,32 @@ const getSelectedRequest = createSelector(
|
|||
({ selectedId, requests }) => selectedId ? requests.get(selectedId) : null
|
||||
);
|
||||
|
||||
const getSelectedRequestCookies = createSelector(
|
||||
getSelectedRequest,
|
||||
selectedRequest => {
|
||||
// request store cookies in requestCookies or requestCookies.cookies
|
||||
if (selectedRequest && selectedRequest.requestCookies) {
|
||||
return selectedRequest.requestCookies.cookies ?
|
||||
selectedRequest.requestCookies.cookies : selectedRequest.requestCookies;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
);
|
||||
|
||||
const getSelectedResponseCookies = createSelector(
|
||||
getSelectedRequest,
|
||||
selectedRequest => {
|
||||
// response store cookies in responseCookies or responseCookies.cookies
|
||||
if (selectedRequest && selectedRequest.responseCookies) {
|
||||
return selectedRequest.responseCookies.cookies ?
|
||||
selectedRequest.responseCookies.cookies : selectedRequest.responseCookies;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
);
|
||||
|
||||
function getRequestById(state, id) {
|
||||
return state.requests.requests.get(id);
|
||||
}
|
||||
|
@ -111,5 +137,7 @@ module.exports = {
|
|||
getDisplayedRequestsSummary,
|
||||
getRequestById,
|
||||
getSelectedRequest,
|
||||
getSelectedRequestCookies,
|
||||
getSelectedResponseCookies,
|
||||
getSortedRequests,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createFactory,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { L10N } = require("../../l10n");
|
||||
const {
|
||||
getSelectedRequestCookies,
|
||||
getSelectedResponseCookies,
|
||||
} = require("../../selectors/index");
|
||||
|
||||
// Component
|
||||
const PropertiesView = createFactory(require("./properties-view"));
|
||||
|
||||
const { div } = DOM;
|
||||
|
||||
const COOKIES_EMPTY_TEXT = L10N.getStr("cookiesEmptyText");
|
||||
const COOKIES_FILTER_TEXT = L10N.getStr("cookiesFilterText");
|
||||
const REQUEST_COOKIES = L10N.getStr("requestCookies");
|
||||
const RESPONSE_COOKIES = L10N.getStr("responseCookies");
|
||||
const SECTION_NAMES = [
|
||||
RESPONSE_COOKIES,
|
||||
REQUEST_COOKIES,
|
||||
];
|
||||
|
||||
/*
|
||||
* Cookies panel component
|
||||
* This tab lists full details of any cookies sent with the request or response
|
||||
*/
|
||||
function CookiesPanel({
|
||||
request,
|
||||
response,
|
||||
}) {
|
||||
if (!response.length && !request.length) {
|
||||
return div({ className: "empty-notice" },
|
||||
COOKIES_EMPTY_TEXT
|
||||
);
|
||||
}
|
||||
|
||||
let object = {};
|
||||
if (response.length) {
|
||||
object[RESPONSE_COOKIES] = getProperties(response);
|
||||
}
|
||||
if (request.length) {
|
||||
object[REQUEST_COOKIES] = getProperties(request);
|
||||
}
|
||||
|
||||
return (
|
||||
PropertiesView({
|
||||
object,
|
||||
filterPlaceHolder: COOKIES_FILTER_TEXT,
|
||||
sectionNames: SECTION_NAMES,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
CookiesPanel.displayName = "CookiesPanel";
|
||||
|
||||
CookiesPanel.propTypes = {
|
||||
request: PropTypes.array.isRequired,
|
||||
response: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping array to dict for TreeView usage.
|
||||
* Since TreeView only support Object(dict) format.
|
||||
*
|
||||
* @param {Object[]} arr - key-value pair array like cookies or params
|
||||
* @returns {Object}
|
||||
*/
|
||||
function getProperties(arr) {
|
||||
return arr.reduce((map, obj) => {
|
||||
// Generally cookies object contains only name and value properties and can
|
||||
// be rendered as name: value pair.
|
||||
// When there are more properties in cookies object such as extra or path,
|
||||
// We will pass the object to display these extra information
|
||||
if (Object.keys(obj).length > 2) {
|
||||
map[obj.name] = Object.assign({}, obj);
|
||||
delete map[obj.name].name;
|
||||
} else {
|
||||
map[obj.name] = obj.value;
|
||||
}
|
||||
return map;
|
||||
}, {});
|
||||
}
|
||||
|
||||
module.exports = connect(
|
||||
state => ({
|
||||
request: getSelectedRequestCookies(state),
|
||||
response: getSelectedResponseCookies(state),
|
||||
})
|
||||
)(CookiesPanel);
|
|
@ -3,6 +3,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'cookies-panel.js',
|
||||
'editor.js',
|
||||
'headers-panel.js',
|
||||
'params-panel.js',
|
||||
|
|
|
@ -1272,6 +1272,7 @@
|
|||
* FIXME: normal html block element cannot fill outer XUL element
|
||||
* This workaround should be removed after netmonitor is migrated to react
|
||||
*/
|
||||
#react-cookies-tabpanel-hook,
|
||||
#react-headers-tabpanel-hook,
|
||||
#react-params-tabpanel-hook,
|
||||
#react-preview-tabpanel-hook,
|
||||
|
@ -1286,6 +1287,7 @@
|
|||
}
|
||||
|
||||
/* For vbox */
|
||||
#react-cookies-tabpanel-hook,
|
||||
#react-headers-tabpanel-hook,
|
||||
#react-params-tabpanel-hook,
|
||||
#react-preview-tabpanel-hook,
|
||||
|
|
|
@ -108,6 +108,8 @@ public:
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
PROFILER_LABEL("HTMLCanvasElement", "FrameCapture", js::ProfileEntry::Category::OTHER);
|
||||
|
||||
if (!mOwningElement) {
|
||||
return;
|
||||
}
|
||||
|
@ -126,18 +128,29 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> snapshot = mOwningElement->GetSurfaceSnapshot(nullptr);
|
||||
if (!snapshot) {
|
||||
return;
|
||||
RefPtr<SourceSurface> snapshot;
|
||||
{
|
||||
PROFILER_LABEL("HTMLCanvasElement", "GetSnapshot", js::ProfileEntry::Category::OTHER);
|
||||
snapshot = mOwningElement->GetSurfaceSnapshot(nullptr);
|
||||
if (!snapshot) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<DataSourceSurface> copy = CopySurface(snapshot);
|
||||
if (!copy) {
|
||||
return;
|
||||
RefPtr<DataSourceSurface> copy;
|
||||
{
|
||||
PROFILER_LABEL("HTMLCanvasElement", "CopySnapshot", js::ProfileEntry::Category::OTHER);
|
||||
copy = CopySurface(snapshot);
|
||||
if (!copy) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mOwningElement->SetFrameCapture(copy.forget());
|
||||
mOwningElement->MarkContextCleanForFrameCapture();
|
||||
{
|
||||
PROFILER_LABEL("HTMLCanvasElement", "SetFrame", js::ProfileEntry::Category::OTHER);
|
||||
mOwningElement->SetFrameCapture(copy.forget());
|
||||
mOwningElement->MarkContextCleanForFrameCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void DetachFromRefreshDriver()
|
||||
|
|
|
@ -752,10 +752,10 @@ MediaDecoder::CallSeek(const SeekTarget& aTarget, dom::Promise* aPromise)
|
|||
DiscardOngoingSeekIfExists();
|
||||
|
||||
mSeekDOMPromise = aPromise;
|
||||
mSeekRequest.Begin(
|
||||
mDecoderStateMachine->InvokeSeek(aTarget)
|
||||
->Then(AbstractThread::MainThread(), __func__, this,
|
||||
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
|
||||
mDecoderStateMachine->InvokeSeek(aTarget)
|
||||
->Then(AbstractThread::MainThread(), __func__, this,
|
||||
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected)
|
||||
->Track(mSeekRequest);
|
||||
}
|
||||
|
||||
double
|
||||
|
|
|
@ -340,14 +340,15 @@ public:
|
|||
|
||||
// We disconnect mMetadataRequest in Exit() so it is fine to capture
|
||||
// a raw pointer here.
|
||||
mMetadataRequest.Begin(Reader()->ReadMetadata()
|
||||
Reader()->ReadMetadata()
|
||||
->Then(OwnerThread(), __func__,
|
||||
[this] (MetadataHolder* aMetadata) {
|
||||
OnMetadataRead(aMetadata);
|
||||
},
|
||||
[this] (const MediaResult& aError) {
|
||||
OnMetadataNotRead(aError);
|
||||
}));
|
||||
})
|
||||
->Track(mMetadataRequest);
|
||||
}
|
||||
|
||||
void Exit() override
|
||||
|
@ -1108,14 +1109,15 @@ private:
|
|||
void DemuxerSeek()
|
||||
{
|
||||
// Request the demuxer to perform seek.
|
||||
mSeekRequest.Begin(Reader()->Seek(mSeekJob.mTarget.ref())
|
||||
Reader()->Seek(mSeekJob.mTarget.ref())
|
||||
->Then(OwnerThread(), __func__,
|
||||
[this] (const media::TimeUnit& aUnit) {
|
||||
OnSeekResolved(aUnit);
|
||||
},
|
||||
[this] (const SeekRejectValue& aReject) {
|
||||
OnSeekRejected(aReject);
|
||||
}));
|
||||
})
|
||||
->Track(mSeekRequest);
|
||||
}
|
||||
|
||||
void DoSeek() override
|
||||
|
@ -1191,20 +1193,18 @@ private:
|
|||
MOZ_ASSERT(!mMaster->IsWaitingVideoData());
|
||||
// Fire 'waiting' to notify the player that we are waiting for data.
|
||||
mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING);
|
||||
mWaitRequest.Begin(
|
||||
Reader()->WaitForData(aReject.mType)->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this] (MediaData::Type aType) {
|
||||
SLOG("OnSeekRejected wait promise resolved");
|
||||
mWaitRequest.Complete();
|
||||
DemuxerSeek();
|
||||
},
|
||||
[this] (const WaitForDataRejectValue& aRejection) {
|
||||
SLOG("OnSeekRejected wait promise rejected");
|
||||
mWaitRequest.Complete();
|
||||
mMaster->DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
|
||||
})
|
||||
);
|
||||
Reader()->WaitForData(aReject.mType)->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this] (MediaData::Type aType) {
|
||||
SLOG("OnSeekRejected wait promise resolved");
|
||||
mWaitRequest.Complete();
|
||||
DemuxerSeek();
|
||||
},
|
||||
[this] (const WaitForDataRejectValue& aRejection) {
|
||||
SLOG("OnSeekRejected wait promise rejected");
|
||||
mWaitRequest.Complete();
|
||||
mMaster->DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
|
||||
})->Track(mWaitRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2086,7 +2086,7 @@ DecodingState::Enter()
|
|||
HandleVideoSuspendTimeout();
|
||||
}
|
||||
|
||||
if (mMaster->CheckIfDecodeComplete()) {
|
||||
if (!mMaster->IsVideoDecoding() && !mMaster->IsAudioDecoding()) {
|
||||
SetState<CompletedState>();
|
||||
return;
|
||||
}
|
||||
|
@ -2126,7 +2126,7 @@ MediaDecoderStateMachine::
|
|||
DecodingState::HandleEndOfAudio()
|
||||
{
|
||||
AudioQueue().Finish();
|
||||
if (mMaster->CheckIfDecodeComplete()) {
|
||||
if (!mMaster->IsVideoDecoding()) {
|
||||
SetState<CompletedState>();
|
||||
} else {
|
||||
MaybeStopPrerolling();
|
||||
|
@ -2138,7 +2138,7 @@ MediaDecoderStateMachine::
|
|||
DecodingState::HandleEndOfVideo()
|
||||
{
|
||||
VideoQueue().Finish();
|
||||
if (mMaster->CheckIfDecodeComplete()) {
|
||||
if (!mMaster->IsAudioDecoding()) {
|
||||
SetState<CompletedState>();
|
||||
} else {
|
||||
MaybeStopPrerolling();
|
||||
|
@ -2382,7 +2382,7 @@ MediaDecoderStateMachine::
|
|||
BufferingState::HandleEndOfAudio()
|
||||
{
|
||||
AudioQueue().Finish();
|
||||
if (mMaster->CheckIfDecodeComplete()) {
|
||||
if (!mMaster->IsVideoDecoding()) {
|
||||
SetState<CompletedState>();
|
||||
} else {
|
||||
// Check if we can exit buffering.
|
||||
|
@ -2395,7 +2395,7 @@ MediaDecoderStateMachine::
|
|||
BufferingState::HandleEndOfVideo()
|
||||
{
|
||||
VideoQueue().Finish();
|
||||
if (mMaster->CheckIfDecodeComplete()) {
|
||||
if (!mMaster->IsAudioDecoding()) {
|
||||
SetState<CompletedState>();
|
||||
} else {
|
||||
// Check if we can exit buffering.
|
||||
|
@ -2699,17 +2699,6 @@ MediaDecoderStateMachine::IsVideoDecoding()
|
|||
return HasVideo() && !VideoQueue().IsFinished();
|
||||
}
|
||||
|
||||
bool
|
||||
MediaDecoderStateMachine::CheckIfDecodeComplete()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
// DecodeComplete is possible only after decoding first frames.
|
||||
MOZ_ASSERT(mSentFirstFrameLoadedEvent);
|
||||
MOZ_ASSERT(mState == DECODER_STATE_DECODING ||
|
||||
mState == DECODER_STATE_BUFFERING);
|
||||
return !IsVideoDecoding() && !IsAudioDecoding();
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::IsPlaying() const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
@ -2739,10 +2728,11 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder)
|
|||
|
||||
mMediaSink = CreateMediaSink(mAudioCaptured);
|
||||
|
||||
mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then(
|
||||
aDecoder->RequestCDMProxy()->Then(
|
||||
OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnCDMProxyReady,
|
||||
&MediaDecoderStateMachine::OnCDMProxyNotReady));
|
||||
&MediaDecoderStateMachine::OnCDMProxyNotReady)
|
||||
->Track(mCDMProxyPromise);
|
||||
|
||||
nsresult rv = mReader->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -3019,35 +3009,33 @@ MediaDecoderStateMachine::RequestAudioData()
|
|||
SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
|
||||
AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
|
||||
|
||||
mAudioDataRequest.Begin(
|
||||
mReader->RequestAudioData()->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this] (MediaData* aAudio) {
|
||||
MOZ_ASSERT(aAudio);
|
||||
mAudioDataRequest.Complete();
|
||||
// audio->GetEndTime() is not always mono-increasing in chained ogg.
|
||||
mDecodedAudioEndTime = std::max(aAudio->GetEndTime(), mDecodedAudioEndTime);
|
||||
SAMPLE_LOG("OnAudioDecoded [%lld,%lld]", aAudio->mTime, aAudio->GetEndTime());
|
||||
mStateObj->HandleAudioDecoded(aAudio);
|
||||
},
|
||||
[this] (const MediaResult& aError) {
|
||||
SAMPLE_LOG("OnAudioNotDecoded aError=%u", aError.Code());
|
||||
mAudioDataRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
mStateObj->HandleWaitingForAudio();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
mStateObj->HandleAudioCanceled();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
mStateObj->HandleEndOfAudio();
|
||||
break;
|
||||
default:
|
||||
DecodeError(aError);
|
||||
}
|
||||
})
|
||||
);
|
||||
mReader->RequestAudioData()->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this] (MediaData* aAudio) {
|
||||
MOZ_ASSERT(aAudio);
|
||||
mAudioDataRequest.Complete();
|
||||
// audio->GetEndTime() is not always mono-increasing in chained ogg.
|
||||
mDecodedAudioEndTime = std::max(aAudio->GetEndTime(), mDecodedAudioEndTime);
|
||||
SAMPLE_LOG("OnAudioDecoded [%lld,%lld]", aAudio->mTime, aAudio->GetEndTime());
|
||||
mStateObj->HandleAudioDecoded(aAudio);
|
||||
},
|
||||
[this] (const MediaResult& aError) {
|
||||
SAMPLE_LOG("OnAudioNotDecoded aError=%u", aError.Code());
|
||||
mAudioDataRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
mStateObj->HandleWaitingForAudio();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
mStateObj->HandleAudioCanceled();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
mStateObj->HandleEndOfAudio();
|
||||
break;
|
||||
default:
|
||||
DecodeError(aError);
|
||||
}
|
||||
})->Track(mAudioDataRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3063,35 +3051,33 @@ MediaDecoderStateMachine::RequestVideoData(bool aSkipToNextKeyframe,
|
|||
aCurrentTime.ToMicroseconds());
|
||||
|
||||
TimeStamp videoDecodeStartTime = TimeStamp::Now();
|
||||
mVideoDataRequest.Begin(
|
||||
mReader->RequestVideoData(aSkipToNextKeyframe, aCurrentTime)->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this, videoDecodeStartTime] (MediaData* aVideo) {
|
||||
MOZ_ASSERT(aVideo);
|
||||
mVideoDataRequest.Complete();
|
||||
// Handle abnormal or negative timestamps.
|
||||
mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, aVideo->GetEndTime());
|
||||
SAMPLE_LOG("OnVideoDecoded [%lld,%lld]", aVideo->mTime, aVideo->GetEndTime());
|
||||
mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime);
|
||||
},
|
||||
[this] (const MediaResult& aError) {
|
||||
SAMPLE_LOG("OnVideoNotDecoded aError=%u", aError.Code());
|
||||
mVideoDataRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
mStateObj->HandleWaitingForVideo();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
mStateObj->HandleVideoCanceled();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
mStateObj->HandleEndOfVideo();
|
||||
break;
|
||||
default:
|
||||
DecodeError(aError);
|
||||
}
|
||||
})
|
||||
);
|
||||
mReader->RequestVideoData(aSkipToNextKeyframe, aCurrentTime)->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this, videoDecodeStartTime] (MediaData* aVideo) {
|
||||
MOZ_ASSERT(aVideo);
|
||||
mVideoDataRequest.Complete();
|
||||
// Handle abnormal or negative timestamps.
|
||||
mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, aVideo->GetEndTime());
|
||||
SAMPLE_LOG("OnVideoDecoded [%lld,%lld]", aVideo->mTime, aVideo->GetEndTime());
|
||||
mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime);
|
||||
},
|
||||
[this] (const MediaResult& aError) {
|
||||
SAMPLE_LOG("OnVideoNotDecoded aError=%u", aError.Code());
|
||||
mVideoDataRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
mStateObj->HandleWaitingForVideo();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
mStateObj->HandleVideoCanceled();
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
mStateObj->HandleEndOfVideo();
|
||||
break;
|
||||
default:
|
||||
DecodeError(aError);
|
||||
}
|
||||
})->Track(mVideoDataRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3100,33 +3086,29 @@ MediaDecoderStateMachine::WaitForData(MediaData::Type aType)
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aType == MediaData::AUDIO_DATA || aType == MediaData::VIDEO_DATA);
|
||||
if (aType == MediaData::AUDIO_DATA) {
|
||||
mAudioWaitRequest.Begin(
|
||||
mReader->WaitForData(MediaData::AUDIO_DATA)->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this] (MediaData::Type aType) {
|
||||
mAudioWaitRequest.Complete();
|
||||
MOZ_ASSERT(aType == MediaData::AUDIO_DATA);
|
||||
mStateObj->HandleAudioWaited(aType);
|
||||
},
|
||||
[this] (const WaitForDataRejectValue& aRejection) {
|
||||
mAudioWaitRequest.Complete();
|
||||
DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
|
||||
})
|
||||
);
|
||||
mReader->WaitForData(MediaData::AUDIO_DATA)->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this] (MediaData::Type aType) {
|
||||
mAudioWaitRequest.Complete();
|
||||
MOZ_ASSERT(aType == MediaData::AUDIO_DATA);
|
||||
mStateObj->HandleAudioWaited(aType);
|
||||
},
|
||||
[this] (const WaitForDataRejectValue& aRejection) {
|
||||
mAudioWaitRequest.Complete();
|
||||
DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
|
||||
})->Track(mAudioWaitRequest);
|
||||
} else {
|
||||
mVideoWaitRequest.Begin(
|
||||
mReader->WaitForData(MediaData::VIDEO_DATA)->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this] (MediaData::Type aType) {
|
||||
mVideoWaitRequest.Complete();
|
||||
MOZ_ASSERT(aType == MediaData::VIDEO_DATA);
|
||||
mStateObj->HandleVideoWaited(aType);
|
||||
},
|
||||
[this] (const WaitForDataRejectValue& aRejection) {
|
||||
mVideoWaitRequest.Complete();
|
||||
DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
|
||||
})
|
||||
);
|
||||
mReader->WaitForData(MediaData::VIDEO_DATA)->Then(
|
||||
OwnerThread(), __func__,
|
||||
[this] (MediaData::Type aType) {
|
||||
mVideoWaitRequest.Complete();
|
||||
MOZ_ASSERT(aType == MediaData::VIDEO_DATA);
|
||||
mStateObj->HandleVideoWaited(aType);
|
||||
},
|
||||
[this] (const WaitForDataRejectValue& aRejection) {
|
||||
mVideoWaitRequest.Complete();
|
||||
DecodeError(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA);
|
||||
})->Track(mVideoWaitRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3142,16 +3124,18 @@ MediaDecoderStateMachine::StartMediaSink()
|
|||
auto audioPromise = mMediaSink->OnEnded(TrackInfo::kAudioTrack);
|
||||
|
||||
if (audioPromise) {
|
||||
mMediaSinkAudioPromise.Begin(audioPromise->Then(
|
||||
audioPromise->Then(
|
||||
OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnMediaSinkAudioComplete,
|
||||
&MediaDecoderStateMachine::OnMediaSinkAudioError));
|
||||
&MediaDecoderStateMachine::OnMediaSinkAudioError)
|
||||
->Track(mMediaSinkAudioPromise);
|
||||
}
|
||||
if (videoPromise) {
|
||||
mMediaSinkVideoPromise.Begin(videoPromise->Then(
|
||||
videoPromise->Then(
|
||||
OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnMediaSinkVideoComplete,
|
||||
&MediaDecoderStateMachine::OnMediaSinkVideoError));
|
||||
&MediaDecoderStateMachine::OnMediaSinkVideoError)
|
||||
->Track(mMediaSinkVideoPromise);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -443,9 +443,6 @@ protected:
|
|||
|
||||
void FinishDecodeFirstFrame();
|
||||
|
||||
// Queries our state to see whether the decode has finished for all streams.
|
||||
bool CheckIfDecodeComplete();
|
||||
|
||||
// Performs one "cycle" of the state machine.
|
||||
void RunStateMachine();
|
||||
|
||||
|
|
|
@ -290,7 +290,7 @@ MediaFormatReader::DecoderFactory::RunStage(TrackType aTrack)
|
|||
switch (data.mStage) {
|
||||
case Stage::None: {
|
||||
MOZ_ASSERT(!data.mToken);
|
||||
data.mTokenPromise.Begin(DecoderAllocPolicy::Instance(aTrack).Alloc()->Then(
|
||||
DecoderAllocPolicy::Instance(aTrack).Alloc()->Then(
|
||||
mOwner->OwnerThread(), __func__,
|
||||
[this, &data, aTrack] (Token* aToken) {
|
||||
data.mTokenPromise.Complete();
|
||||
|
@ -301,7 +301,7 @@ MediaFormatReader::DecoderFactory::RunStage(TrackType aTrack)
|
|||
[&data] () {
|
||||
data.mTokenPromise.Complete();
|
||||
data.mStage = Stage::None;
|
||||
}));
|
||||
})->Track(data.mTokenPromise);
|
||||
data.mStage = Stage::WaitForToken;
|
||||
break;
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ MediaFormatReader::DecoderFactory::DoInitDecoder(TrackType aTrack)
|
|||
auto& ownerData = mOwner->GetDecoderData(aTrack);
|
||||
auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
|
||||
|
||||
data.mInitPromise.Begin(data.mDecoder->Init()->Then(
|
||||
data.mDecoder->Init()->Then(
|
||||
mOwner->OwnerThread(), __func__,
|
||||
[this, &data, &ownerData] (TrackType aTrack) {
|
||||
data.mInitPromise.Complete();
|
||||
|
@ -426,7 +426,7 @@ MediaFormatReader::DecoderFactory::DoInitDecoder(TrackType aTrack)
|
|||
data.mDecoder->Shutdown();
|
||||
data.mDecoder = nullptr;
|
||||
mOwner->NotifyError(aTrack, aError);
|
||||
}));
|
||||
})->Track(data.mInitPromise);
|
||||
}
|
||||
|
||||
// DemuxerProxy ensures that the original main demuxer is only ever accessed
|
||||
|
@ -977,10 +977,11 @@ MediaFormatReader::AsyncReadMetadata()
|
|||
|
||||
RefPtr<MetadataPromise> p = mMetadataPromise.Ensure(__func__);
|
||||
|
||||
mDemuxerInitRequest.Begin(mDemuxer->Init()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnDemuxerInitDone,
|
||||
&MediaFormatReader::OnDemuxerInitFailed));
|
||||
mDemuxer->Init()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnDemuxerInitDone,
|
||||
&MediaFormatReader::OnDemuxerInitFailed)
|
||||
->Track(mDemuxerInitRequest);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -1277,9 +1278,10 @@ MediaFormatReader::DoDemuxVideo()
|
|||
});
|
||||
}
|
||||
|
||||
mVideo.mDemuxRequest.Begin(p->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnVideoDemuxCompleted,
|
||||
&MediaFormatReader::OnVideoDemuxFailed));
|
||||
p->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnVideoDemuxCompleted,
|
||||
&MediaFormatReader::OnVideoDemuxFailed)
|
||||
->Track(mVideo.mDemuxRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1343,9 +1345,10 @@ MediaFormatReader::DoDemuxAudio()
|
|||
});
|
||||
}
|
||||
|
||||
mAudio.mDemuxRequest.Begin(p->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnAudioDemuxCompleted,
|
||||
&MediaFormatReader::OnAudioDemuxFailed));
|
||||
p->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnAudioDemuxCompleted,
|
||||
&MediaFormatReader::OnAudioDemuxFailed)
|
||||
->Track(mAudio.mDemuxRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1705,37 +1708,38 @@ MediaFormatReader::InternalSeek(TrackType aTrack, const InternalSeekTarget& aTar
|
|||
decoder.ResetDemuxer();
|
||||
decoder.mTimeThreshold = Some(aTarget);
|
||||
RefPtr<MediaFormatReader> self = this;
|
||||
decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self, aTrack] (media::TimeUnit aTime) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
MOZ_ASSERT(decoder.mTimeThreshold,
|
||||
"Seek promise must be disconnected when timethreshold is reset");
|
||||
decoder.mTimeThreshold.ref().mHasSeeked = true;
|
||||
self->SetVideoDecodeThreshold();
|
||||
self->ScheduleUpdate(aTrack);
|
||||
},
|
||||
[self, aTrack] (const MediaResult& aError) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
self->NotifyWaitingForData(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyEndOfStream(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
decoder.mTimeThreshold.reset();
|
||||
break;
|
||||
default:
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyError(aTrack, aError);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self, aTrack] (media::TimeUnit aTime) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
MOZ_ASSERT(decoder.mTimeThreshold,
|
||||
"Seek promise must be disconnected when timethreshold is reset");
|
||||
decoder.mTimeThreshold.ref().mHasSeeked = true;
|
||||
self->SetVideoDecodeThreshold();
|
||||
self->ScheduleUpdate(aTrack);
|
||||
},
|
||||
[self, aTrack] (const MediaResult& aError) {
|
||||
auto& decoder = self->GetDecoderData(aTrack);
|
||||
decoder.mSeekRequest.Complete();
|
||||
switch (aError.Code()) {
|
||||
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
|
||||
self->NotifyWaitingForData(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyEndOfStream(aTrack);
|
||||
break;
|
||||
case NS_ERROR_DOM_MEDIA_CANCELED:
|
||||
decoder.mTimeThreshold.reset();
|
||||
break;
|
||||
default:
|
||||
decoder.mTimeThreshold.reset();
|
||||
self->NotifyError(aTrack, aError);
|
||||
break;
|
||||
}
|
||||
})
|
||||
->Track(decoder.mSeekRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2197,10 +2201,11 @@ MediaFormatReader::SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold)
|
|||
// decoder threshold to the value of currentTime.
|
||||
DropDecodedSamples(TrackInfo::kVideoTrack);
|
||||
|
||||
mSkipRequest.Begin(mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnVideoSkipCompleted,
|
||||
&MediaFormatReader::OnVideoSkipFailed));
|
||||
mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnVideoSkipCompleted,
|
||||
&MediaFormatReader::OnVideoSkipFailed)
|
||||
->Track(mSkipRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2408,10 +2413,11 @@ MediaFormatReader::DoVideoSeek()
|
|||
MOZ_ASSERT(mPendingSeekTime.isSome());
|
||||
LOGV("Seeking video to %lld", mPendingSeekTime.ref().ToMicroseconds());
|
||||
media::TimeUnit seekTime = mPendingSeekTime.ref();
|
||||
mVideo.mSeekRequest.Begin(mVideo.mTrackDemuxer->Seek(seekTime)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnVideoSeekCompleted,
|
||||
&MediaFormatReader::OnVideoSeekFailed));
|
||||
mVideo.mTrackDemuxer->Seek(seekTime)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnVideoSeekCompleted,
|
||||
&MediaFormatReader::OnVideoSeekFailed)
|
||||
->Track(mVideo.mSeekRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2490,10 +2496,11 @@ MediaFormatReader::DoAudioSeek()
|
|||
MOZ_ASSERT(mPendingSeekTime.isSome());
|
||||
LOGV("Seeking audio to %lld", mPendingSeekTime.ref().ToMicroseconds());
|
||||
media::TimeUnit seekTime = mPendingSeekTime.ref();
|
||||
mAudio.mSeekRequest.Begin(mAudio.mTrackDemuxer->Seek(seekTime)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnAudioSeekCompleted,
|
||||
&MediaFormatReader::OnAudioSeekFailed));
|
||||
mAudio.mTrackDemuxer->Seek(seekTime)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaFormatReader::OnAudioSeekCompleted,
|
||||
&MediaFormatReader::OnAudioSeekFailed)
|
||||
->Track(mAudio.mSeekRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2564,14 +2571,15 @@ MediaFormatReader::NotifyDataArrived()
|
|||
}
|
||||
|
||||
RefPtr<MediaFormatReader> self = this;
|
||||
mNotifyDataArrivedPromise.Begin(mDemuxer->NotifyDataArrived()->Then(
|
||||
OwnerThread(), __func__,
|
||||
[self]() {
|
||||
self->mNotifyDataArrivedPromise.Complete();
|
||||
self->UpdateBuffered();
|
||||
self->NotifyTrackDemuxers();
|
||||
},
|
||||
[self]() { self->mNotifyDataArrivedPromise.Complete(); }));
|
||||
mDemuxer->NotifyDataArrived()
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self]() {
|
||||
self->mNotifyDataArrivedPromise.Complete();
|
||||
self->UpdateBuffered();
|
||||
self->NotifyTrackDemuxers();
|
||||
},
|
||||
[self]() { self->mNotifyDataArrivedPromise.Complete(); })
|
||||
->Track(mNotifyDataArrivedPromise);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -145,10 +145,11 @@ public:
|
|||
}
|
||||
Reset();
|
||||
mTarget = aTarget;
|
||||
mRequest.Begin(mMediaTimer->WaitUntil(mTarget, __func__)->Then(
|
||||
mMediaTimer->WaitUntil(mTarget, __func__)->Then(
|
||||
mTargetThread, __func__,
|
||||
Forward<ResolveFunc>(aResolver),
|
||||
Forward<RejectFunc>(aRejector)));
|
||||
Forward<RejectFunc>(aRejector))
|
||||
->Track(mRequest);
|
||||
}
|
||||
|
||||
void CompleteRequest()
|
||||
|
|
|
@ -330,7 +330,7 @@ AndroidMediaReader::Seek(const SeekTarget& aTarget)
|
|||
mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds();
|
||||
|
||||
RefPtr<AndroidMediaReader> self = this;
|
||||
mSeekRequest.Begin(DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (MediaData* v) {
|
||||
DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (MediaData* v) {
|
||||
self->mSeekRequest.Complete();
|
||||
self->mAudioSeekTimeUs = v->mTime;
|
||||
self->mSeekPromise.Resolve(media::TimeUnit::FromMicroseconds(self->mAudioSeekTimeUs), __func__);
|
||||
|
@ -338,7 +338,7 @@ AndroidMediaReader::Seek(const SeekTarget& aTarget)
|
|||
self->mSeekRequest.Complete();
|
||||
self->mAudioSeekTimeUs = aTarget.GetTime().ToMicroseconds();
|
||||
self->mSeekPromise.Resolve(aTarget.GetTime(), __func__);
|
||||
}));
|
||||
})->Track(mSeekRequest);
|
||||
} else {
|
||||
mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds();
|
||||
mSeekPromise.Resolve(aTarget.GetTime(), __func__);
|
||||
|
|
|
@ -24,7 +24,6 @@ LazyLogModule gVP8TrackEncoderLog("VP8TrackEncoder");
|
|||
// Debug logging macro with object pointer and class name.
|
||||
|
||||
#define DEFAULT_BITRATE_BPS 2500000
|
||||
#define DEFAULT_ENCODE_FRAMERATE 30
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::layers;
|
||||
|
@ -56,9 +55,7 @@ GetSourceSurface(already_AddRefed<Image> aImg)
|
|||
|
||||
VP8TrackEncoder::VP8TrackEncoder(TrackRate aTrackRate)
|
||||
: VideoTrackEncoder(aTrackRate)
|
||||
, mEncodedFrameDuration(0)
|
||||
, mEncodedTimestamp(0)
|
||||
, mRemainingTicks(0)
|
||||
, mVPXContext(new vpx_codec_ctx_t())
|
||||
, mVPXImageWrapper(new vpx_image_t())
|
||||
{
|
||||
|
@ -87,8 +84,6 @@ VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, int32_t aDisplayWidth,
|
|||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
mEncodedFrameRate = DEFAULT_ENCODE_FRAMERATE;
|
||||
mEncodedFrameDuration = mTrackRate / mEncodedFrameRate;
|
||||
mFrameWidth = aWidth;
|
||||
mFrameHeight = aHeight;
|
||||
mDisplayWidth = aDisplayWidth;
|
||||
|
@ -147,7 +142,7 @@ VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, int32_t aDisplayWidth,
|
|||
|
||||
config.kf_mode = VPX_KF_AUTO;
|
||||
// Ensure that we can output one I-frame per second.
|
||||
config.kf_max_dist = mEncodedFrameRate;
|
||||
config.kf_max_dist = 60;
|
||||
|
||||
vpx_codec_flags_t flags = 0;
|
||||
flags |= VPX_CODEC_USE_OUTPUT_PARTITION;
|
||||
|
@ -188,7 +183,6 @@ VP8TrackEncoder::GetMetadata()
|
|||
meta->mHeight = mFrameHeight;
|
||||
meta->mDisplayWidth = mDisplayWidth;
|
||||
meta->mDisplayHeight = mDisplayHeight;
|
||||
meta->mEncodedFrameRate = mEncodedFrameRate;
|
||||
|
||||
return meta.forget();
|
||||
}
|
||||
|
@ -473,8 +467,7 @@ VP8TrackEncoder::GetNextEncodeOperation(TimeDuration aTimeElapsed,
|
|||
StreamTime aProcessedDuration)
|
||||
{
|
||||
int64_t durationInUsec =
|
||||
FramesToUsecs(aProcessedDuration + mEncodedFrameDuration,
|
||||
mTrackRate).value();
|
||||
FramesToUsecs(aProcessedDuration, mTrackRate).value();
|
||||
if (aTimeElapsed.ToMicroseconds() > (durationInUsec * SKIP_FRAME_RATIO)) {
|
||||
// The encoder is too slow.
|
||||
// We should skip next frame to consume the mSourceSegment.
|
||||
|
@ -488,71 +481,20 @@ VP8TrackEncoder::GetNextEncodeOperation(TimeDuration aTimeElapsed,
|
|||
}
|
||||
}
|
||||
|
||||
StreamTime
|
||||
VP8TrackEncoder::CalculateRemainingTicks(StreamTime aDurationCopied,
|
||||
StreamTime aEncodedDuration)
|
||||
{
|
||||
return mRemainingTicks + aEncodedDuration - aDurationCopied;
|
||||
}
|
||||
|
||||
// Try to extend the encodedDuration as long as possible if the target frame
|
||||
// has a long duration.
|
||||
StreamTime
|
||||
VP8TrackEncoder::CalculateEncodedDuration(StreamTime aDurationCopied)
|
||||
{
|
||||
StreamTime temp64 = aDurationCopied;
|
||||
StreamTime encodedDuration = mEncodedFrameDuration;
|
||||
temp64 -= mRemainingTicks;
|
||||
while (temp64 > mEncodedFrameDuration) {
|
||||
temp64 -= mEncodedFrameDuration;
|
||||
encodedDuration += mEncodedFrameDuration;
|
||||
}
|
||||
return encodedDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoding flow in GetEncodedTrack():
|
||||
* 1: Check the mInitialized state and the packet duration.
|
||||
* 2: Move the data from mRawSegment to mSourceSegment.
|
||||
* 3: Encode the video chunks in mSourceSegment in a for-loop.
|
||||
* 3.1: Pick the video chunk by mRemainingTicks.
|
||||
* 3.2: Calculate the encoding duration for the parameter of vpx_codec_encode().
|
||||
* The encoding duration is a multiple of mEncodedFrameDuration.
|
||||
* 3.3: Setup the video chunk to mVPXImageWrapper by PrepareRawFrame().
|
||||
* 3.4: Send frame into vp8 encoder by vpx_codec_encode().
|
||||
* 3.5: Get the output frame from encoder by calling GetEncodedPartitions().
|
||||
* 3.6: Calculate the mRemainingTicks for next target frame.
|
||||
* 3.7: Set the nextEncodeOperation for the next target frame.
|
||||
* 3.1: The duration is taken straight from the video chunk's duration.
|
||||
* 3.2: Setup the video chunk with mVPXImageWrapper by PrepareRawFrame().
|
||||
* 3.3: Pass frame to vp8 encoder by vpx_codec_encode().
|
||||
* 3.4: Get the encoded frame from encoder by GetEncodedPartitions().
|
||||
* 3.5: Set the nextEncodeOperation for the next target frame.
|
||||
* There is a heuristic: If the frame duration we have processed in
|
||||
* mSourceSegment is 100ms, means that we can't spend more than 100ms to
|
||||
* encode it.
|
||||
* 4. Remove the encoded chunks in mSourceSegment after for-loop.
|
||||
*
|
||||
* Ex1: Input frame rate is 100 => input frame duration is 10ms for each.
|
||||
* mEncodedFrameRate is 30 => output frame duration is 33ms.
|
||||
* In this case, the frame duration in mSourceSegment will be:
|
||||
* 1st : 0~10ms
|
||||
* 2nd : 10~20ms
|
||||
* 3rd : 20~30ms
|
||||
* 4th : 30~40ms
|
||||
* ...
|
||||
* The VP8 encoder will take the 1st and 4th frames to encode. At beginning
|
||||
* mRemainingTicks is 0 for 1st frame, then the mRemainingTicks is set
|
||||
* to 23 to pick the 4th frame. (mEncodedFrameDuration - 1st frame duration)
|
||||
*
|
||||
* Ex2: Input frame rate is 25 => frame duration is 40ms for each.
|
||||
* mEncodedFrameRate is 30 => output frame duration is 33ms.
|
||||
* In this case, the frame duration in mSourceSegment will be:
|
||||
* 1st : 0~40ms
|
||||
* 2nd : 40~80ms
|
||||
* 3rd : 80~120ms
|
||||
* 4th : 120~160ms
|
||||
* ...
|
||||
* Because the input frame duration is 40ms larger than 33ms, so the first
|
||||
* encoded frame duration will be 66ms by calling CalculateEncodedDuration.
|
||||
* And the mRemainingTicks will be set to 26
|
||||
* (CalculateRemainingTicks 0+66-40) in order to pick the next frame(2nd)
|
||||
* in mSourceSegment.
|
||||
*/
|
||||
nsresult
|
||||
VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
|
@ -567,8 +509,8 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
|||
// Wait if mEncoder is not initialized, or when not enough raw data, but is
|
||||
// not the end of stream nor is being canceled.
|
||||
while (!mCanceled && (!mInitialized ||
|
||||
(mRawSegment.GetDuration() + mSourceSegment.GetDuration() <
|
||||
mEncodedFrameDuration && !mEndOfStream))) {
|
||||
(mRawSegment.GetDuration() + mSourceSegment.GetDuration() == 0 &&
|
||||
!mEndOfStream))) {
|
||||
mon.Wait();
|
||||
}
|
||||
if (mCanceled || mEncodingComplete) {
|
||||
|
@ -578,75 +520,54 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
|||
EOS = mEndOfStream;
|
||||
}
|
||||
|
||||
VideoSegment::ChunkIterator iter(mSourceSegment);
|
||||
StreamTime durationCopied = 0;
|
||||
StreamTime totalProcessedDuration = 0;
|
||||
TimeStamp timebase = TimeStamp::Now();
|
||||
EncodeOperation nextEncodeOperation = ENCODE_NORMAL_FRAME;
|
||||
|
||||
for (; !iter.IsEnded(); iter.Next()) {
|
||||
for (VideoSegment::ChunkIterator iter(mSourceSegment);
|
||||
!iter.IsEnded(); iter.Next()) {
|
||||
VideoChunk &chunk = *iter;
|
||||
// Accumulate chunk's duration to durationCopied until it reaches
|
||||
// mRemainingTicks.
|
||||
durationCopied += chunk.GetDuration();
|
||||
MOZ_ASSERT(mRemainingTicks <= mEncodedFrameDuration);
|
||||
VP8LOG("durationCopied %lld mRemainingTicks %lld\n",
|
||||
durationCopied, mRemainingTicks);
|
||||
if (durationCopied >= mRemainingTicks) {
|
||||
VP8LOG("nextEncodeOperation is %d\n",nextEncodeOperation);
|
||||
// Calculate encodedDuration for this target frame.
|
||||
StreamTime encodedDuration = CalculateEncodedDuration(durationCopied);
|
||||
VP8LOG("nextEncodeOperation is %d for frame of duration %lld\n",
|
||||
nextEncodeOperation, chunk.GetDuration());
|
||||
|
||||
// Encode frame.
|
||||
if (nextEncodeOperation != SKIP_FRAME) {
|
||||
nsresult rv = PrepareRawFrame(chunk);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||
// Encode frame.
|
||||
if (nextEncodeOperation != SKIP_FRAME) {
|
||||
nsresult rv = PrepareRawFrame(chunk);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||
|
||||
// Encode the data with VP8 encoder
|
||||
int flags = (nextEncodeOperation == ENCODE_NORMAL_FRAME) ?
|
||||
0 : VPX_EFLAG_FORCE_KF;
|
||||
if (vpx_codec_encode(mVPXContext, mVPXImageWrapper, mEncodedTimestamp,
|
||||
(unsigned long)encodedDuration, flags,
|
||||
VPX_DL_REALTIME)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Get the encoded data from VP8 encoder.
|
||||
GetEncodedPartitions(aData);
|
||||
} else {
|
||||
// SKIP_FRAME
|
||||
// Extend the duration of the last encoded data in aData
|
||||
// because this frame will be skip.
|
||||
RefPtr<EncodedFrame> last = nullptr;
|
||||
last = aData.GetEncodedFrames().LastElement();
|
||||
if (last) {
|
||||
last->SetDuration(last->GetDuration() + encodedDuration);
|
||||
}
|
||||
// Encode the data with VP8 encoder
|
||||
int flags = (nextEncodeOperation == ENCODE_NORMAL_FRAME) ?
|
||||
0 : VPX_EFLAG_FORCE_KF;
|
||||
if (vpx_codec_encode(mVPXContext, mVPXImageWrapper, mEncodedTimestamp,
|
||||
(unsigned long)chunk.GetDuration(), flags,
|
||||
VPX_DL_REALTIME)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Move forward the mEncodedTimestamp.
|
||||
mEncodedTimestamp += encodedDuration;
|
||||
totalProcessedDuration += durationCopied;
|
||||
// Calculate mRemainingTicks for next target frame.
|
||||
mRemainingTicks = CalculateRemainingTicks(durationCopied,
|
||||
encodedDuration);
|
||||
|
||||
// Check the remain data is enough for next target frame.
|
||||
if (mSourceSegment.GetDuration() - totalProcessedDuration
|
||||
>= mEncodedFrameDuration) {
|
||||
TimeDuration elapsedTime = TimeStamp::Now() - timebase;
|
||||
nextEncodeOperation = GetNextEncodeOperation(elapsedTime,
|
||||
totalProcessedDuration);
|
||||
// Reset durationCopied for next iteration.
|
||||
durationCopied = 0;
|
||||
} else {
|
||||
// Process done, there is no enough data left for next iteration,
|
||||
// break the for-loop.
|
||||
break;
|
||||
// Get the encoded data from VP8 encoder.
|
||||
GetEncodedPartitions(aData);
|
||||
} else {
|
||||
// SKIP_FRAME
|
||||
// Extend the duration of the last encoded data in aData
|
||||
// because this frame will be skip.
|
||||
NS_WARNING("MediaRecorder lagging behind. Skipping a frame.");
|
||||
RefPtr<EncodedFrame> last = aData.GetEncodedFrames().LastElement();
|
||||
if (last) {
|
||||
last->SetDuration(last->GetDuration() + chunk.GetDuration());
|
||||
}
|
||||
}
|
||||
|
||||
// Move forward the mEncodedTimestamp.
|
||||
mEncodedTimestamp += chunk.GetDuration();
|
||||
totalProcessedDuration += chunk.GetDuration();
|
||||
|
||||
// Check what to do next.
|
||||
TimeDuration elapsedTime = TimeStamp::Now() - timebase;
|
||||
nextEncodeOperation = GetNextEncodeOperation(elapsedTime,
|
||||
totalProcessedDuration);
|
||||
}
|
||||
|
||||
// Remove the chunks we have processed.
|
||||
mSourceSegment.RemoveLeading(totalProcessedDuration);
|
||||
VP8LOG("RemoveLeading %lld\n",totalProcessedDuration);
|
||||
mSourceSegment.Clear();
|
||||
|
||||
// End of stream, pull the rest frames in encoder.
|
||||
if (EOS) {
|
||||
|
@ -657,7 +578,7 @@ VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
|||
|
||||
do {
|
||||
if (vpx_codec_encode(mVPXContext, nullptr, mEncodedTimestamp,
|
||||
mEncodedFrameDuration, 0, VPX_DL_REALTIME)) {
|
||||
0, 0, VPX_DL_REALTIME)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} while(GetEncodedPartitions(aData));
|
||||
|
|
|
@ -16,10 +16,9 @@ typedef struct vpx_codec_enc_cfg vpx_codec_enc_cfg_t;
|
|||
typedef struct vpx_image vpx_image_t;
|
||||
|
||||
/**
|
||||
* VP8TrackEncoder implements VideoTrackEncoder by using libvpx library.
|
||||
* We implement a realtime and fixed FPS encoder. In order to achieve that,
|
||||
* there is a pick target frame and drop frame encoding policy implemented in
|
||||
* GetEncodedTrack.
|
||||
* VP8TrackEncoder implements VideoTrackEncoder by using the libvpx library.
|
||||
* We implement a realtime and variable frame rate encoder. In order to achieve
|
||||
* that, there is a frame-drop encoding policy implemented in GetEncodedTrack.
|
||||
*/
|
||||
class VP8TrackEncoder : public VideoTrackEncoder
|
||||
{
|
||||
|
@ -41,13 +40,6 @@ protected:
|
|||
int32_t aDisplayWidth, int32_t aDisplayHeight) final override;
|
||||
|
||||
private:
|
||||
// Calculate the target frame's encoded duration.
|
||||
StreamTime CalculateEncodedDuration(StreamTime aDurationCopied);
|
||||
|
||||
// Calculate the mRemainingTicks for next target frame.
|
||||
StreamTime CalculateRemainingTicks(StreamTime aDurationCopied,
|
||||
StreamTime aEncodedDuration);
|
||||
|
||||
// Get the EncodeOperation for next target frame.
|
||||
EncodeOperation GetNextEncodeOperation(TimeDuration aTimeElapsed,
|
||||
StreamTime aProcessedDuration);
|
||||
|
@ -60,14 +52,8 @@ private:
|
|||
// Prepare the input data to the mVPXImageWrapper for encoding.
|
||||
nsresult PrepareRawFrame(VideoChunk &aChunk);
|
||||
|
||||
// Output frame rate.
|
||||
uint32_t mEncodedFrameRate;
|
||||
// Duration for the output frame, reciprocal to mEncodedFrameRate.
|
||||
StreamTime mEncodedFrameDuration;
|
||||
// Encoded timestamp.
|
||||
StreamTime mEncodedTimestamp;
|
||||
// Duration to the next encode frame.
|
||||
StreamTime mRemainingTicks;
|
||||
|
||||
// Muted frame, we only create it once.
|
||||
RefPtr<layers::Image> mMuteFrame;
|
||||
|
@ -77,9 +63,7 @@ private:
|
|||
|
||||
/**
|
||||
* A local segment queue which takes the raw data out from mRawSegment in the
|
||||
* call of GetEncodedTrack(). Since we implement the fixed FPS encoding
|
||||
* policy, it needs to be global in order to store the leftover segments
|
||||
* taken from mRawSegment.
|
||||
* call of GetEncodedTrack().
|
||||
*/
|
||||
VideoSegment mSourceSegment;
|
||||
|
||||
|
|
|
@ -280,7 +280,7 @@ TEST(MozPromise, Chaining)
|
|||
}
|
||||
// We will hit the assertion if we don't disconnect the leaf Request
|
||||
// in the promise chain.
|
||||
holder.Begin(p->Then(queue, __func__, [] () {}, [] () {}));
|
||||
p->Then(queue, __func__, [] () {}, [] () {})->Track(holder);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -193,10 +193,11 @@ AudioSinkWrapper::Start(int64_t aStartTime, const MediaInfo& aInfo)
|
|||
mAudioSink = mCreator->Create();
|
||||
mEndPromise = mAudioSink->Init(mParams);
|
||||
|
||||
mAudioSinkPromise.Begin(mEndPromise->Then(
|
||||
mEndPromise->Then(
|
||||
mOwnerThread.get(), __func__, this,
|
||||
&AudioSinkWrapper::OnAudioEnded,
|
||||
&AudioSinkWrapper::OnAudioEnded));
|
||||
&AudioSinkWrapper::OnAudioEnded
|
||||
)->Track(mAudioSinkPromise);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ VideoSink::Start(int64_t aStartTime, const MediaInfo& aInfo)
|
|||
RefPtr<GenericPromise> p = mAudioSink->OnEnded(TrackInfo::kVideoTrack);
|
||||
if (p) {
|
||||
RefPtr<VideoSink> self = this;
|
||||
mVideoSinkEndRequest.Begin(p->Then(mOwnerThread, __func__,
|
||||
p->Then(mOwnerThread, __func__,
|
||||
[self] () {
|
||||
self->mVideoSinkEndRequest.Complete();
|
||||
self->TryUpdateRenderedVideoFrames();
|
||||
|
@ -197,7 +197,8 @@ VideoSink::Start(int64_t aStartTime, const MediaInfo& aInfo)
|
|||
self->mVideoSinkEndRequest.Complete();
|
||||
self->TryUpdateRenderedVideoFrames();
|
||||
self->MaybeResolveEndPromise();
|
||||
}));
|
||||
})
|
||||
->Track(mVideoSinkEndRequest);
|
||||
}
|
||||
|
||||
ConnectListener();
|
||||
|
|
|
@ -258,7 +258,6 @@ SourceBuffer::RangeRemoval(double aStart, double aEnd)
|
|||
StartUpdating();
|
||||
|
||||
RefPtr<SourceBuffer> self = this;
|
||||
mPendingRemoval.Begin(
|
||||
mTrackBuffersManager->RangeRemoval(TimeUnit::FromSeconds(aStart),
|
||||
TimeUnit::FromSeconds(aEnd))
|
||||
->Then(AbstractThread::MainThread(), __func__,
|
||||
|
@ -266,7 +265,8 @@ SourceBuffer::RangeRemoval(double aStart, double aEnd)
|
|||
self->mPendingRemoval.Complete();
|
||||
self->StopUpdating();
|
||||
},
|
||||
[]() { MOZ_ASSERT(false); }));
|
||||
[]() { MOZ_ASSERT(false); })
|
||||
->Track(mPendingRemoval);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -415,10 +415,11 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
|||
}
|
||||
StartUpdating();
|
||||
|
||||
mPendingAppend.Begin(mTrackBuffersManager->AppendData(data, mCurrentAttributes)
|
||||
->Then(AbstractThread::MainThread(), __func__, this,
|
||||
&SourceBuffer::AppendDataCompletedWithSuccess,
|
||||
&SourceBuffer::AppendDataErrored));
|
||||
mTrackBuffersManager->AppendData(data, mCurrentAttributes)
|
||||
->Then(AbstractThread::MainThread(), __func__, this,
|
||||
&SourceBuffer::AppendDataCompletedWithSuccess,
|
||||
&SourceBuffer::AppendDataErrored)
|
||||
->Track(mPendingAppend);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -733,20 +733,21 @@ TrackBuffersManager::SegmentParserLoop()
|
|||
|
||||
// 3. If the input buffer contains one or more complete coded frames, then run the coded frame processing algorithm.
|
||||
RefPtr<TrackBuffersManager> self = this;
|
||||
mProcessingRequest.Begin(CodedFrameProcessing()
|
||||
->Then(GetTaskQueue(), __func__,
|
||||
[self] (bool aNeedMoreData) {
|
||||
self->mProcessingRequest.Complete();
|
||||
if (aNeedMoreData) {
|
||||
self->NeedMoreData();
|
||||
} else {
|
||||
self->ScheduleSegmentParserLoop();
|
||||
}
|
||||
},
|
||||
[self] (const MediaResult& aRejectValue) {
|
||||
self->mProcessingRequest.Complete();
|
||||
self->RejectAppend(aRejectValue, __func__);
|
||||
}));
|
||||
CodedFrameProcessing()
|
||||
->Then(GetTaskQueue(), __func__,
|
||||
[self] (bool aNeedMoreData) {
|
||||
self->mProcessingRequest.Complete();
|
||||
if (aNeedMoreData) {
|
||||
self->NeedMoreData();
|
||||
} else {
|
||||
self->ScheduleSegmentParserLoop();
|
||||
}
|
||||
},
|
||||
[self] (const MediaResult& aRejectValue) {
|
||||
self->mProcessingRequest.Complete();
|
||||
self->RejectAppend(aRejectValue, __func__);
|
||||
})
|
||||
->Track(mProcessingRequest);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -842,11 +843,12 @@ TrackBuffersManager::ResetDemuxingState()
|
|||
RejectAppend(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
mDemuxerInitRequest.Begin(mInputDemuxer->Init()
|
||||
->Then(GetTaskQueue(), __func__,
|
||||
this,
|
||||
&TrackBuffersManager::OnDemuxerResetDone,
|
||||
&TrackBuffersManager::OnDemuxerInitFailed));
|
||||
mInputDemuxer->Init()
|
||||
->Then(GetTaskQueue(), __func__,
|
||||
this,
|
||||
&TrackBuffersManager::OnDemuxerResetDone,
|
||||
&TrackBuffersManager::OnDemuxerInitFailed)
|
||||
->Track(mDemuxerInitRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -916,11 +918,12 @@ TrackBuffersManager::InitializationSegmentReceived()
|
|||
RejectAppend(NS_ERROR_DOM_NOT_SUPPORTED_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
mDemuxerInitRequest.Begin(mInputDemuxer->Init()
|
||||
->Then(GetTaskQueue(), __func__,
|
||||
this,
|
||||
&TrackBuffersManager::OnDemuxerInitDone,
|
||||
&TrackBuffersManager::OnDemuxerInitFailed));
|
||||
mInputDemuxer->Init()
|
||||
->Then(GetTaskQueue(), __func__,
|
||||
this,
|
||||
&TrackBuffersManager::OnDemuxerInitDone,
|
||||
&TrackBuffersManager::OnDemuxerInitFailed)
|
||||
->Track(mDemuxerInitRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1200,10 +1203,11 @@ TrackBuffersManager::DoDemuxVideo()
|
|||
DoDemuxAudio();
|
||||
return;
|
||||
}
|
||||
mVideoTracks.mDemuxRequest.Begin(mVideoTracks.mDemuxer->GetSamples(-1)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&TrackBuffersManager::OnVideoDemuxCompleted,
|
||||
&TrackBuffersManager::OnVideoDemuxFailed));
|
||||
mVideoTracks.mDemuxer->GetSamples(-1)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&TrackBuffersManager::OnVideoDemuxCompleted,
|
||||
&TrackBuffersManager::OnVideoDemuxFailed)
|
||||
->Track(mVideoTracks.mDemuxRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1224,10 +1228,11 @@ TrackBuffersManager::DoDemuxAudio()
|
|||
CompleteCodedFrameProcessing();
|
||||
return;
|
||||
}
|
||||
mAudioTracks.mDemuxRequest.Begin(mAudioTracks.mDemuxer->GetSamples(-1)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&TrackBuffersManager::OnAudioDemuxCompleted,
|
||||
&TrackBuffersManager::OnAudioDemuxFailed));
|
||||
mAudioTracks.mDemuxer->GetSamples(-1)
|
||||
->Then(GetTaskQueue(), __func__, this,
|
||||
&TrackBuffersManager::OnAudioDemuxCompleted,
|
||||
&TrackBuffersManager::OnAudioDemuxFailed)
|
||||
->Track(mAudioTracks.mDemuxRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -60,10 +60,11 @@ public:
|
|||
writer->mCrypto.mSessionIds);
|
||||
|
||||
mDecrypts.Put(aSample, new DecryptPromiseRequestHolder());
|
||||
mDecrypts.Get(aSample)->Begin(mProxy->Decrypt(aSample)->Then(
|
||||
mProxy->Decrypt(aSample)->Then(
|
||||
mTaskQueue, __func__, this,
|
||||
&EMEDecryptor::Decrypted,
|
||||
&EMEDecryptor::Decrypted));
|
||||
&EMEDecryptor::Decrypted)
|
||||
->Track(*mDecrypts.Get(aSample));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -242,23 +242,23 @@ DecoderCallbackFuzzingWrapper::ScheduleOutputDelayedFrame()
|
|||
return;
|
||||
}
|
||||
RefPtr<DecoderCallbackFuzzingWrapper> self = this;
|
||||
mDelayedOutputRequest.Begin(
|
||||
mDelayedOutputTimer->WaitUntil(
|
||||
mPreviousOutput + mFrameOutputMinimumInterval,
|
||||
__func__)
|
||||
->Then(mTaskQueue, __func__,
|
||||
[self] () -> void {
|
||||
if (self->mDelayedOutputRequest.Exists()) {
|
||||
self->mDelayedOutputRequest.Complete();
|
||||
self->OutputDelayedFrame();
|
||||
}
|
||||
},
|
||||
[self] () -> void {
|
||||
if (self->mDelayedOutputRequest.Exists()) {
|
||||
self->mDelayedOutputRequest.Complete();
|
||||
self->ClearDelayedOutput();
|
||||
}
|
||||
}));
|
||||
mDelayedOutputTimer->WaitUntil(
|
||||
mPreviousOutput + mFrameOutputMinimumInterval,
|
||||
__func__)
|
||||
->Then(mTaskQueue, __func__,
|
||||
[self] () -> void {
|
||||
if (self->mDelayedOutputRequest.Exists()) {
|
||||
self->mDelayedOutputRequest.Complete();
|
||||
self->OutputDelayedFrame();
|
||||
}
|
||||
},
|
||||
[self] () -> void {
|
||||
if (self->mDelayedOutputRequest.Exists()) {
|
||||
self->mDelayedOutputRequest.Complete();
|
||||
self->ClearDelayedOutput();
|
||||
}
|
||||
})
|
||||
->Track(mDelayedOutputRequest);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -231,10 +231,11 @@ H264Converter::CreateDecoderAndInit(MediaRawData* aSample)
|
|||
// Queue the incoming sample.
|
||||
mMediaRawSamples.AppendElement(aSample);
|
||||
|
||||
mInitPromiseRequest.Begin(mDecoder->Init()
|
||||
mDecoder->Init()
|
||||
->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, this,
|
||||
&H264Converter::OnDecoderInitDone,
|
||||
&H264Converter::OnDecoderInitFailed));
|
||||
&H264Converter::OnDecoderInitFailed)
|
||||
->Track(mInitPromiseRequest);
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
return rv;
|
||||
|
|
|
@ -46,7 +46,7 @@ void EbmlComposer::GenerateHeader()
|
|||
if (mWidth > 0 && mHeight > 0) {
|
||||
writeVideoTrack(&ebml, 0x1, 0, "V_VP8",
|
||||
mWidth, mHeight,
|
||||
mDisplayWidth, mDisplayHeight, mFrameRate);
|
||||
mDisplayWidth, mDisplayHeight);
|
||||
}
|
||||
// Audio
|
||||
if (mCodecPrivateData.Length() > 0) {
|
||||
|
@ -176,19 +176,16 @@ EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame)
|
|||
|
||||
void
|
||||
EbmlComposer::SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
|
||||
uint32_t aDisplayWidth, uint32_t aDisplayHeight,
|
||||
float aFrameRate)
|
||||
uint32_t aDisplayWidth, uint32_t aDisplayHeight)
|
||||
{
|
||||
MOZ_ASSERT(aWidth > 0, "Width should > 0");
|
||||
MOZ_ASSERT(aHeight > 0, "Height should > 0");
|
||||
MOZ_ASSERT(aDisplayWidth > 0, "DisplayWidth should > 0");
|
||||
MOZ_ASSERT(aDisplayHeight > 0, "DisplayHeight should > 0");
|
||||
MOZ_ASSERT(aFrameRate > 0, "FrameRate should > 0");
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
mDisplayWidth = aDisplayWidth;
|
||||
mDisplayHeight = aDisplayHeight;
|
||||
mFrameRate = aFrameRate;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -228,7 +225,6 @@ EbmlComposer::EbmlComposer()
|
|||
, mClusterTimecode(0)
|
||||
, mWidth(0)
|
||||
, mHeight(0)
|
||||
, mFrameRate(0)
|
||||
, mSampleFreq(0)
|
||||
, mChannels(0)
|
||||
{}
|
||||
|
|
|
@ -19,8 +19,8 @@ public:
|
|||
/*
|
||||
* Assign the parameter which header required.
|
||||
*/
|
||||
void SetVideoConfig(uint32_t aWidth, uint32_t aHeight, uint32_t aDisplayWidth,
|
||||
uint32_t aDisplayHeight, float aFrameRate);
|
||||
void SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
|
||||
uint32_t aDisplayWidth, uint32_t aDisplayHeight);
|
||||
|
||||
void SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels);
|
||||
/*
|
||||
|
@ -78,7 +78,6 @@ private:
|
|||
int mHeight;
|
||||
int mDisplayWidth;
|
||||
int mDisplayHeight;
|
||||
float mFrameRate;
|
||||
// Audio configuration
|
||||
float mSampleFreq;
|
||||
int mChannels;
|
||||
|
|
|
@ -57,8 +57,7 @@ WebMWriter::SetMetadata(TrackMetadataBase* aMetadata)
|
|||
VP8Metadata* meta = static_cast<VP8Metadata*>(aMetadata);
|
||||
MOZ_ASSERT(meta, "Cannot find vp8 encoder metadata");
|
||||
mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
|
||||
meta->mDisplayWidth, meta->mDisplayHeight,
|
||||
meta->mEncodedFrameRate);
|
||||
meta->mDisplayWidth, meta->mDisplayHeight);
|
||||
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::CREATE_VIDEO_TRACK;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ public:
|
|||
int32_t mHeight;
|
||||
int32_t mDisplayWidth;
|
||||
int32_t mDisplayHeight;
|
||||
int32_t mEncodedFrameRate;
|
||||
MetadataKind GetKind() const override { return METADATA_VP8; }
|
||||
};
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ void MessagePumpDefault::Run(Delegate* delegate) {
|
|||
PROFILER_LABEL("MessagePump", "Wait",
|
||||
js::ProfileEntry::Category::OTHER);
|
||||
{
|
||||
GeckoProfilerSleepRAII profiler_sleep;
|
||||
mozilla::GeckoProfilerSleepRAII profiler_sleep;
|
||||
event_.Wait();
|
||||
}
|
||||
} else {
|
||||
|
@ -68,7 +68,7 @@ void MessagePumpDefault::Run(Delegate* delegate) {
|
|||
PROFILER_LABEL("MessagePump", "Wait",
|
||||
js::ProfileEntry::Category::OTHER);
|
||||
{
|
||||
GeckoProfilerSleepRAII profiler_sleep;
|
||||
mozilla::GeckoProfilerSleepRAII profiler_sleep;
|
||||
event_.TimedWait(delay);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -61,9 +61,7 @@ RestyleTracker::Document() const {
|
|||
|
||||
struct RestyleEnumerateData : RestyleTracker::Hints {
|
||||
RefPtr<dom::Element> mElement;
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
UniqueProfilerBacktrace mBacktrace;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline void
|
||||
|
@ -257,12 +255,10 @@ RestyleTracker::DoProcessRestyles()
|
|||
data->mRestyleHint, MarkerTracingType::START)));
|
||||
}
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
Maybe<GeckoProfilerTracingRAII> profilerRAII;
|
||||
if (profiler_feature_active("restyle")) {
|
||||
profilerRAII.emplace("Paint", "Styles", Move(data->mBacktrace));
|
||||
}
|
||||
#endif
|
||||
ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint,
|
||||
data->mRestyleHintData);
|
||||
AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
|
||||
|
@ -337,9 +333,7 @@ RestyleTracker::DoProcessRestyles()
|
|||
// We can move data since we'll be clearing mPendingRestyles after
|
||||
// we finish enumerating it.
|
||||
restyle->mRestyleHintData = Move(data->mRestyleHintData);
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
restyle->mBacktrace = Move(data->mBacktrace);
|
||||
#endif
|
||||
|
||||
#ifdef RESTYLE_LOGGING
|
||||
count++;
|
||||
|
@ -365,12 +359,10 @@ RestyleTracker::DoProcessRestyles()
|
|||
index++, count);
|
||||
LOG_RESTYLE_INDENT();
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
Maybe<GeckoProfilerTracingRAII> profilerRAII;
|
||||
if (profiler_feature_active("restyle")) {
|
||||
profilerRAII.emplace("Paint", "Styles", Move(currentRestyle->mBacktrace));
|
||||
}
|
||||
#endif
|
||||
if (isTimelineRecording) {
|
||||
timelines->AddMarkerForDocShell(docShell, Move(
|
||||
MakeUnique<RestyleTimelineMarker>(
|
||||
|
|
|
@ -22,10 +22,6 @@
|
|||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
#include "ProfilerBacktrace.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class RestyleManager;
|
||||
|
@ -128,9 +124,7 @@ public:
|
|||
// that we called AddPendingRestyle for and found the element this is
|
||||
// the RestyleData for as its nearest restyle root.
|
||||
nsTArray<RefPtr<Element>> mDescendants;
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
UniqueProfilerBacktrace mBacktrace;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -265,11 +259,9 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
|
|||
if (!existingData) {
|
||||
RestyleData* rd =
|
||||
new RestyleData(aRestyleHint, aMinChangeHint, aRestyleHintData);
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
if (profiler_feature_active("restyle")) {
|
||||
rd->mBacktrace = profiler_get_backtrace();
|
||||
}
|
||||
#endif
|
||||
mPendingRestyles.Put(aElement, rd);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ShapeUtils.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "nsCSSRendering.h"
|
||||
#include "nsRuleNode.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "SVGContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nscoord
|
||||
ShapeUtils::ComputeShapeRadius(const StyleShapeRadius aType,
|
||||
const nscoord aCenter,
|
||||
const nscoord aPosMin,
|
||||
const nscoord aPosMax)
|
||||
{
|
||||
nscoord dist1 = std::abs(aPosMin - aCenter);
|
||||
nscoord dist2 = std::abs(aPosMax - aCenter);
|
||||
nscoord length = 0;
|
||||
switch (aType) {
|
||||
case StyleShapeRadius::FarthestSide:
|
||||
length = dist1 > dist2 ? dist1 : dist2;
|
||||
break;
|
||||
case StyleShapeRadius::ClosestSide:
|
||||
length = dist1 > dist2 ? dist2 : dist1;
|
||||
break;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
nsPoint
|
||||
ShapeUtils::ComputeCircleOrEllipseCenter(StyleBasicShape* const aBasicShape,
|
||||
const nsRect& aRefBox)
|
||||
{
|
||||
nsPoint topLeft, anchor;
|
||||
nsSize size(aRefBox.Size());
|
||||
nsImageRenderer::ComputeObjectAnchorPoint(aBasicShape->GetPosition(),
|
||||
size, size,
|
||||
&topLeft, &anchor);
|
||||
return nsPoint(anchor.x + aRefBox.x, anchor.y + aRefBox.y);
|
||||
}
|
||||
|
||||
nscoord
|
||||
ShapeUtils::ComputeCircleRadius(StyleBasicShape* const aBasicShape,
|
||||
const nsPoint& aCenter,
|
||||
const nsRect& aRefBox)
|
||||
{
|
||||
const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
|
||||
MOZ_ASSERT(coords.Length() == 1, "wrong number of arguments");
|
||||
nscoord r = 0;
|
||||
if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
|
||||
const auto styleShapeRadius = coords[0].GetEnumValue<StyleShapeRadius>();
|
||||
nscoord horizontal =
|
||||
ComputeShapeRadius(styleShapeRadius, aCenter.x, aRefBox.x, aRefBox.XMost());
|
||||
nscoord vertical =
|
||||
ComputeShapeRadius(styleShapeRadius, aCenter.y, aRefBox.y, aRefBox.YMost());
|
||||
r = styleShapeRadius == StyleShapeRadius::FarthestSide
|
||||
? std::max(horizontal, vertical)
|
||||
: std::min(horizontal, vertical);
|
||||
} else {
|
||||
// We resolve percent <shape-radius> value for circle() as defined here:
|
||||
// https://drafts.csswg.org/css-shapes/#funcdef-circle
|
||||
double referenceLength =
|
||||
SVGContentUtils::ComputeNormalizedHypotenuse(aRefBox.width,
|
||||
aRefBox.height);
|
||||
r = nsRuleNode::ComputeCoordPercentCalc(coords[0],
|
||||
NSToCoordRound(referenceLength));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ShapeUtils_h
|
||||
#define mozilla_ShapeUtils_h
|
||||
|
||||
#include "nsCoord.h"
|
||||
#include "nsStyleConsts.h"
|
||||
|
||||
struct nsPoint;
|
||||
struct nsRect;
|
||||
|
||||
namespace mozilla {
|
||||
class StyleBasicShape;
|
||||
|
||||
// ShapeUtils is a namespace class containing utility functions related to
|
||||
// processing basic shapes in the CSS Shapes Module.
|
||||
// https://drafts.csswg.org/css-shapes/#basic-shape-functions
|
||||
//
|
||||
struct ShapeUtils final
|
||||
{
|
||||
// Compute the length of a keyword <shape-radius>, i.e. closest-side or
|
||||
// farthest-side, for a circle or an ellipse on a single dimension. The
|
||||
// caller needs to call for both dimensions and combine the result.
|
||||
// https://drafts.csswg.org/css-shapes/#typedef-shape-radius.
|
||||
//
|
||||
// @return The length of the radius in app units.
|
||||
static nscoord ComputeShapeRadius(const StyleShapeRadius aType,
|
||||
const nscoord aCenter,
|
||||
const nscoord aPosMin,
|
||||
const nscoord aPosMax);
|
||||
|
||||
// Compute the center of a circle or an ellipse.
|
||||
//
|
||||
// @param aRefBox The reference box of the basic shape.
|
||||
// @return The point of the center.
|
||||
static nsPoint ComputeCircleOrEllipseCenter(
|
||||
StyleBasicShape* const aBasicShape,
|
||||
const nsRect& aRefBox);
|
||||
|
||||
// Compute the radius for a circle.
|
||||
// @param aCenter the center of the circle.
|
||||
// @param aRefBox the reference box of the circle.
|
||||
// @return The length of the radius in app units.
|
||||
static nscoord ComputeCircleRadius(
|
||||
mozilla::StyleBasicShape* const aBasicShape,
|
||||
const nsPoint& aCenter, const nsRect& aRefBox);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ShapeUtils_h
|
|
@ -80,6 +80,7 @@ EXPORTS.mozilla += [
|
|||
'RestyleManagerHandleInlines.h',
|
||||
'ServoRestyleManager.h',
|
||||
'ServoRestyleManagerInlines.h',
|
||||
'ShapeUtils.h',
|
||||
'StaticPresData.h',
|
||||
]
|
||||
|
||||
|
@ -114,6 +115,7 @@ UNIFIED_SOURCES += [
|
|||
'RestyleTracker.cpp',
|
||||
'ScrollbarStyles.cpp',
|
||||
'ServoRestyleManager.cpp',
|
||||
'ShapeUtils.cpp',
|
||||
'StackArena.cpp',
|
||||
'StaticPresData.cpp',
|
||||
'TouchManager.cpp',
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsCharTraits.h"
|
||||
#include "nsDocument.h"
|
||||
#include "nsFontMetrics.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIContent.h"
|
||||
|
|
|
@ -988,9 +988,8 @@ BlockReflowInput::FlowAndPlaceFloat(nsIFrame* aFloat)
|
|||
region.BSize(wm) = std::max(region.BSize(wm),
|
||||
ContentBSize() - floatPos.B(wm));
|
||||
}
|
||||
DebugOnly<nsresult> rv = mFloatManager->AddFloat(aFloat, region, wm,
|
||||
ContainerSize());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "bad float placement");
|
||||
mFloatManager->AddFloat(aFloat, region, wm, ContainerSize());
|
||||
|
||||
// store region
|
||||
nsFloatManager::StoreRegionFor(wm, aFloat, region, ContainerSize());
|
||||
|
||||
|
|
|
@ -784,6 +784,16 @@ public:
|
|||
CHECK_WRITING_MODE(aWritingMode);
|
||||
return mPoint.y;
|
||||
}
|
||||
nscoord LineRelative(WritingMode aWritingMode,
|
||||
const nsSize& aContainerSize) const // line-axis
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
if (aWritingMode.IsBidiLTR()) {
|
||||
return I();
|
||||
}
|
||||
return (aWritingMode.IsVertical() ? aContainerSize.height
|
||||
: aContainerSize.width) - I();
|
||||
}
|
||||
|
||||
/**
|
||||
* These non-const accessors return a reference (lvalue) that can be
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "mozilla/ReflowInput.h"
|
||||
#include "mozilla/ShapeUtils.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIPresShell.h"
|
||||
|
@ -187,7 +188,7 @@ nsFloatManager::GetFlowArea(WritingMode aWM, nscoord aBCoord, nscoord aBSize,
|
|||
// There aren't any more floats that could intersect this band.
|
||||
break;
|
||||
}
|
||||
if (fi.IsEmpty()) {
|
||||
if (fi.IsEmpty(aShapeType)) {
|
||||
// For compatibility, ignore floats with empty rects, even though it
|
||||
// disagrees with the spec. (We might want to fix this in the
|
||||
// future, though.)
|
||||
|
@ -261,7 +262,7 @@ nsFloatManager::GetFlowArea(WritingMode aWM, nscoord aBCoord, nscoord aBSize,
|
|||
lineRight - lineLeft, blockSize, haveFloats);
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsFloatManager::AddFloat(nsIFrame* aFloatFrame, const LogicalRect& aMarginRect,
|
||||
WritingMode aWM, const nsSize& aContainerSize)
|
||||
{
|
||||
|
@ -290,10 +291,7 @@ nsFloatManager::AddFloat(nsIFrame* aFloatFrame, const LogicalRect& aMarginRect,
|
|||
if (thisBEnd > sideBEnd)
|
||||
sideBEnd = thisBEnd;
|
||||
|
||||
if (!mFloats.AppendElement(info))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return NS_OK;
|
||||
mFloats.AppendElement(Move(info));
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -530,6 +528,145 @@ nsFloatManager::ClearContinues(StyleClear aBreakType) const
|
|||
aBreakType == StyleClear::Right));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// BoxShapeInfo
|
||||
|
||||
nscoord
|
||||
nsFloatManager::BoxShapeInfo::LineLeft(WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const
|
||||
{
|
||||
nscoord radii[8];
|
||||
bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
|
||||
|
||||
if (!hasRadii) {
|
||||
return mShapeBoxRect.x;
|
||||
}
|
||||
|
||||
// Get the physical side for line-left since border-radii are in
|
||||
// the physical axis.
|
||||
mozilla::Side lineLeftSide =
|
||||
aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
|
||||
nscoord blockStartCornerRadiusL =
|
||||
radii[SideToHalfCorner(lineLeftSide, true, false)];
|
||||
nscoord blockStartCornerRadiusB =
|
||||
radii[SideToHalfCorner(lineLeftSide, true, true)];
|
||||
nscoord blockEndCornerRadiusL =
|
||||
radii[SideToHalfCorner(lineLeftSide, false, false)];
|
||||
nscoord blockEndCornerRadiusB =
|
||||
radii[SideToHalfCorner(lineLeftSide, false, true)];
|
||||
|
||||
if (aWM.IsLineInverted()) {
|
||||
// This happens only when aWM is vertical-lr. Need to swap blockStart
|
||||
// and blockEnd corners.
|
||||
std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
|
||||
std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
|
||||
}
|
||||
|
||||
nscoord lineLeftDiff =
|
||||
ComputeEllipseLineInterceptDiff(
|
||||
mShapeBoxRect.y, mShapeBoxRect.YMost(),
|
||||
blockStartCornerRadiusL, blockStartCornerRadiusB,
|
||||
blockEndCornerRadiusL, blockEndCornerRadiusB,
|
||||
aBStart, aBEnd);
|
||||
return mShapeBoxRect.x + lineLeftDiff;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFloatManager::BoxShapeInfo::LineRight(WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const
|
||||
{
|
||||
nscoord radii[8];
|
||||
bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
|
||||
|
||||
if (!hasRadii) {
|
||||
return mShapeBoxRect.XMost();
|
||||
}
|
||||
|
||||
// Get the physical side for line-right since border-radii are in
|
||||
// the physical axis.
|
||||
mozilla::Side lineRightSide =
|
||||
aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
|
||||
nscoord blockStartCornerRadiusL =
|
||||
radii[SideToHalfCorner(lineRightSide, false, false)];
|
||||
nscoord blockStartCornerRadiusB =
|
||||
radii[SideToHalfCorner(lineRightSide, false, true)];
|
||||
nscoord blockEndCornerRadiusL =
|
||||
radii[SideToHalfCorner(lineRightSide, true, false)];
|
||||
nscoord blockEndCornerRadiusB =
|
||||
radii[SideToHalfCorner(lineRightSide, true, true)];
|
||||
|
||||
if (aWM.IsLineInverted()) {
|
||||
// This happens only when aWM is vertical-lr. Need to swap blockStart
|
||||
// and blockEnd corners.
|
||||
std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
|
||||
std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
|
||||
}
|
||||
|
||||
nscoord lineRightDiff =
|
||||
ComputeEllipseLineInterceptDiff(
|
||||
mShapeBoxRect.y, mShapeBoxRect.YMost(),
|
||||
blockStartCornerRadiusL, blockStartCornerRadiusB,
|
||||
blockEndCornerRadiusL, blockEndCornerRadiusB,
|
||||
aBStart, aBEnd);
|
||||
return mShapeBoxRect.XMost() - lineRightDiff;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CircleShapeInfo
|
||||
|
||||
nsFloatManager::CircleShapeInfo::CircleShapeInfo(
|
||||
StyleBasicShape* const aBasicShape,
|
||||
nscoord aLineLeft,
|
||||
nscoord aBlockStart,
|
||||
const LogicalRect& aShapeBoxRect,
|
||||
WritingMode aWM,
|
||||
const nsSize& aContainerSize)
|
||||
{
|
||||
// Use physical coordinates to compute the center of the circle() since
|
||||
// the <position> keywords such as 'left', 'top', etc. are physical.
|
||||
// https://drafts.csswg.org/css-shapes-1/#funcdef-circle
|
||||
nsRect physicalShapeBoxRect =
|
||||
aShapeBoxRect.GetPhysicalRect(aWM, aContainerSize);
|
||||
nsPoint physicalCenter =
|
||||
ShapeUtils::ComputeCircleOrEllipseCenter(aBasicShape, physicalShapeBoxRect);
|
||||
mRadius =
|
||||
ShapeUtils::ComputeCircleRadius(aBasicShape, physicalCenter,
|
||||
physicalShapeBoxRect);
|
||||
|
||||
// Convert the coordinate space back to the same as FloatInfo::mRect.
|
||||
// mCenter.x is in the line-axis of the frame manager and mCenter.y are in
|
||||
// the frame manager's real block-axis.
|
||||
LogicalPoint logicalCenter(aWM, physicalCenter, aContainerSize);
|
||||
mCenter = nsPoint(logicalCenter.LineRelative(aWM, aContainerSize) + aLineLeft,
|
||||
logicalCenter.B(aWM) + aBlockStart);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFloatManager::CircleShapeInfo::LineLeft(WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const
|
||||
{
|
||||
nscoord lineLeftDiff =
|
||||
ComputeEllipseLineInterceptDiff(BStart(), BEnd(),
|
||||
mRadius, mRadius, mRadius, mRadius,
|
||||
aBStart, aBEnd);
|
||||
return mCenter.x - mRadius + lineLeftDiff;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFloatManager::CircleShapeInfo::LineRight(WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const
|
||||
{
|
||||
nscoord lineRightDiff =
|
||||
ComputeEllipseLineInterceptDiff(BStart(), BEnd(),
|
||||
mRadius, mRadius, mRadius, mRadius,
|
||||
aBStart, aBEnd);
|
||||
return mCenter.x + mRadius - lineRightDiff;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// FloatInfo
|
||||
|
||||
|
@ -548,41 +685,58 @@ nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
|
|||
|
||||
const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
|
||||
|
||||
if (shapeOutside.GetType() == StyleShapeSourceType::None) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize <shape-box>'s reference rect.
|
||||
LogicalRect rect = aMarginRect;
|
||||
|
||||
switch (shapeOutside.GetReferenceBox()) {
|
||||
case StyleShapeOutsideShapeBox::Content:
|
||||
rect.Deflate(aWM, mFrame->GetLogicalUsedPadding(aWM));
|
||||
MOZ_FALLTHROUGH;
|
||||
case StyleShapeOutsideShapeBox::Padding:
|
||||
rect.Deflate(aWM, mFrame->GetLogicalUsedBorder(aWM));
|
||||
MOZ_FALLTHROUGH;
|
||||
case StyleShapeOutsideShapeBox::Border:
|
||||
rect.Deflate(aWM, mFrame->GetLogicalUsedMargin(aWM));
|
||||
break;
|
||||
case StyleShapeOutsideShapeBox::Margin:
|
||||
// Do nothing. rect is already a margin rect.
|
||||
break;
|
||||
case StyleShapeOutsideShapeBox::NoBox:
|
||||
MOZ_ASSERT(shapeOutside.GetType() != StyleShapeSourceType::Box,
|
||||
"Box source type must have <shape-box> specified!");
|
||||
break;
|
||||
}
|
||||
|
||||
if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
|
||||
// Initialize shape-box reference rect.
|
||||
LogicalRect rect = aMarginRect;
|
||||
nsRect shapeBoxRect(rect.LineLeft(aWM, aContainerSize) + aLineLeft,
|
||||
rect.BStart(aWM) + aBlockStart,
|
||||
rect.ISize(aWM), rect.BSize(aWM));
|
||||
mShapeInfo = MakeUnique<BoxShapeInfo>(shapeBoxRect, mFrame);
|
||||
} else if (shapeOutside.GetType() == StyleShapeSourceType::Shape) {
|
||||
StyleBasicShape* const basicShape = shapeOutside.GetBasicShape();
|
||||
|
||||
switch (shapeOutside.GetReferenceBox()) {
|
||||
case StyleShapeOutsideShapeBox::Content:
|
||||
rect.Deflate(aWM, mFrame->GetLogicalUsedPadding(aWM));
|
||||
MOZ_FALLTHROUGH;
|
||||
case StyleShapeOutsideShapeBox::Padding:
|
||||
rect.Deflate(aWM, mFrame->GetLogicalUsedBorder(aWM));
|
||||
MOZ_FALLTHROUGH;
|
||||
case StyleShapeOutsideShapeBox::Border:
|
||||
rect.Deflate(aWM, mFrame->GetLogicalUsedMargin(aWM));
|
||||
break;
|
||||
case StyleShapeOutsideShapeBox::Margin:
|
||||
// Do nothing. rect is already a margin rect.
|
||||
break;
|
||||
case StyleShapeOutsideShapeBox::NoBox:
|
||||
MOZ_ASSERT_UNREACHABLE("Why don't we have a shape-box?");
|
||||
break;
|
||||
if (basicShape->GetShapeType() == StyleBasicShapeType::Circle) {
|
||||
mShapeInfo = MakeUnique<CircleShapeInfo>(basicShape, aLineLeft, aBlockStart,
|
||||
rect, aWM, aContainerSize);
|
||||
}
|
||||
|
||||
mShapeBoxRect.emplace(rect.LineLeft(aWM, aContainerSize) + aLineLeft,
|
||||
rect.BStart(aWM) + aBlockStart,
|
||||
rect.ISize(aWM), rect.BSize(aWM));
|
||||
} else if (shapeOutside.GetType() == StyleShapeSourceType::URL) {
|
||||
// Bug 1265343: Implement 'shape-image-threshold'.
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown StyleShapeSourceType!");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsFloatManager::FloatInfo::FloatInfo(const FloatInfo& aOther)
|
||||
: mFrame(aOther.mFrame)
|
||||
, mLeftBEnd(aOther.mLeftBEnd)
|
||||
, mRightBEnd(aOther.mRightBEnd)
|
||||
, mRect(aOther.mRect)
|
||||
, mShapeBoxRect(aOther.mShapeBoxRect)
|
||||
nsFloatManager::FloatInfo::FloatInfo(FloatInfo&& aOther)
|
||||
: mFrame(Move(aOther.mFrame))
|
||||
, mLeftBEnd(Move(aOther.mLeftBEnd))
|
||||
, mRightBEnd(Move(aOther.mRightBEnd))
|
||||
, mRect(Move(aOther.mRect))
|
||||
, mShapeInfo(Move(aOther.mShapeInfo))
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
|
||||
}
|
||||
|
@ -604,51 +758,14 @@ nsFloatManager::FloatInfo::LineLeft(WritingMode aWM,
|
|||
}
|
||||
|
||||
MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
|
||||
const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
|
||||
if (shapeOutside.GetType() == StyleShapeSourceType::None) {
|
||||
if (!mShapeInfo) {
|
||||
return LineLeft();
|
||||
}
|
||||
|
||||
if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
|
||||
nscoord radii[8];
|
||||
bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
|
||||
|
||||
if (!hasRadii) {
|
||||
return ShapeBoxRect().x;
|
||||
}
|
||||
|
||||
// Get the physical side for line-left since border-radii are in
|
||||
// the physical axis.
|
||||
mozilla::Side lineLeftSide =
|
||||
aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
|
||||
nscoord blockStartCornerRadiusL =
|
||||
radii[SideToHalfCorner(lineLeftSide, true, false)];
|
||||
nscoord blockStartCornerRadiusB =
|
||||
radii[SideToHalfCorner(lineLeftSide, true, true)];
|
||||
nscoord blockEndCornerRadiusL =
|
||||
radii[SideToHalfCorner(lineLeftSide, false, false)];
|
||||
nscoord blockEndCornerRadiusB =
|
||||
radii[SideToHalfCorner(lineLeftSide, false, true)];
|
||||
|
||||
if (aWM.IsLineInverted()) {
|
||||
// This happens only when aWM is vertical-lr. Need to swap blockStart
|
||||
// and blockEnd corners.
|
||||
std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
|
||||
std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
|
||||
}
|
||||
|
||||
nscoord lineLeftDiff =
|
||||
ComputeEllipseLineInterceptDiff(
|
||||
ShapeBoxRect().y, ShapeBoxRect().YMost(),
|
||||
blockStartCornerRadiusL, blockStartCornerRadiusB,
|
||||
blockEndCornerRadiusL, blockEndCornerRadiusB,
|
||||
aBStart, aBEnd);
|
||||
return ShapeBoxRect().x + lineLeftDiff;
|
||||
}
|
||||
|
||||
// XXX: Other shape source types are not implemented yet.
|
||||
|
||||
return LineLeft();
|
||||
// Clip the flow area to the margin-box because
|
||||
// https://drafts.csswg.org/css-shapes-1/#relation-to-box-model-and-float-behavior
|
||||
// says "When a shape is used to define a float area, the shape is clipped
|
||||
// to the float’s margin box."
|
||||
return std::max(LineLeft(), mShapeInfo->LineLeft(aWM, aBStart, aBEnd));
|
||||
}
|
||||
|
||||
nscoord
|
||||
|
@ -662,55 +779,59 @@ nsFloatManager::FloatInfo::LineRight(WritingMode aWM,
|
|||
}
|
||||
|
||||
MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
|
||||
const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
|
||||
if (shapeOutside.GetType() == StyleShapeSourceType::None) {
|
||||
if (!mShapeInfo) {
|
||||
return LineRight();
|
||||
}
|
||||
// Clip the flow area to the margin-box. See LineLeft().
|
||||
return std::min(LineRight(), mShapeInfo->LineRight(aWM, aBStart, aBEnd));
|
||||
}
|
||||
|
||||
if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
|
||||
nscoord radii[8];
|
||||
bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
|
||||
|
||||
if (!hasRadii) {
|
||||
return ShapeBoxRect().XMost();
|
||||
}
|
||||
|
||||
// Get the physical side for line-right since border-radii are in
|
||||
// the physical axis.
|
||||
mozilla::Side lineRightSide =
|
||||
aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
|
||||
nscoord blockStartCornerRadiusL =
|
||||
radii[SideToHalfCorner(lineRightSide, false, false)];
|
||||
nscoord blockStartCornerRadiusB =
|
||||
radii[SideToHalfCorner(lineRightSide, false, true)];
|
||||
nscoord blockEndCornerRadiusL =
|
||||
radii[SideToHalfCorner(lineRightSide, true, false)];
|
||||
nscoord blockEndCornerRadiusB =
|
||||
radii[SideToHalfCorner(lineRightSide, true, true)];
|
||||
|
||||
if (aWM.IsLineInverted()) {
|
||||
// This happens only when aWM is vertical-lr. Need to swap blockStart
|
||||
// and blockEnd corners.
|
||||
std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
|
||||
std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
|
||||
}
|
||||
|
||||
nscoord lineRightDiff =
|
||||
ComputeEllipseLineInterceptDiff(
|
||||
ShapeBoxRect().y, ShapeBoxRect().YMost(),
|
||||
blockStartCornerRadiusL, blockStartCornerRadiusB,
|
||||
blockEndCornerRadiusL, blockEndCornerRadiusB,
|
||||
aBStart, aBEnd);
|
||||
return ShapeBoxRect().XMost() - lineRightDiff;
|
||||
nscoord
|
||||
nsFloatManager::FloatInfo::BStart(ShapeType aShapeType) const
|
||||
{
|
||||
if (aShapeType == ShapeType::Margin) {
|
||||
return BStart();
|
||||
}
|
||||
|
||||
// XXX: Other shape source types are not implemented yet.
|
||||
MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
|
||||
if (!mShapeInfo) {
|
||||
return BStart();
|
||||
}
|
||||
// Clip the flow area to the margin-box. See LineLeft().
|
||||
return std::max(BStart(), mShapeInfo->BStart());
|
||||
}
|
||||
|
||||
return LineRight();
|
||||
nscoord
|
||||
nsFloatManager::FloatInfo::BEnd(ShapeType aShapeType) const
|
||||
{
|
||||
if (aShapeType == ShapeType::Margin) {
|
||||
return BEnd();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
|
||||
if (!mShapeInfo) {
|
||||
return BEnd();
|
||||
}
|
||||
// Clip the flow area to the margin-box. See LineLeft().
|
||||
return std::min(BEnd(), mShapeInfo->BEnd());
|
||||
}
|
||||
|
||||
bool
|
||||
nsFloatManager::FloatInfo::IsEmpty(ShapeType aShapeType) const
|
||||
{
|
||||
if (aShapeType == ShapeType::Margin) {
|
||||
return IsEmpty();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
|
||||
if (!mShapeInfo) {
|
||||
return IsEmpty();
|
||||
}
|
||||
return mShapeInfo->IsEmpty();
|
||||
}
|
||||
|
||||
/* static */ nscoord
|
||||
nsFloatManager::FloatInfo::ComputeEllipseLineInterceptDiff(
|
||||
nsFloatManager::ShapeInfo::ComputeEllipseLineInterceptDiff(
|
||||
const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
|
||||
const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
|
||||
const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
|
||||
|
@ -780,7 +901,7 @@ nsFloatManager::FloatInfo::ComputeEllipseLineInterceptDiff(
|
|||
}
|
||||
|
||||
/* static */ nscoord
|
||||
nsFloatManager::FloatInfo::XInterceptAtY(const nscoord aY,
|
||||
nsFloatManager::ShapeInfo::XInterceptAtY(const nscoord aY,
|
||||
const nscoord aRadiusX,
|
||||
const nscoord aRadiusY)
|
||||
{
|
||||
|
|
|
@ -10,11 +10,12 @@
|
|||
#define nsFloatManager_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsFrameList.h" // for DEBUG_FRAME_DUMP
|
||||
#include "nsIntervalSet.h"
|
||||
#include "nsPoint.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIPresShell;
|
||||
|
@ -22,6 +23,7 @@ class nsIFrame;
|
|||
class nsPresContext;
|
||||
namespace mozilla {
|
||||
struct ReflowInput;
|
||||
class StyleBasicShape;
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
|
@ -201,9 +203,9 @@ public:
|
|||
* aMarginRect is relative to the current translation. The caller
|
||||
* must ensure aMarginRect.height >= 0 and aMarginRect.width >= 0.
|
||||
*/
|
||||
nsresult AddFloat(nsIFrame* aFloatFrame,
|
||||
const mozilla::LogicalRect& aMarginRect,
|
||||
mozilla::WritingMode aWM, const nsSize& aContainerSize);
|
||||
void AddFloat(nsIFrame* aFloatFrame,
|
||||
const mozilla::LogicalRect& aMarginRect,
|
||||
mozilla::WritingMode aWM, const nsSize& aContainerSize);
|
||||
|
||||
/**
|
||||
* Notify that we tried to place a float that could not fit at all and
|
||||
|
@ -332,6 +334,101 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
// ShapeInfo is an abstract class for implementing all the shapes in CSS
|
||||
// Shapes Module. A subclass needs to override all the methods to adjust
|
||||
// the flow area with respect to its shape.
|
||||
class ShapeInfo
|
||||
{
|
||||
public:
|
||||
virtual ~ShapeInfo() {}
|
||||
|
||||
virtual nscoord LineLeft(mozilla::WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const = 0;
|
||||
virtual nscoord LineRight(mozilla::WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const = 0;
|
||||
virtual nscoord BStart() const = 0;
|
||||
virtual nscoord BEnd() const = 0;
|
||||
virtual bool IsEmpty() const = 0;
|
||||
|
||||
protected:
|
||||
// Compute the minimum line-axis difference between the bounding shape
|
||||
// box and its rounded corner within the given band (block-axis region).
|
||||
// This is used as a helper function to compute the LineRight() and
|
||||
// LineLeft(). See the picture in the implementation for an example.
|
||||
// RadiusL and RadiusB stand for radius on the line-axis and block-axis.
|
||||
//
|
||||
// Returns radius-x diff on the line-axis, or 0 if there's no rounded
|
||||
// corner within the given band.
|
||||
static nscoord ComputeEllipseLineInterceptDiff(
|
||||
const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
|
||||
const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
|
||||
const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
|
||||
const nscoord aBandBStart, const nscoord aBandBEnd);
|
||||
|
||||
static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
|
||||
const nscoord aRadiusY);
|
||||
};
|
||||
|
||||
// Implements shape-outside: <shape-box>.
|
||||
class BoxShapeInfo final : public ShapeInfo
|
||||
{
|
||||
public:
|
||||
BoxShapeInfo(const nsRect& aShapeBoxRect, nsIFrame* const aFrame)
|
||||
: mShapeBoxRect(aShapeBoxRect)
|
||||
, mFrame(aFrame)
|
||||
{
|
||||
}
|
||||
|
||||
nscoord LineLeft(mozilla::WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const override;
|
||||
nscoord LineRight(mozilla::WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const override;
|
||||
nscoord BStart() const override { return mShapeBoxRect.y; }
|
||||
nscoord BEnd() const override { return mShapeBoxRect.YMost(); }
|
||||
bool IsEmpty() const override { return mShapeBoxRect.IsEmpty(); };
|
||||
|
||||
private:
|
||||
// This is the reference box of css shape-outside if specified, which
|
||||
// implements the <shape-box> value in the CSS Shapes Module Level 1.
|
||||
// The coordinate space is the same as FloatInfo::mRect.
|
||||
const nsRect mShapeBoxRect;
|
||||
// The frame of the float.
|
||||
nsIFrame* const mFrame;
|
||||
};
|
||||
|
||||
// Implements shape-outside: circle().
|
||||
class CircleShapeInfo final : public ShapeInfo
|
||||
{
|
||||
public:
|
||||
CircleShapeInfo(mozilla::StyleBasicShape* const aBasicShape,
|
||||
nscoord aLineLeft,
|
||||
nscoord aBlockStart,
|
||||
const mozilla::LogicalRect& aShapeBoxRect,
|
||||
mozilla::WritingMode aWM,
|
||||
const nsSize& aContainerSize);
|
||||
|
||||
nscoord LineLeft(mozilla::WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const override;
|
||||
nscoord LineRight(mozilla::WritingMode aWM,
|
||||
const nscoord aBStart,
|
||||
const nscoord aBEnd) const override;
|
||||
nscoord BStart() const override { return mCenter.y - mRadius; }
|
||||
nscoord BEnd() const override { return mCenter.y + mRadius; }
|
||||
bool IsEmpty() const override { return mRadius == 0; };
|
||||
|
||||
private:
|
||||
// The position of the center of the circle. The coordinate space is the
|
||||
// same as FloatInfo::mRect.
|
||||
nsPoint mCenter;
|
||||
// The radius of the circle in app units.
|
||||
nscoord mRadius;
|
||||
};
|
||||
|
||||
struct FloatInfo {
|
||||
nsIFrame *const mFrame;
|
||||
// The lowest block-ends of left/right floats up to and including
|
||||
|
@ -350,8 +447,6 @@ private:
|
|||
nscoord BSize() const { return mRect.height; }
|
||||
bool IsEmpty() const { return mRect.IsEmpty(); }
|
||||
|
||||
nsRect ShapeBoxRect() const { return mShapeBoxRect.valueOr(mRect); }
|
||||
|
||||
// aBStart and aBEnd are the starting and ending coordinate of a band.
|
||||
// LineLeft() and LineRight() return the innermost line-left extent and
|
||||
// line-right extent within the given band, respectively.
|
||||
|
@ -359,35 +454,12 @@ private:
|
|||
const nscoord aBStart, const nscoord aBEnd) const;
|
||||
nscoord LineRight(mozilla::WritingMode aWM, ShapeType aShapeType,
|
||||
const nscoord aBStart, const nscoord aBEnd) const;
|
||||
|
||||
nscoord BStart(ShapeType aShapeType) const
|
||||
{
|
||||
return aShapeType == ShapeType::Margin ? BStart() : ShapeBoxRect().y;
|
||||
}
|
||||
nscoord BEnd(ShapeType aShapeType) const
|
||||
{
|
||||
return aShapeType == ShapeType::Margin ? BEnd() : ShapeBoxRect().YMost();
|
||||
}
|
||||
|
||||
// Compute the minimum line-axis difference between the bounding shape
|
||||
// box and its rounded corner within the given band (block-axis region).
|
||||
// This is used as a helper function to compute the LineRight() and
|
||||
// LineLeft(). See the picture in the implementation for an example.
|
||||
// RadiusL and RadiusB stand for radius on the line-axis and block-axis.
|
||||
//
|
||||
// Returns radius-x diff on the line-axis, or 0 if there's no rounded
|
||||
// corner within the given band.
|
||||
static nscoord ComputeEllipseLineInterceptDiff(
|
||||
const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
|
||||
const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
|
||||
const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
|
||||
const nscoord aBandBStart, const nscoord aBandBEnd);
|
||||
|
||||
static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
|
||||
const nscoord aRadiusY);
|
||||
nscoord BStart(ShapeType aShapeType) const;
|
||||
nscoord BEnd(ShapeType aShapeType) const;
|
||||
bool IsEmpty(ShapeType aShapeType) const;
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
FloatInfo(const FloatInfo& aOther);
|
||||
FloatInfo(FloatInfo&& aOther);
|
||||
~FloatInfo();
|
||||
#endif
|
||||
|
||||
|
@ -398,10 +470,9 @@ private:
|
|||
// the line-relative axis of the frame manager and its block
|
||||
// coordinates are in the frame manager's real block direction.
|
||||
nsRect mRect;
|
||||
// This is the reference box of css shape-outside if specified, which
|
||||
// implements the <shape-box> value in the CSS Shapes Module Level 1.
|
||||
// The coordinate setup is the same as mRect.
|
||||
mozilla::Maybe<nsRect> mShapeBoxRect;
|
||||
// Pointer to a concrete subclass of ShapeInfo or null, which means that
|
||||
// there is no shape-outside.
|
||||
mozilla::UniquePtr<ShapeInfo> mShapeInfo;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<style>
|
||||
span {color: red}
|
||||
|
@ -9,7 +9,8 @@
|
|||
</head>
|
||||
|
||||
<body onload='document.getElementById("one").setAttribute("type", "checkbox");
|
||||
document.getElementById("two").setAttribute("type", "checkbox");'>
|
||||
document.getElementById("two").setAttribute("type", "checkbox");
|
||||
document.documentElement.removeAttribute("class");'>
|
||||
<div>
|
||||
<input type="text" id="one" checked="checked"/>
|
||||
<span>Should be no red </span>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
|
||||
default-preferences pref(dom.forms.datetime,true)
|
||||
|
||||
# not valid on Android/B2G where type=time looks like type=text
|
||||
# not valid on Android where type=time looks like type=text
|
||||
# == time-simple-unthemed.html time-simple-unthemed.html
|
||||
# == time-large-font.html time-large-font.html
|
||||
# == time-width-height.html time-width-height.html
|
||||
# == time-border.html time-border.html
|
||||
# only valid on Android/B2G where type=number looks the same as type=text
|
||||
# only valid on Android where type=number looks the same as type=text
|
||||
# == time-simple-unthemed.html time-simple-unthemed.html
|
||||
|
||||
# type change
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
default-preferences pref(dom.forms.datetime,true)
|
||||
|
||||
# not valid on Android/B2G where type=time looks like type=text
|
||||
skip-if(Android||B2G||Mulet) != time-simple-unthemed.html time-simple-unthemed-ref.html
|
||||
skip-if(Android||B2G||Mulet) != time-large-font.html time-basic.html
|
||||
skip-if(Android||B2G||Mulet) != time-width-height.html time-basic.html
|
||||
skip-if(Android||B2G||Mulet) != time-border.html time-basic.html
|
||||
# only valid on Android/B2G where type=number looks the same as type=text
|
||||
skip-if(!Android&&!B2G&&!Mulet) == time-simple-unthemed.html time-simple-unthemed-ref.html
|
||||
# not valid on Android where type=time looks like type=text
|
||||
skip-if(Android) != time-simple-unthemed.html time-simple-unthemed-ref.html
|
||||
skip-if(Android) != time-large-font.html time-basic.html
|
||||
skip-if(Android) != time-width-height.html time-basic.html
|
||||
skip-if(Android) != time-border.html time-basic.html
|
||||
# only valid on Android where type=number looks the same as type=text
|
||||
skip-if(!Android) == time-simple-unthemed.html time-simple-unthemed-ref.html
|
||||
|
||||
# type change
|
||||
skip-if(Android||B2G||Mulet) == to-time-from-other-type-unthemed.html time-simple-unthemed.html
|
||||
skip-if(Android||B2G||Mulet) == from-time-to-other-type-unthemed.html from-time-to-other-type-unthemed-ref.html
|
||||
skip-if(Android) == to-time-from-other-type-unthemed.html time-simple-unthemed.html
|
||||
skip-if(Android) == from-time-to-other-type-unthemed.html from-time-to-other-type-unthemed-ref.html
|
||||
|
|
|
@ -53,7 +53,9 @@ include ruby/reftest.list
|
|||
include selectors4/reftest.list
|
||||
|
||||
# Shapes Level 1
|
||||
include shapes1/reftest.list
|
||||
# Bug 1300355: Skip shapes reftests to prevent frequent intermittent failures
|
||||
# on Win7 debug.
|
||||
skip-if(winWidget&&isDebugBuild) include shapes1/reftest.list
|
||||
|
||||
# Text Level 3
|
||||
# In Bug 1316482, we've added a large number of tests in this folder, which
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
default-preferences pref(layout.css.shape-outside.enabled,true)
|
||||
default-preferences pref(layout.css.shape-outside.enabled,true) pref(layout.css.clip-path-shapes.enabled,true)
|
||||
|
||||
# <shape-box> only
|
||||
== shape-outside-margin-box-001.html shape-outside-margin-box-001-ref.html
|
||||
|
@ -35,3 +35,29 @@ fails == shape-outside-border-box-border-radius-004.html shape-outside-border-bo
|
|||
== shape-outside-padding-box-border-radius-002.html shape-outside-padding-box-border-radius-002-ref.html
|
||||
== shape-outside-content-box-border-radius-001.html shape-outside-content-box-border-radius-001-ref.html
|
||||
== shape-outside-content-box-border-radius-002.html shape-outside-content-box-border-radius-002-ref.html
|
||||
|
||||
# Basic shape: circle()
|
||||
== shape-outside-circle-001.html shape-outside-circle-001-ref.html
|
||||
== shape-outside-circle-002.html shape-outside-circle-002-ref.html
|
||||
== shape-outside-circle-003.html shape-outside-circle-003-ref.html
|
||||
== shape-outside-circle-004.html shape-outside-circle-004-ref.html
|
||||
== shape-outside-circle-005.html shape-outside-circle-005-ref.html
|
||||
== shape-outside-circle-006.html shape-outside-circle-005-ref.html
|
||||
== shape-outside-circle-007.html shape-outside-circle-005-ref.html
|
||||
== shape-outside-circle-008.html shape-outside-circle-008-ref.html
|
||||
== shape-outside-circle-009.html shape-outside-circle-008-ref.html
|
||||
== shape-outside-circle-010.html shape-outside-circle-010-ref.html
|
||||
== shape-outside-circle-011.html shape-outside-circle-011-ref.html
|
||||
== shape-outside-circle-012.html shape-outside-circle-011-ref.html
|
||||
== shape-outside-circle-013.html shape-outside-circle-011-ref.html
|
||||
== shape-outside-circle-014.html shape-outside-circle-014-ref.html
|
||||
== shape-outside-circle-015.html shape-outside-circle-014-ref.html
|
||||
== shape-outside-circle-016.html shape-outside-circle-016-ref.html
|
||||
== shape-outside-circle-017.html shape-outside-circle-017-ref.html
|
||||
== shape-outside-circle-018.html shape-outside-circle-018-ref.html
|
||||
== shape-outside-circle-019.html shape-outside-circle-019-ref.html
|
||||
== shape-outside-circle-020.html shape-outside-circle-020-ref.html
|
||||
== shape-outside-circle-021.html shape-outside-circle-021-ref.html
|
||||
== shape-outside-circle-022.html shape-outside-circle-022-ref.html
|
||||
== shape-outside-circle-023.html shape-outside-circle-023-ref.html
|
||||
== shape-outside-circle-024.html shape-outside-circle-024-ref.html
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(50% at left top) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at left top);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 36px; top: 0px; left: 60px;"></div>
|
||||
<div class="box" style="height: 12px; top: 36px; left: 48px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px; top: 48px; left: 36px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="height: 60px; top: 60px; left: 0px;"></div> <!-- Fill the space between two floats -->
|
||||
<div class="box" style="height: 36px; top: 120px; left: 60px;"></div>
|
||||
<div class="box" style="height: 12px; top: 156px; left: 48px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px; top: 168px; left: 36px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(50% at left top)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-001-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(50% at left top) value.">
|
||||
<style>
|
||||
.container {
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(50% at left top);
|
||||
clip-path: circle(50% at left top);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(50% at right bottom) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at right bottom);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="height: 60px; top: 0px; left: 0px;"></div> <!-- Fill the space above the first float -->
|
||||
<div class="box" style="height: 36px; top: 60px; left: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 96px; left: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 108px; left: 120px;"></div>
|
||||
<div class="long box" style="height: 60px; top: 120px; left: 0px;"></div> <!-- Fill the space between two floats -->
|
||||
<div class="box" style="height: 36px; top: 180px; left: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 216px; left: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 228px; left: 120px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(50% at right bottom)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-002-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(50% at right bottom) value.">
|
||||
<style>
|
||||
.container {
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(50% at right bottom);
|
||||
clip-path: circle(50% at right bottom);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="height: 60px;"></div> <!-- Fill the space above the first float -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(50% at right top) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at right top);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 36px; top: 0px; right: 60px;"></div>
|
||||
<div class="box" style="height: 12px; top: 36px; right: 48px;"></div>
|
||||
<div class="box" style="height: 12px; top: 48px; right: 36px;"></div>
|
||||
<div class="long box" style="height: 60px; top: 60px; right: 0px;"></div> <!-- Fill the space between two floats -->
|
||||
<div class="box" style="height: 36px; top: 120px; right: 60px;"></div>
|
||||
<div class="box" style="height: 12px; top: 156px; right: 48px;"></div>
|
||||
<div class="box" style="height: 12px; top: 168px; right: 36px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(50% at right top)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-003-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(50% at right top) value.">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(50% at right top);
|
||||
clip-path: circle(50% at right top);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(50% at left bottom) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at left bottom);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="height: 60px; top: 0px; right: 0px;"></div> <!-- Fill the space above the first float -->
|
||||
<div class="box" style="height: 36px; top: 60px; right: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 96px; right: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 108px; right: 120px;"></div>
|
||||
<div class="long box" style="height: 60px; top: 120px; right: 0px;"></div> <!-- Fill the space between two floats -->
|
||||
<div class="box" style="height: 36px; top: 180px; right: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 216px; right: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 228px; right: 120px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(50% at left bottom)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-004-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(50% at left bottom) value.">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(50% at left bottom);
|
||||
clip-path: circle(50% at left bottom);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
width: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="height: 60px;"></div> <!-- Fill the space above the first float -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="long box" style="height: 60px;"></div> <!-- Fill the space between two floats -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle() reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle();
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px; top: 0px; left: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px; top: 12px; left: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 36px; top: 24px; left: 120px;"></div>
|
||||
<div class="box" style="height: 36px; top: 60px; left: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 96px; left: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px; top: 108px; left: 96px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle()</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-005-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle() value.">
|
||||
<style>
|
||||
.container {
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle();
|
||||
clip-path: circle();
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(closest-side at center) border-box</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-005-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(closest-side at center) border-box value.">
|
||||
<style>
|
||||
.container {
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(closest-side at center) border-box;
|
||||
clip-path: circle(closest-side at center) border-box;
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-right: 10px; /* Not affect layout of the boxes */
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(farthest-side at center)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-005-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(farthest-side at center) value.">
|
||||
<style>
|
||||
.container {
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(farthest-side at center);
|
||||
clip-path: circle(farthest-side at center);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(0%) border-box reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(0%) border-box;
|
||||
box-sizing: content-box;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin: 10px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px; top: 0px; left: 0px;"></div>
|
||||
<div class="box" style="height: 12px; top: 12px; left: 0px;"></div>
|
||||
<div class="box" style="height: 36px; top: 24px; left: 0px;"></div>
|
||||
<div class="box" style="height: 36px; top: 60px; left: 0px;"></div>
|
||||
<div class="box" style="height: 12px; top: 96px; left: 0px;"></div>
|
||||
<div class="box" style="height: 12px; top: 108px; left: 0px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(0%) border-box</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-008-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the left float shape defines an empty float area by the basic shape circle(0%) border-box value.">
|
||||
<style>
|
||||
.container {
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(0%) border-box;
|
||||
clip-path: circle(0%) border-box;
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin: 10px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(closest-side at left center) border-box</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-008-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the left float shape defines an empty float area by the basic shape circle(closest-side at left center) border-box value.">
|
||||
<style>
|
||||
.container {
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(closest-side at left center) border-box;
|
||||
clip-path: circle(closest-side at left center) border-box;
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin: 10px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(100%) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(100%);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px; top: 0px; left: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 12px; left: 120px;"></div>
|
||||
<div class="box" style="height: 36px; top: 24px; left: 120px;"></div>
|
||||
<div class="box" style="height: 36px; top: 60px; left: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 96px; left: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 108px; left: 120px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float left, circle(100%)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-010-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the basic shape circle(100%) value.">
|
||||
<style>
|
||||
.container {
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(100%);
|
||||
clip-path: circle(100%); /* Rendered as a rectangle */
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle() reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle();
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px; top: 0px; right: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px; top: 12px; right: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 36px; top: 24px; right: 120px;"></div>
|
||||
<div class="box" style="height: 36px; top: 60px; right: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 96px; right: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px; top: 108px; right: 96px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle()</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-011-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle() value.">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle();
|
||||
clip-path: circle();
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(closest-side at center) border-box</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-011-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(closest-side at center) border-box value.">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(closest-side at center) border-box;
|
||||
clip-path: circle(closest-side at center) border-box;
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-left: 10px; /* Not affect layout of the boxes */
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(farthest-side at center)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-011-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(farthest-side at center) value.">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(farthest-side at center);
|
||||
clip-path: circle(farthest-side at center);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="height: 12px;"></div> <!-- Box at corner -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(0%) border-box reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(0%) border-box;
|
||||
box-sizing: content-box;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin: 10px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px; top: 0px; right: 0px;"></div>
|
||||
<div class="box" style="height: 12px; top: 12px; right: 0px;"></div>
|
||||
<div class="box" style="height: 36px; top: 24px; right: 0px;"></div>
|
||||
<div class="box" style="height: 36px; top: 60px; right: 0px;"></div>
|
||||
<div class="box" style="height: 12px; top: 96px; right: 0px;"></div>
|
||||
<div class="box" style="height: 12px; top: 108px; right: 0px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(0%) border-box</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-014-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the right float shape defines an empty float area by the basic shape circle(0%) border-box value.">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(0%) border-box;
|
||||
clip-path: circle(0%) border-box;
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin: 10px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(closest-side at right center) border-box</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-014-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the right float shape defines an empty float area by the basic shape circle(closest-side at right center) border-box value.">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(closest-side at right center) border-box;
|
||||
clip-path: circle(closest-side at right center) border-box;
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin: 10px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(100%) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(100%);
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px; top: 0px; right: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 12px; right: 120px;"></div>
|
||||
<div class="box" style="height: 36px; top: 24px; right: 120px;"></div>
|
||||
<div class="box" style="height: 36px; top: 60px; right: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 96px; right: 120px;"></div>
|
||||
<div class="box" style="height: 12px; top: 108px; right: 120px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: float right, circle(100%)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-016-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the basic shape circle(100%) value.">
|
||||
<style>
|
||||
.container {
|
||||
direction: rtl;
|
||||
width: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(100%);
|
||||
clip-path: circle(100%); /* Rendered as a rectangle */
|
||||
box-sizing: content-box;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 36px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
<div class="box" style="height: 12px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: vertical-rl, float left, circle(50% at left 40px top 40px) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: vertical-rl;
|
||||
position: absolute;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at left 40px top 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-start: 20px;
|
||||
margin-block-end: 28px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: vertical-rl, float left, circle(50% at left 40px top 40px)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-017-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by circle(50% at left 40px top 40px) value under vertical-rl writing-mode.">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: vertical-rl;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(50% at left 40px top 40px) border-box;
|
||||
clip-path: circle(50% at left 40px top 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: vertical-rl, float right, circle(50% at left 40px bottom 40px) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: vertical-rl;
|
||||
direction: rtl;
|
||||
position: absolute;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at left 40px bottom 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-start: 20px;
|
||||
margin-block-end: 28px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: vertical-rl, float right, circle(50% at left 40px bottom 40px)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-018-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at left 40px bottom 40px) value under vertical-rl writing-mode.">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: vertical-rl;
|
||||
direction: rtl;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(50% at left 40px bottom 40px) border-box;
|
||||
clip-path: circle(50% at left 40px bottom 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: vertical-lr, float left, circle(50% at right 40px top 40px) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: vertical-lr;
|
||||
position: absolute;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at right 40px top 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-start: 20px;
|
||||
margin-block-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: vertical-lr, float left, circle(50% at right 40px top 40px)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-019-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at right 40px top 40px) value under vertical-lr writing-mode.">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: vertical-lr;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(50% at right 40px top 40px) border-box;
|
||||
clip-path: circle(50% at right 40px top 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: vertical-lr, float right, circle(50% at right 40px bottom 40px) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: vertical-lr;
|
||||
direction: rtl;
|
||||
position: absolute;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at right 40px bottom 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-start: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: vertical-lr, float right, circle(50% at right 40px bottom 40px)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-020-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at right 40px bottom 40px) value under vertical-lr writing-mode.">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: vertical-lr;
|
||||
direction: rtl;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(50% at right 40px bottom 40px) border-box;
|
||||
clip-path: circle(50% at right 40px bottom 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: sideways-lr, float left, circle(50% at right 40px bottom 40px) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: sideways-lr;
|
||||
position: absolute;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at right 40px bottom 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-start: 20px;
|
||||
margin-block-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: sideways-lr, float left, circle(50% at right 40px bottom 40px)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-021-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the left float shape defined by circle(50% at right 40px bottom 40px) value under sideways-lr writing-mode.">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: sideways-lr;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
shape-outside: circle(50% at right 40px bottom 40px) border-box;
|
||||
clip-path: circle(50% at right 40px bottom 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: sideways-lr, float right, circle(50% at right 40px top 40px) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: sideways-lr;
|
||||
direction: rtl;
|
||||
position: absolute;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at right 40px top 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-start: 20px;
|
||||
margin-block-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: sideways-lr, float right, circle(50% at right 40px top 40px)</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
|
||||
<link rel="match" href="shape-outside-circle-022-ref.html">
|
||||
<meta name="flags" content="">
|
||||
<meta name="assert" content="Test the boxes are wrapping around the right float shape defined by circle(50% at right 40px top 40px) value under sideways-lr writing-mode.">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: sideways-lr;
|
||||
direction: rtl;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: right;
|
||||
shape-outside: circle(50% at right 40px top 40px) border-box;
|
||||
clip-path: circle(50% at right 40px top 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 36px;"></div>
|
||||
<div class="box" style="block-size: 12px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Shape Test: horizontal-tb, float left, circle(50% at left 40px bottom 40px) reference</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
.container {
|
||||
writing-mode: horizontal-tb;
|
||||
position: absolute;
|
||||
inline-size: 200px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.shape {
|
||||
float: left;
|
||||
/* Omit shape-outside */
|
||||
clip-path: circle(50% at left 40px bottom 40px) border-box;
|
||||
box-sizing: content-box;
|
||||
block-size: 40px;
|
||||
inline-size: 40px;
|
||||
padding: 20px;
|
||||
border: 20px solid lightgreen;
|
||||
margin-inline-start: 20px;
|
||||
margin-inline-start: 20px;
|
||||
margin-block-end: 20px;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
inline-size: 60px;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.long {
|
||||
inline-size: 200px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="container">
|
||||
<div class="shape"></div>
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 0px; offset-inline-start: 0;"></div> <!-- Fill the border area due to the circle shifted -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 20px; offset-inline-start: 96px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 32px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 44px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 36px; offset-block-start: 80px; offset-inline-start: 120px;"></div>
|
||||
<div class="box" style="block-size: 12px; offset-block-start: 116px; offset-inline-start: 108px;"></div> <!-- Box at corner -->
|
||||
<div class="long box" style="block-size: 20px; offset-block-start: 128px; offset-inline-start: 0;"></div>
|
||||
</body>
|
||||
</html>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче