Merge autoland to central, a=merge

MozReview-Commit-ID: Ano2O7fFKEW
This commit is contained in:
Wes Kocher 2017-01-13 15:28:13 -08:00
Родитель ef80e5ccca 79791a2cff
Коммит 8a82c900f8
350 изменённых файлов: 5630 добавлений и 4748 удалений

Просмотреть файл

@ -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

55
layout/base/ShapeUtils.h Normal file
Просмотреть файл

@ -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 floats 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>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше