зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
1e1fdc2b3d
|
@ -121,21 +121,16 @@ this.ShieldPreferences = {
|
|||
viewStudies.classList.add("learnMore", "text-link");
|
||||
hContainer.appendChild(viewStudies);
|
||||
|
||||
const optOutPref = doc.createElementNS(XUL_NS, "preference");
|
||||
optOutPref.setAttribute("id", OPT_OUT_STUDIES_ENABLED_PREF);
|
||||
optOutPref.setAttribute("name", OPT_OUT_STUDIES_ENABLED_PREF);
|
||||
optOutPref.setAttribute("type", "bool");
|
||||
|
||||
// Preference instances for prefs that we need to monitor while the page is open.
|
||||
doc.defaultView.Preferences.add({ id: OPT_OUT_STUDIES_ENABLED_PREF, type: "bool" });
|
||||
|
||||
// Weirdly, FHR doesn't have a <preference> element on the page, so we create it.
|
||||
// Weirdly, FHR doesn't have a Preference instance on the page, so we create it.
|
||||
const fhrPref = doc.defaultView.Preferences.add({ id: FHR_UPLOAD_ENABLED_PREF, type: "bool" });
|
||||
fhrPref.on("change", function(event) {
|
||||
// Avoid reference to the document directly, to avoid leaks.
|
||||
const eventTargetCheckbox = event.target.ownerDocument.getElementById("optOutStudiesEnabled");
|
||||
eventTargetCheckbox.disabled = !Services.prefs.getBoolPref(FHR_UPLOAD_ENABLED_PREF);
|
||||
});
|
||||
function onChangeFHRPref(event) {
|
||||
checkbox.disabled = !Services.prefs.getBoolPref(FHR_UPLOAD_ENABLED_PREF);
|
||||
}
|
||||
fhrPref.on("change", onChangeFHRPref);
|
||||
doc.defaultView.addEventListener("unload", () => fhrPref.off("change", onChangeFHRPref), { once: true });
|
||||
|
||||
// Actually inject the elements we've created.
|
||||
const parent = doc.getElementById("submitHealthReportBox").closest("description");
|
||||
|
|
|
@ -171,9 +171,11 @@ decorate_task(
|
|||
await BrowserTestUtils.waitForLocationChange(gBrowser);
|
||||
|
||||
is(
|
||||
browser.currentURI.spec,
|
||||
gBrowser.currentURI.spec,
|
||||
"about:studies",
|
||||
"Clicking the view studies link opens about:studies."
|
||||
"Clicking the view studies link opens about:studies in a new tab."
|
||||
);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -39,7 +39,6 @@ XPIDL_SOURCES += [
|
|||
'nsCDefaultURIFixup.idl',
|
||||
'nsIClipboardCommands.idl',
|
||||
'nsIContentViewer.idl',
|
||||
'nsIContentViewerContainer.idl',
|
||||
'nsIContentViewerEdit.idl',
|
||||
'nsIDocCharset.idl',
|
||||
'nsIDocShell.idl',
|
||||
|
|
|
@ -513,7 +513,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell)
|
|||
NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
|
||||
NS_INTERFACE_MAP_ENTRY(nsILoadContext)
|
||||
|
@ -6856,11 +6855,7 @@ nsDocShell::RefreshURIFromQueue()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsDocShell::nsIContentViewerContainer
|
||||
//*****************************************************************************
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsDocShell::Embed(nsIContentViewer* aContentViewer,
|
||||
const char* aCommand, nsISupports* aExtraInfo)
|
||||
{
|
||||
|
@ -6923,12 +6918,6 @@ nsDocShell::Embed(nsIContentViewer* aContentViewer,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetIsPrinting(bool aIsPrinting)
|
||||
{
|
||||
mIsPrintingOrPP = aIsPrinting;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsDocShell::nsIWebProgressListener
|
||||
|
@ -13857,6 +13846,13 @@ nsDocShell::StopDocumentLoad(void)
|
|||
return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetIsPrinting(bool aIsPrinting)
|
||||
{
|
||||
mIsPrintingOrPP = aIsPrinting;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
|
||||
{
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "nsIAuthPromptProvider.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIClipboardCommands.h"
|
||||
#include "nsIContentViewerContainer.h"
|
||||
#include "nsIDeprecationWarner.h"
|
||||
#include "nsIDocCharset.h"
|
||||
#include "nsIDocShell.h"
|
||||
|
@ -127,7 +126,6 @@ class nsDocShell final
|
|||
, public nsIScrollable
|
||||
, public nsITextScroll
|
||||
, public nsIDocCharset
|
||||
, public nsIContentViewerContainer
|
||||
, public nsIRefreshURI
|
||||
, public nsIWebProgressListener
|
||||
, public nsIWebPageDescriptor
|
||||
|
@ -183,7 +181,6 @@ public:
|
|||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_NSIREFRESHURI
|
||||
NS_DECL_NSICONTENTVIEWERCONTAINER
|
||||
NS_DECL_NSIWEBPAGEDESCRIPTOR
|
||||
NS_DECL_NSIAUTHPROMPTPROVIDER
|
||||
NS_DECL_NSICLIPBOARDCOMMANDS
|
||||
|
@ -869,6 +866,8 @@ private: // member functions
|
|||
nsresult EnsureFind();
|
||||
nsresult EnsureCommandHandler();
|
||||
nsresult RefreshURIFromQueue();
|
||||
nsresult Embed(nsIContentViewer* aContentViewer,
|
||||
const char* aCommand, nsISupports* aExtraInfo);
|
||||
nsresult GetEldestPresContext(nsPresContext** aPresContext);
|
||||
nsresult CheckLoadingPermissions();
|
||||
nsresult PersistLayoutHistoryState();
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 "nsISupports.idl"
|
||||
|
||||
interface nsIContentViewer;
|
||||
|
||||
[scriptable, uuid(ea2ce7a0-5c3d-11d4-90c2-0050041caf44)]
|
||||
interface nsIContentViewerContainer : nsISupports {
|
||||
void embed(in nsIContentViewer aDocViewer, in string aCommand, in nsISupports aExtraInfo);
|
||||
|
||||
/**
|
||||
* Allows nsPrintJob to make this call on an internal interface to the
|
||||
* DocShell.
|
||||
*/
|
||||
void setIsPrinting(in boolean aIsPrinting);
|
||||
};
|
|
@ -655,6 +655,12 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
**/
|
||||
attribute boolean isOffScreenBrowser;
|
||||
|
||||
/**
|
||||
* Allows nsDocumentViewer to tell the top-level same-type docshell that
|
||||
* one of the documents under it is printing.
|
||||
*/
|
||||
void setIsPrinting(in boolean aIsPrinting);
|
||||
|
||||
/**
|
||||
* If the current content viewer isn't initialized for print preview,
|
||||
* it is replaced with one which is and to which an about:blank document
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "nsIIOService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIPrivateBrowsingChannel.h"
|
||||
#include "nsIContentViewerContainer.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsDocShellLoadTypes.h"
|
||||
|
|
|
@ -473,12 +473,6 @@ cubeb* GetCubebContextUnlocked()
|
|||
NS_WARNING_ASSERTION(rv == CUBEB_OK, "Could not get a cubeb context.");
|
||||
sCubebState = (rv == CUBEB_OK) ? CubebState::Initialized : CubebState::Uninitialized;
|
||||
|
||||
if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
|
||||
cubeb_set_log_callback(CUBEB_LOG_VERBOSE, CubebLogCallback);
|
||||
} else if (MOZ_LOG_TEST(gCubebLog, LogLevel::Error)) {
|
||||
cubeb_set_log_callback(CUBEB_LOG_NORMAL, CubebLogCallback);
|
||||
}
|
||||
|
||||
return sCubebContext;
|
||||
}
|
||||
|
||||
|
@ -550,10 +544,15 @@ void InitLibrary()
|
|||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
|
||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
|
||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_SANDBOX);
|
||||
if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
|
||||
cubeb_set_log_callback(CUBEB_LOG_VERBOSE, CubebLogCallback);
|
||||
} else if (MOZ_LOG_TEST(gCubebLog, LogLevel::Error)) {
|
||||
cubeb_set_log_callback(CUBEB_LOG_NORMAL, CubebLogCallback);
|
||||
}
|
||||
// We don't want to call the callback on startup, because the pref is the
|
||||
// empty string by default ("", which means "logging disabled"). Because the
|
||||
// logging can be enabled via environment variables (MOZ_LOG="module:5"),
|
||||
// calling this callback on init would immediately re-disble the logging.
|
||||
// calling this callback on init would immediately re-disable the logging.
|
||||
Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LOGGING_LEVEL);
|
||||
#ifndef MOZ_WIDGET_ANDROID
|
||||
AbstractThread::MainThread()->Dispatch(
|
||||
|
|
|
@ -65,6 +65,8 @@
|
|||
|
||||
using JS::SourceBufferHolder;
|
||||
|
||||
using mozilla::Telemetry::LABELS_DOM_SCRIPT_PRELOAD_RESULT;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -180,6 +182,10 @@ ScriptLoader::~ScriptLoader()
|
|||
for (uint32_t j = 0; j < mPendingChildLoaders.Length(); ++j) {
|
||||
mPendingChildLoaders[j]->RemoveParserBlockingScriptExecutionBlocker();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mPreloads.Length(); i++) {
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::NotUsed);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect telemtry data about the cache information, and the kind of source
|
||||
|
@ -195,6 +201,13 @@ CollectScriptTelemetry(nsIIncrementalStreamLoader* aLoader,
|
|||
return;
|
||||
}
|
||||
|
||||
// Report the script kind.
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_KIND::ModuleScript);
|
||||
} else {
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_KIND::ClassicScript);
|
||||
}
|
||||
|
||||
// Report the type of source, as well as the size of the source.
|
||||
if (aRequest->IsLoadingSource()) {
|
||||
if (aRequest->mIsInline) {
|
||||
|
@ -1316,6 +1329,7 @@ ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
|
|||
// Probably plans have changed; even though the preload was allowed seems
|
||||
// like the actual load is not; let's cancel the preload request.
|
||||
request->Cancel();
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::RejectedByPolicy);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1326,6 +1340,8 @@ ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
|
|||
// update them here.
|
||||
request->SetScriptMode(aElement->GetScriptDeferred(),
|
||||
aElement->GetScriptAsync());
|
||||
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::Used);
|
||||
} else {
|
||||
// No usable preload found.
|
||||
|
||||
|
@ -1581,6 +1597,7 @@ ScriptLoader::LookupPreloadRequest(nsIScriptElement* aElement,
|
|||
mDocument->GetReferrerPolicy() != request->mReferrerPolicy ||
|
||||
aScriptKind != request->mKind) {
|
||||
// Drop the preload.
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::RequestMismatch);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2957,6 +2974,7 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult)
|
|||
mCurrentParserInsertedScript = oldParserInsertedScript;
|
||||
} else {
|
||||
mPreloads.RemoveElement(aRequest, PreloadRequestComparator());
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::LoadError);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "nsIXMLContentSink.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIContentViewerContainer.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsHTMLParts.h"
|
||||
|
|
|
@ -242,9 +242,9 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
copy.CopyBuffer();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
|
||||
}
|
||||
} else {
|
||||
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
|
||||
}
|
||||
} else {
|
||||
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
|
||||
|
@ -336,12 +336,6 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|||
mTile.Flip();
|
||||
UnlockTile(mTile);
|
||||
|
||||
if (backBuffer->HasIntermediateBuffer()) {
|
||||
// If our new buffer has an internal buffer, we don't want to keep another
|
||||
// TextureClient around unnecessarily, so discard the back-buffer.
|
||||
mTile.DiscardBackBuffer();
|
||||
}
|
||||
|
||||
mValidRegion = aNewValidRegion;
|
||||
mLastPaintSurfaceMode = mode;
|
||||
mLastPaintContentType = content;
|
||||
|
|
|
@ -1995,9 +1995,18 @@ gfxFont::DrawMissingGlyph(const TextRunDrawParams& aRunParams,
|
|||
float advance = aDetails->mAdvance;
|
||||
if (aRunParams.drawMode != DrawMode::GLYPH_PATH && advance > 0) {
|
||||
auto* textDrawer = aRunParams.context->GetTextDrawer();
|
||||
const Matrix* matPtr = nullptr;
|
||||
Matrix mat;
|
||||
if (textDrawer) {
|
||||
textDrawer->FoundUnsupportedFeature();
|
||||
return false;
|
||||
// Generate an orientation matrix for the current writing mode
|
||||
wr::FontInstanceFlags flags = textDrawer->GetWRGlyphFlags();
|
||||
if (flags.bits & wr::FontInstanceFlags::TRANSPOSE) {
|
||||
std::swap(mat._11, mat._12);
|
||||
std::swap(mat._21, mat._22);
|
||||
}
|
||||
mat.PostScale(flags.bits & wr::FontInstanceFlags::FLIP_X ? -1.0f : 1.0f,
|
||||
flags.bits & wr::FontInstanceFlags::FLIP_Y ? -1.0f : 1.0f);
|
||||
matPtr = &mat;
|
||||
}
|
||||
|
||||
Point pt(Float(ToDeviceUnits(aPt.x, aRunParams.devPerApp)),
|
||||
|
@ -2005,7 +2014,8 @@ gfxFont::DrawMissingGlyph(const TextRunDrawParams& aRunParams,
|
|||
Float advanceDevUnits =
|
||||
Float(ToDeviceUnits(advance, aRunParams.devPerApp));
|
||||
Float height = GetMetrics(eHorizontal).maxAscent;
|
||||
Rect glyphRect = aFontParams.isVerticalFont ?
|
||||
// Horizontally center if drawing vertically upright with no sideways transform.
|
||||
Rect glyphRect = aFontParams.isVerticalFont && !mat.HasNonAxisAlignedTransform() ?
|
||||
Rect(pt.x - height / 2, pt.y,
|
||||
height, advanceDevUnits) :
|
||||
Rect(pt.x, pt.y - height,
|
||||
|
@ -2028,7 +2038,7 @@ gfxFont::DrawMissingGlyph(const TextRunDrawParams& aRunParams,
|
|||
gfxFontMissingGlyphs::DrawMissingGlyph(
|
||||
aDetails->mGlyphID, glyphRect, *aRunParams.dt,
|
||||
PatternFromState(aRunParams.context),
|
||||
1.0 / aRunParams.devPerApp);
|
||||
1.0 / aRunParams.devPerApp, matPtr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -158,13 +158,39 @@ static const Float BOX_BORDER_OPACITY = 0.5;
|
|||
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
static void
|
||||
DrawHexChar(uint32_t aDigit, const Point& aPt, DrawTarget& aDrawTarget,
|
||||
const Pattern &aPattern)
|
||||
const Pattern &aPattern, const Matrix* aMat)
|
||||
{
|
||||
uint32_t glyphBits = glyphMicroFont[aDigit];
|
||||
|
||||
if (aMat) {
|
||||
// If using an orientation matrix instead of a DT transform, step
|
||||
// with the matrix basis vectors, filling individual rectangles of
|
||||
// the size indicated by the matrix.
|
||||
Point stepX(aMat->_11, aMat->_12);
|
||||
Point stepY(aMat->_21, aMat->_22);
|
||||
Point corner = stepX + stepY;
|
||||
// Get the rectangle at the origin that will be stepped into place.
|
||||
Rect startRect(std::min(corner.x, 0.0f), std::min(corner.y, 0.0f),
|
||||
fabs(corner.x), fabs(corner.y));
|
||||
startRect.MoveBy(aMat->TransformPoint(aPt));
|
||||
for (int y = 0; y < MINIFONT_HEIGHT; ++y) {
|
||||
Rect curRect = startRect;
|
||||
for (int x = 0; x < MINIFONT_WIDTH; ++x) {
|
||||
if (glyphBits & 1) {
|
||||
aDrawTarget.FillRect(curRect, aPattern);
|
||||
}
|
||||
glyphBits >>= 1;
|
||||
curRect.MoveBy(stepX);
|
||||
}
|
||||
startRect.MoveBy(stepY);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// To avoid the potential for seams showing between rects when we're under
|
||||
// a transform we concat all the rects into a PathBuilder and fill the
|
||||
// resulting Path (rather than using DrawTarget::FillRect).
|
||||
RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
|
||||
uint32_t glyphBits = glyphMicroFont[aDigit];
|
||||
for (int y = 0; y < MINIFONT_HEIGHT; ++y) {
|
||||
for (int x = 0; x < MINIFONT_WIDTH; ++x) {
|
||||
if (glyphBits & 1) {
|
||||
|
@ -189,8 +215,17 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
const Rect& aRect,
|
||||
DrawTarget& aDrawTarget,
|
||||
const Pattern& aPattern,
|
||||
uint32_t aAppUnitsPerDevPixel)
|
||||
uint32_t aAppUnitsPerDevPixel,
|
||||
const Matrix* aMat)
|
||||
{
|
||||
Rect rect(aRect);
|
||||
// If there is an orientation transform, reorient the bounding rect.
|
||||
if (aMat) {
|
||||
rect.MoveBy(-aRect.BottomLeft());
|
||||
rect = aMat->TransformBounds(rect);
|
||||
rect.MoveBy(aRect.BottomLeft());
|
||||
}
|
||||
|
||||
// If we're currently drawing with some kind of pattern, we just draw the
|
||||
// missing-glyph data in black.
|
||||
ColorPattern color = aPattern.GetType() == PatternType::COLOR ?
|
||||
|
@ -201,11 +236,11 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
// from the left edge of the glyph box and the stroke's right edge
|
||||
// is inset one pixel from the right edge of the glyph box.
|
||||
Float halfBorderWidth = BOX_BORDER_WIDTH / 2.0;
|
||||
Float borderLeft = aRect.X() + BOX_HORIZONTAL_INSET + halfBorderWidth;
|
||||
Float borderRight = aRect.XMost() - BOX_HORIZONTAL_INSET - halfBorderWidth;
|
||||
Rect borderStrokeRect(borderLeft, aRect.Y() + halfBorderWidth,
|
||||
Float borderLeft = rect.X() + BOX_HORIZONTAL_INSET + halfBorderWidth;
|
||||
Float borderRight = rect.XMost() - BOX_HORIZONTAL_INSET - halfBorderWidth;
|
||||
Rect borderStrokeRect(borderLeft, rect.Y() + halfBorderWidth,
|
||||
borderRight - borderLeft,
|
||||
aRect.Height() - 2.0 * halfBorderWidth);
|
||||
rect.Height() - 2.0 * halfBorderWidth);
|
||||
if (!borderStrokeRect.IsEmpty()) {
|
||||
ColorPattern adjustedColor = color;
|
||||
color.mColor.a *= BOX_BORDER_OPACITY;
|
||||
|
@ -218,7 +253,7 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
}
|
||||
|
||||
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
Point center = aRect.Center();
|
||||
Point center = rect.Center();
|
||||
Float halfGap = HEX_CHAR_GAP / 2.f;
|
||||
Float top = -(MINIFONT_HEIGHT + halfGap);
|
||||
// We always want integer scaling, otherwise the "bitmap" glyphs will look
|
||||
|
@ -226,46 +261,65 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
int32_t devPixelsPerCSSPx =
|
||||
std::max<int32_t>(1, nsDeviceContext::AppUnitsPerCSSPixel() /
|
||||
aAppUnitsPerDevPixel);
|
||||
AutoRestoreTransform autoRestoreTransform(&aDrawTarget);
|
||||
aDrawTarget.SetTransform(
|
||||
aDrawTarget.GetTransform().PreTranslate(center).
|
||||
PreScale(devPixelsPerCSSPx,
|
||||
devPixelsPerCSSPx));
|
||||
|
||||
Matrix tempMat;
|
||||
if (aMat) {
|
||||
// If there is an orientation transform, since draw target transforms may
|
||||
// not be supported, scale and translate it so that it can be directly used
|
||||
// for rendering the mini font without changing the draw target transform.
|
||||
tempMat = Matrix(*aMat).PostScale(devPixelsPerCSSPx, devPixelsPerCSSPx)
|
||||
.PostTranslate(center);
|
||||
aMat = &tempMat;
|
||||
} else {
|
||||
// Otherwise, scale and translate the draw target transform assuming it
|
||||
// supports that.
|
||||
tempMat = aDrawTarget.GetTransform();
|
||||
aDrawTarget.SetTransform(
|
||||
Matrix(tempMat).PreTranslate(center)
|
||||
.PreScale(devPixelsPerCSSPx, devPixelsPerCSSPx));
|
||||
}
|
||||
|
||||
if (aChar < 0x10000) {
|
||||
if (aRect.Width() >= 2 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
|
||||
aRect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
|
||||
if (rect.Width() >= 2 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
|
||||
rect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
|
||||
// Draw 4 digits for BMP
|
||||
Float left = -(MINIFONT_WIDTH + halfGap);
|
||||
DrawHexChar((aChar >> 12) & 0xF,
|
||||
Point(left, top), aDrawTarget, color);
|
||||
Point(left, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 8) & 0xF,
|
||||
Point(halfGap, top), aDrawTarget, color);
|
||||
Point(halfGap, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 4) & 0xF,
|
||||
Point(left, halfGap), aDrawTarget, color);
|
||||
Point(left, halfGap), aDrawTarget, color, aMat);
|
||||
DrawHexChar(aChar & 0xF,
|
||||
Point(halfGap, halfGap), aDrawTarget, color);
|
||||
Point(halfGap, halfGap), aDrawTarget, color, aMat);
|
||||
}
|
||||
} else {
|
||||
if (aRect.Width() >= 3 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
|
||||
aRect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
|
||||
if (rect.Width() >= 3 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
|
||||
rect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
|
||||
// Draw 6 digits for non-BMP
|
||||
Float first = -(MINIFONT_WIDTH * 1.5 + HEX_CHAR_GAP);
|
||||
Float second = -(MINIFONT_WIDTH / 2.0);
|
||||
Float third = (MINIFONT_WIDTH / 2.0 + HEX_CHAR_GAP);
|
||||
DrawHexChar((aChar >> 20) & 0xF,
|
||||
Point(first, top), aDrawTarget, color);
|
||||
Point(first, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 16) & 0xF,
|
||||
Point(second, top), aDrawTarget, color);
|
||||
Point(second, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 12) & 0xF,
|
||||
Point(third, top), aDrawTarget, color);
|
||||
Point(third, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 8) & 0xF,
|
||||
Point(first, halfGap), aDrawTarget, color);
|
||||
Point(first, halfGap), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 4) & 0xF,
|
||||
Point(second, halfGap), aDrawTarget, color);
|
||||
Point(second, halfGap), aDrawTarget, color, aMat);
|
||||
DrawHexChar(aChar & 0xF,
|
||||
Point(third, halfGap), aDrawTarget, color);
|
||||
Point(third, halfGap), aDrawTarget, color, aMat);
|
||||
}
|
||||
}
|
||||
|
||||
if (!aMat) {
|
||||
// The draw target transform was changed, so it must be restored to
|
||||
// the original value.
|
||||
aDrawTarget.SetTransform(tempMat);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -38,12 +38,14 @@ public:
|
|||
* @param aPattern the pattern currently being used to paint
|
||||
* @param aAppUnitsPerDevPixel the appUnits to devPixel ratio we're using,
|
||||
* (so we can scale glyphs to a sensible size)
|
||||
* @param aMat optional local-space orientation matrix
|
||||
*/
|
||||
static void DrawMissingGlyph(uint32_t aChar,
|
||||
const Rect& aRect,
|
||||
DrawTarget& aDrawTarget,
|
||||
const Pattern& aPattern,
|
||||
uint32_t aAppUnitsPerDevPixel);
|
||||
uint32_t aAppUnitsPerDevPixel,
|
||||
const Matrix* aMat = nullptr);
|
||||
/**
|
||||
* @return the desired minimum width for a glyph-box that will allow
|
||||
* the hexboxes to be drawn reasonably.
|
||||
|
|
|
@ -7,16 +7,26 @@
|
|||
#include "RenderCompositor.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/layers/SyncObject.h"
|
||||
#include "mozilla/webrender/RenderCompositorOGL.h"
|
||||
#include "mozilla/widget/CompositorWidget.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/webrender/RenderCompositorANGLE.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace wr {
|
||||
|
||||
/* static */ UniquePtr<RenderCompositor>
|
||||
RenderCompositor::Create(RefPtr<widget::CompositorWidget>&& aWidget)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
if (gfx::gfxVars::UseWebRenderANGLE()) {
|
||||
return RenderCompositorANGLE::Create(Move(aWidget));
|
||||
}
|
||||
#endif
|
||||
return RenderCompositorOGL::Create(Move(aWidget));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/* -*- 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 "RenderCompositorANGLE.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "GLContextEGL.h"
|
||||
#include "GLContextProvider.h"
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#include "mozilla/layers/HelpersD3D11.h"
|
||||
#include "mozilla/layers/SyncObject.h"
|
||||
#include "mozilla/widget/CompositorWidget.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace wr {
|
||||
|
||||
/* static */ UniquePtr<RenderCompositor>
|
||||
RenderCompositorANGLE::Create(RefPtr<widget::CompositorWidget>&& aWidget)
|
||||
{
|
||||
UniquePtr<RenderCompositorANGLE> compositor = MakeUnique<RenderCompositorANGLE>(Move(aWidget));
|
||||
if (!compositor->Initialize()) {
|
||||
return nullptr;
|
||||
}
|
||||
return compositor;
|
||||
}
|
||||
|
||||
RenderCompositorANGLE::RenderCompositorANGLE(RefPtr<widget::CompositorWidget>&& aWidget)
|
||||
: RenderCompositor(Move(aWidget))
|
||||
{
|
||||
}
|
||||
|
||||
RenderCompositorANGLE::~RenderCompositorANGLE()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
RenderCompositorANGLE::Initialize()
|
||||
{
|
||||
mDevice = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
|
||||
if (!mDevice) {
|
||||
gfxCriticalNote << "[D3D11] failed to get compositor device.";
|
||||
return false;
|
||||
}
|
||||
|
||||
mDevice->GetImmediateContext(getter_AddRefs(mCtx));
|
||||
if (!mCtx) {
|
||||
gfxCriticalNote << "[D3D11] failed to get immediate context.";
|
||||
return false;
|
||||
}
|
||||
|
||||
mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(mDevice);
|
||||
if (!mSyncObject->Init()) {
|
||||
// Some errors occur. Clear the mSyncObject here.
|
||||
// Then, there will be no texture synchronization.
|
||||
return false;
|
||||
}
|
||||
|
||||
mGL = gl::GLContextProviderEGL::CreateForCompositorWidget(mWidget, true);
|
||||
if (!mGL || !mGL->IsANGLE()) {
|
||||
gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(mGL.get());
|
||||
return false;
|
||||
}
|
||||
if (!mGL->MakeCurrent()) {
|
||||
gfxCriticalNote << "Failed GL context creation for WebRender: " << gfx::hexa(mGL.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RenderCompositorANGLE::Destroy()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RenderCompositorANGLE::BeginFrame()
|
||||
{
|
||||
if (!mGL->MakeCurrent()) {
|
||||
gfxCriticalNote << "Failed to make render context current, can't draw.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSyncObject) {
|
||||
// XXX: if the synchronization is failed, we should handle the device reset.
|
||||
mSyncObject->Synchronize();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
RenderCompositorANGLE::EndFrame()
|
||||
{
|
||||
InsertPresentWaitQuery();
|
||||
|
||||
mGL->SwapBuffers();
|
||||
|
||||
// Note: this waits on the query we inserted in the previous frame,
|
||||
// not the one we just inserted now. Example:
|
||||
// Insert query #1
|
||||
// Present #1
|
||||
// (first frame, no wait)
|
||||
// Insert query #2
|
||||
// Present #2
|
||||
// Wait for query #1.
|
||||
// Insert query #3
|
||||
// Present #3
|
||||
// Wait for query #2.
|
||||
//
|
||||
// This ensures we're done reading textures before swapping buffers.
|
||||
WaitForPreviousPresentQuery();
|
||||
}
|
||||
|
||||
void
|
||||
RenderCompositorANGLE::Pause()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
RenderCompositorANGLE::Resume()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
LayoutDeviceIntSize
|
||||
RenderCompositorANGLE::GetClientSize()
|
||||
{
|
||||
return mWidget->GetClientSize();
|
||||
}
|
||||
|
||||
void
|
||||
RenderCompositorANGLE::InsertPresentWaitQuery()
|
||||
{
|
||||
CD3D11_QUERY_DESC desc(D3D11_QUERY_EVENT);
|
||||
HRESULT hr = mDevice->CreateQuery(&desc, getter_AddRefs(mNextWaitForPresentQuery));
|
||||
if (FAILED(hr) || !mNextWaitForPresentQuery) {
|
||||
gfxWarning() << "Could not create D3D11_QUERY_EVENT: " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
mCtx->End(mNextWaitForPresentQuery);
|
||||
}
|
||||
|
||||
void
|
||||
RenderCompositorANGLE::WaitForPreviousPresentQuery()
|
||||
{
|
||||
if (mWaitForPresentQuery) {
|
||||
BOOL result;
|
||||
layers::WaitForGPUQuery(mDevice, mCtx, mWaitForPresentQuery, &result);
|
||||
}
|
||||
mWaitForPresentQuery = mNextWaitForPresentQuery.forget();
|
||||
}
|
||||
|
||||
|
||||
} // namespace wr
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,58 @@
|
|||
/* -*- 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_GFX_RENDERCOMPOSITOR_ANGLE_H
|
||||
#define MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
|
||||
|
||||
#include "mozilla/webrender/RenderCompositor.h"
|
||||
|
||||
struct ID3D11DeviceContext;
|
||||
struct ID3D11Device;
|
||||
struct ID3D11Query;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace wr {
|
||||
|
||||
class RenderCompositorANGLE : public RenderCompositor
|
||||
{
|
||||
public:
|
||||
static UniquePtr<RenderCompositor> Create(RefPtr<widget::CompositorWidget>&& aWidget);
|
||||
|
||||
explicit RenderCompositorANGLE(RefPtr<widget::CompositorWidget>&& aWidget);
|
||||
virtual ~RenderCompositorANGLE();
|
||||
bool Initialize();
|
||||
|
||||
bool Destroy() override;
|
||||
bool BeginFrame() override;
|
||||
void EndFrame() override;
|
||||
void Pause() override;
|
||||
bool Resume() override;
|
||||
|
||||
gl::GLContext* gl() const override { return mGL; }
|
||||
|
||||
bool UseANGLE() const override { return true; }
|
||||
|
||||
LayoutDeviceIntSize GetClientSize() override;
|
||||
|
||||
protected:
|
||||
void InsertPresentWaitQuery();
|
||||
void WaitForPreviousPresentQuery();
|
||||
|
||||
RefPtr<gl::GLContext> mGL;
|
||||
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
RefPtr<ID3D11DeviceContext> mCtx;
|
||||
|
||||
RefPtr<ID3D11Query> mWaitForPresentQuery;
|
||||
RefPtr<ID3D11Query> mNextWaitForPresentQuery;
|
||||
|
||||
};
|
||||
|
||||
} // namespace wr
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -8,14 +8,8 @@
|
|||
|
||||
#include "GLContext.h"
|
||||
#include "GLContextProvider.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/layers/SyncObject.h"
|
||||
#include "mozilla/widget/CompositorWidget.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "GLContextEGL.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace wr {
|
||||
|
||||
|
@ -23,16 +17,7 @@ namespace wr {
|
|||
RenderCompositorOGL::Create(RefPtr<widget::CompositorWidget>&& aWidget)
|
||||
{
|
||||
RefPtr<gl::GLContext> gl;
|
||||
if (gfx::gfxVars::UseWebRenderANGLE()) {
|
||||
gl = gl::GLContextProviderEGL::CreateForCompositorWidget(aWidget, true);
|
||||
if (!gl || !gl->IsANGLE()) {
|
||||
gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(gl.get());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (!gl) {
|
||||
gl = gl::GLContextProvider::CreateForCompositorWidget(aWidget, true);
|
||||
}
|
||||
gl = gl::GLContextProvider::CreateForCompositorWidget(aWidget, true);
|
||||
if (!gl || !gl->MakeCurrent()) {
|
||||
gfxCriticalNote << "Failed GL context creation for WebRender: " << gfx::hexa(gl.get());
|
||||
return nullptr;
|
||||
|
@ -41,34 +26,11 @@ RenderCompositorOGL::Create(RefPtr<widget::CompositorWidget>&& aWidget)
|
|||
}
|
||||
|
||||
RenderCompositorOGL::RenderCompositorOGL(RefPtr<gl::GLContext>&& aGL,
|
||||
RefPtr<widget::CompositorWidget>&& aWidget)
|
||||
RefPtr<widget::CompositorWidget>&& aWidget)
|
||||
: RenderCompositor(Move(aWidget))
|
||||
, mGL(aGL)
|
||||
{
|
||||
MOZ_ASSERT(mGL);
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (mGL->IsANGLE()) {
|
||||
gl::GLLibraryEGL* egl = &gl::sEGLLibrary;
|
||||
|
||||
// Fetch the D3D11 device.
|
||||
EGLDeviceEXT eglDevice = nullptr;
|
||||
egl->fQueryDisplayAttribEXT(egl->Display(), LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
|
||||
MOZ_ASSERT(eglDevice);
|
||||
ID3D11Device* device = nullptr;
|
||||
egl->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, (EGLAttrib*)&device);
|
||||
MOZ_ASSERT(device);
|
||||
|
||||
mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(device);
|
||||
if (mSyncObject) {
|
||||
if (!mSyncObject->Init()) {
|
||||
// Some errors occur. Clear the mSyncObject here.
|
||||
// Then, there will be no texture synchronization.
|
||||
mSyncObject = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
RenderCompositorOGL::~RenderCompositorOGL()
|
||||
|
@ -88,11 +50,6 @@ RenderCompositorOGL::BeginFrame()
|
|||
gfxCriticalNote << "Failed to make render context current, can't draw.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSyncObject) {
|
||||
// XXX: if the synchronization is failed, we should handle the device reset.
|
||||
mSyncObject->Synchronize();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -128,12 +85,6 @@ RenderCompositorOGL::Resume()
|
|||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
RenderCompositorOGL::UseANGLE() const
|
||||
{
|
||||
return mGL->IsANGLE();
|
||||
}
|
||||
|
||||
LayoutDeviceIntSize
|
||||
RenderCompositorOGL::GetClientSize()
|
||||
{
|
||||
|
|
|
@ -10,19 +10,7 @@
|
|||
#include "mozilla/webrender/RenderCompositor.h"
|
||||
|
||||
namespace mozilla {
|
||||
/*
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
class SyncObjectHost;
|
||||
}
|
||||
|
||||
namespace widget {
|
||||
class CompositorWidget;
|
||||
}
|
||||
*/
|
||||
namespace wr {
|
||||
|
||||
class RenderCompositorOGL : public RenderCompositor
|
||||
|
@ -31,7 +19,7 @@ public:
|
|||
static UniquePtr<RenderCompositor> Create(RefPtr<widget::CompositorWidget>&& aWidget);
|
||||
|
||||
RenderCompositorOGL(RefPtr<gl::GLContext>&& aGL,
|
||||
RefPtr<widget::CompositorWidget>&& aWidget);
|
||||
RefPtr<widget::CompositorWidget>&& aWidget);
|
||||
virtual ~RenderCompositorOGL();
|
||||
|
||||
bool Destroy() override;
|
||||
|
@ -42,7 +30,7 @@ public:
|
|||
|
||||
gl::GLContext* gl() const override { return mGL; }
|
||||
|
||||
bool UseANGLE() const override;
|
||||
bool UseANGLE() const override { return false; }
|
||||
|
||||
LayoutDeviceIntSize GetClientSize() override;
|
||||
|
||||
|
|
|
@ -47,9 +47,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
|||
if CONFIG['MOZ_ENABLE_D3D10_LAYER']:
|
||||
DEFINES['MOZ_ENABLE_D3D10_LAYER'] = True
|
||||
EXPORTS.mozilla.webrender += [
|
||||
'RenderCompositorANGLE.h',
|
||||
'RenderD3D11TextureHostOGL.h',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'RenderCompositorANGLE.cpp',
|
||||
'RenderD3D11TextureHostOGL.cpp',
|
||||
]
|
||||
|
||||
|
|
|
@ -1112,6 +1112,105 @@ function ArrayConcat(arg1) {
|
|||
return A;
|
||||
}
|
||||
|
||||
// https://tc39.github.io/proposal-flatMap/
|
||||
// January 16, 2018
|
||||
function ArrayFlatMap(mapperFunction/*, thisArg*/) {
|
||||
// Step 1.
|
||||
var O = ToObject(this);
|
||||
|
||||
// Step 2.
|
||||
var sourceLen = ToLength(O.length);
|
||||
|
||||
// Step 3.
|
||||
if (!IsCallable(mapperFunction))
|
||||
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction));
|
||||
|
||||
// Step 4.
|
||||
var T = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 5.
|
||||
var A = ArraySpeciesCreate(O, 0);
|
||||
|
||||
// Step 6.
|
||||
FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
|
||||
|
||||
// Step 7.
|
||||
return A;
|
||||
}
|
||||
|
||||
// https://tc39.github.io/proposal-flatMap/
|
||||
// January 16, 2018
|
||||
function ArrayFlatten(/* depth */) {
|
||||
// Step 1.
|
||||
var O = ToObject(this);
|
||||
|
||||
// Step 2.
|
||||
var sourceLen = ToLength(O.length);
|
||||
|
||||
// Step 3.
|
||||
var depthNum = 1;
|
||||
|
||||
// Step 4.
|
||||
if (arguments.length > 0 && arguments[0] !== undefined)
|
||||
depthNum = ToInteger(arguments[0]);
|
||||
|
||||
// Step 5.
|
||||
var A = ArraySpeciesCreate(O, 0);
|
||||
|
||||
// Step 6.
|
||||
FlattenIntoArray(A, O, sourceLen, 0, depthNum);
|
||||
|
||||
// Step 7.
|
||||
return A;
|
||||
}
|
||||
|
||||
function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) {
|
||||
// Step 1.
|
||||
var targetIndex = start;
|
||||
|
||||
// Steps 2-3.
|
||||
for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
|
||||
// Steps 3.a-c.
|
||||
if (sourceIndex in source) {
|
||||
// Step 3.c.i.
|
||||
var element = source[sourceIndex];
|
||||
|
||||
if (mapperFunction) {
|
||||
// Step 3.c.ii.1.
|
||||
assert(arguments.length === 7, "thisArg is present");
|
||||
|
||||
// Step 3.c.ii.2.
|
||||
element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source);
|
||||
}
|
||||
|
||||
// Step 3.c.iii.
|
||||
var flattenable = IsArray(element);
|
||||
|
||||
// Step 3.c.iv.
|
||||
if (flattenable && depth > 0) {
|
||||
// Step 3.c.iv.1.
|
||||
var elementLen = ToLength(element.length);
|
||||
|
||||
// Step 3.c.iv.2.
|
||||
targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1);
|
||||
} else {
|
||||
// Step 3.c.v.1.
|
||||
if (targetIndex >= MAX_NUMERIC_INDEX)
|
||||
ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
|
||||
|
||||
// Step 3.c.v.2.
|
||||
_DefineDataProperty(target, targetIndex, element);
|
||||
|
||||
// Step 3.c.v.3.
|
||||
targetIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4.
|
||||
return targetIndex;
|
||||
}
|
||||
|
||||
function ArrayStaticConcat(arr, arg1) {
|
||||
if (arguments.length < 1)
|
||||
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.concat");
|
||||
|
|
|
@ -40,8 +40,8 @@
|
|||
'#' + __LINE__ + ': ' + msg) \
|
||||
} while (false)
|
||||
#else
|
||||
#define assert(b, info) do {} while (false) // Elided assertion.
|
||||
#define dbg(msg) do {} while (false) // Elided debugging output.
|
||||
#define assert(b, info) ; // Elided assertion.
|
||||
#define dbg(msg) ; // Elided debugging output.
|
||||
#endif
|
||||
|
||||
// All C++-implemented standard builtins library functions used in self-hosted
|
||||
|
|
|
@ -8535,6 +8535,31 @@ CodeGenerator::visitBoundsCheckLower(LBoundsCheckLower* lir)
|
|||
lir->snapshot());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitSpectreMaskIndex(LSpectreMaskIndex* lir)
|
||||
{
|
||||
MOZ_ASSERT(JitOptions.spectreIndexMasking);
|
||||
|
||||
const LAllocation* index = lir->index();
|
||||
const LAllocation* length = lir->length();
|
||||
Register output = ToRegister(lir->output());
|
||||
|
||||
if (index->isConstant()) {
|
||||
int32_t idx = ToInt32(index);
|
||||
if (length->isRegister())
|
||||
masm.spectreMaskIndex(idx, ToRegister(length), output);
|
||||
else
|
||||
masm.spectreMaskIndex(idx, ToAddress(length), output);
|
||||
return;
|
||||
}
|
||||
|
||||
Register indexReg = ToRegister(index);
|
||||
if (length->isRegister())
|
||||
masm.spectreMaskIndex(indexReg, ToRegister(length), output);
|
||||
else
|
||||
masm.spectreMaskIndex(indexReg, ToAddress(length), output);
|
||||
}
|
||||
|
||||
class OutOfLineStoreElementHole : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LInstruction* ins_;
|
||||
|
|
|
@ -251,6 +251,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitBoundsCheck(LBoundsCheck* lir) override;
|
||||
void visitBoundsCheckRange(LBoundsCheckRange* lir) override;
|
||||
void visitBoundsCheckLower(LBoundsCheckLower* lir) override;
|
||||
void visitSpectreMaskIndex(LSpectreMaskIndex* lir) override;
|
||||
void visitLoadFixedSlotV(LLoadFixedSlotV* ins) override;
|
||||
void visitLoadFixedSlotAndUnbox(LLoadFixedSlotAndUnbox* lir) override;
|
||||
void visitLoadFixedSlotT(LLoadFixedSlotT* ins) override;
|
||||
|
|
|
@ -7835,7 +7835,8 @@ IonBuilder::checkTypedObjectIndexInBounds(uint32_t elemSize,
|
|||
MDefinition* obj,
|
||||
MDefinition* index,
|
||||
TypedObjectPrediction objPrediction,
|
||||
LinearSum* indexAsByteOffset)
|
||||
LinearSum* indexAsByteOffset,
|
||||
BoundsCheckKind kind)
|
||||
{
|
||||
// Ensure index is an integer.
|
||||
MInstruction* idInt32 = MToInt32::New(alloc(), index);
|
||||
|
@ -7862,7 +7863,7 @@ IonBuilder::checkTypedObjectIndexInBounds(uint32_t elemSize,
|
|||
return false;
|
||||
}
|
||||
|
||||
index = addBoundsCheck(idInt32, length);
|
||||
index = addBoundsCheck(idInt32, length, kind);
|
||||
|
||||
return indexAsByteOffset->add(index, AssertedCast<int32_t>(elemSize));
|
||||
}
|
||||
|
@ -7882,8 +7883,11 @@ IonBuilder::getElemTryScalarElemOfTypedObject(bool* emitted,
|
|||
MOZ_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
|
||||
|
||||
LinearSum indexAsByteOffset(alloc());
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
|
||||
BoundsCheckKind::IsLoad))
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
trackOptimizationSuccess();
|
||||
*emitted = true;
|
||||
|
@ -7904,8 +7908,11 @@ IonBuilder::getElemTryReferenceElemOfTypedObject(bool* emitted,
|
|||
uint32_t elemSize = ReferenceTypeDescr::size(elemType);
|
||||
|
||||
LinearSum indexAsByteOffset(alloc());
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
|
||||
BoundsCheckKind::IsLoad))
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
trackOptimizationSuccess();
|
||||
*emitted = true;
|
||||
|
@ -8025,8 +8032,11 @@ IonBuilder::getElemTryComplexElemOfTypedObject(bool* emitted,
|
|||
MDefinition* elemTypeObj = typeObjectForElementFromArrayStructType(type);
|
||||
|
||||
LinearSum indexAsByteOffset(alloc());
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
|
||||
BoundsCheckKind::IsLoad))
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return pushDerivedTypedObject(emitted, obj, indexAsByteOffset,
|
||||
elemPrediction, elemTypeObj);
|
||||
|
@ -8317,7 +8327,7 @@ IonBuilder::getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index
|
|||
MStringLength* length = MStringLength::New(alloc(), obj);
|
||||
current->add(length);
|
||||
|
||||
index = addBoundsCheck(index, length);
|
||||
index = addBoundsCheck(index, length, BoundsCheckKind::IsLoad);
|
||||
|
||||
MCharCodeAt* charCode = MCharCodeAt::New(alloc(), obj, index);
|
||||
current->add(charCode);
|
||||
|
@ -8359,7 +8369,7 @@ IonBuilder::getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* in
|
|||
index = idInt32;
|
||||
|
||||
// Bailouts if we read more than the number of actual arguments.
|
||||
index = addBoundsCheck(index, length);
|
||||
index = addBoundsCheck(index, length, BoundsCheckKind::IsLoad);
|
||||
|
||||
// Load the argument from the actual arguments.
|
||||
bool modifiesArgs = script()->baselineScript()->modifiesArguments();
|
||||
|
@ -8447,7 +8457,8 @@ IonBuilder::getElemTryArgumentsInlinedIndex(bool* emitted, MDefinition* obj, MDe
|
|||
// cannot re-enter because reading out of bounds arguments will disable the
|
||||
// lazy arguments optimization for this script, when this code would be
|
||||
// executed in Baseline. (see GetElemOptimizedArguments)
|
||||
index = addBoundsCheck(index, constantInt(inlineCallInfo_->argc()));
|
||||
index = addBoundsCheck(index, constantInt(inlineCallInfo_->argc()),
|
||||
BoundsCheckKind::IsLoad);
|
||||
|
||||
// Get an instruction to represent the state of the argument vector.
|
||||
MInstruction* args = MArgumentState::New(alloc().fallible(), inlineCallInfo_->argv());
|
||||
|
@ -8646,7 +8657,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index)
|
|||
// in-bounds elements, and the array is packed or its holes are not
|
||||
// read. This is the best case: we can separate the bounds check for
|
||||
// hoisting.
|
||||
index = addBoundsCheck(index, initLength);
|
||||
index = addBoundsCheck(index, initLength, BoundsCheckKind::IsLoad);
|
||||
|
||||
load = MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble);
|
||||
current->add(load);
|
||||
|
@ -8685,7 +8696,8 @@ void
|
|||
IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
|
||||
BoundsChecking checking,
|
||||
MDefinition** index,
|
||||
MInstruction** length, MInstruction** elements)
|
||||
MInstruction** length, MInstruction** elements,
|
||||
BoundsCheckKind boundsCheckKind)
|
||||
{
|
||||
MOZ_ASSERT((index != nullptr) == (elements != nullptr));
|
||||
|
||||
|
@ -8719,7 +8731,7 @@ IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
|
|||
|
||||
if (index) {
|
||||
if (checking == DoBoundsCheck)
|
||||
*index = addBoundsCheck(*index, *length);
|
||||
*index = addBoundsCheck(*index, *length, boundsCheckKind);
|
||||
|
||||
*elements = MConstantElements::New(alloc(), data);
|
||||
current->add(*elements);
|
||||
|
@ -8734,7 +8746,7 @@ IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
|
|||
|
||||
if (index) {
|
||||
if (checking == DoBoundsCheck)
|
||||
*index = addBoundsCheck(*index, *length);
|
||||
*index = addBoundsCheck(*index, *length, boundsCheckKind);
|
||||
|
||||
*elements = MTypedArrayElements::New(alloc(), obj);
|
||||
current->add(*elements);
|
||||
|
@ -8816,7 +8828,8 @@ IonBuilder::jsop_getelem_typed(MDefinition* obj, MDefinition* index,
|
|||
// Get length, bounds-check, then get elements, and add all instructions.
|
||||
MInstruction* length;
|
||||
MInstruction* elements;
|
||||
addTypedArrayLengthAndData(obj, DoBoundsCheck, &index, &length, &elements);
|
||||
addTypedArrayLengthAndData(obj, DoBoundsCheck, &index, &length, &elements,
|
||||
BoundsCheckKind::IsLoad);
|
||||
|
||||
// Load the element.
|
||||
MLoadUnboxedScalar* load = MLoadUnboxedScalar::New(alloc(), elements, index, arrayType);
|
||||
|
@ -9001,8 +9014,11 @@ IonBuilder::setElemTryReferenceElemOfTypedObject(bool* emitted,
|
|||
uint32_t elemSize = ReferenceTypeDescr::size(elemType);
|
||||
|
||||
LinearSum indexAsByteOffset(alloc());
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
|
||||
BoundsCheckKind::IsStore))
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return setPropTryReferenceTypedObjectValue(emitted, obj, indexAsByteOffset,
|
||||
elemType, value, nullptr);
|
||||
|
@ -9022,8 +9038,11 @@ IonBuilder::setElemTryScalarElemOfTypedObject(bool* emitted,
|
|||
MOZ_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
|
||||
|
||||
LinearSum indexAsByteOffset(alloc());
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
|
||||
BoundsCheckKind::IsStore))
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return setPropTryScalarTypedObjectValue(emitted, obj, indexAsByteOffset, elemType, value);
|
||||
}
|
||||
|
@ -9319,7 +9338,7 @@ IonBuilder::initOrSetElemDense(TemporaryTypeSet::DoubleConversion conversion,
|
|||
} else {
|
||||
MInstruction* initLength = initializedLength(obj, elements);
|
||||
|
||||
id = addBoundsCheck(id, initLength);
|
||||
id = addBoundsCheck(id, initLength, BoundsCheckKind::IsStore);
|
||||
bool needsHoleCheck = !packed && hasExtraIndexedProperty;
|
||||
|
||||
MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck);
|
||||
|
@ -9367,7 +9386,8 @@ IonBuilder::jsop_setelem_typed(Scalar::Type arrayType,
|
|||
MInstruction* length;
|
||||
MInstruction* elements;
|
||||
BoundsChecking checking = expectOOB ? SkipBoundsCheck : DoBoundsCheck;
|
||||
addTypedArrayLengthAndData(obj, checking, &id, &length, &elements);
|
||||
addTypedArrayLengthAndData(obj, checking, &id, &length, &elements,
|
||||
BoundsCheckKind::IsStore);
|
||||
|
||||
// Clamp value to [0, 255] for Uint8ClampedArray.
|
||||
MDefinition* toWrite = value;
|
||||
|
@ -12901,7 +12921,7 @@ IonBuilder::inTryDense(bool* emitted, MDefinition* obj, MDefinition* id)
|
|||
|
||||
// If there are no holes, speculate the InArray check will not fail.
|
||||
if (!needsHoleCheck && !failedBoundsCheck_) {
|
||||
addBoundsCheck(idInt32, initLength);
|
||||
addBoundsCheck(idInt32, initLength, BoundsCheckKind::UnusedIndex);
|
||||
pushConstant(BooleanValue(true));
|
||||
return Ok();
|
||||
}
|
||||
|
@ -13246,7 +13266,7 @@ IonBuilder::addMaybeCopyElementsForWrite(MDefinition* object, bool checkNative)
|
|||
}
|
||||
|
||||
MInstruction*
|
||||
IonBuilder::addBoundsCheck(MDefinition* index, MDefinition* length)
|
||||
IonBuilder::addBoundsCheck(MDefinition* index, MDefinition* length, BoundsCheckKind kind)
|
||||
{
|
||||
MInstruction* check = MBoundsCheck::New(alloc(), index, length);
|
||||
current->add(check);
|
||||
|
@ -13255,6 +13275,11 @@ IonBuilder::addBoundsCheck(MDefinition* index, MDefinition* length)
|
|||
if (failedBoundsCheck_)
|
||||
check->setNotMovable();
|
||||
|
||||
if (kind == BoundsCheckKind::IsLoad && JitOptions.spectreIndexMasking) {
|
||||
check = MSpectreMaskIndex::New(alloc(), check, length);
|
||||
current->add(check);
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,7 +195,10 @@ class IonBuilder
|
|||
|
||||
MInstruction* addConvertElementsToDoubles(MDefinition* elements);
|
||||
MDefinition* addMaybeCopyElementsForWrite(MDefinition* object, bool checkNative);
|
||||
MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
|
||||
|
||||
enum class BoundsCheckKind { IsLoad, IsStore, UnusedIndex };
|
||||
MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length, BoundsCheckKind kind);
|
||||
|
||||
MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind);
|
||||
MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind);
|
||||
MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind);
|
||||
|
@ -375,7 +378,8 @@ class IonBuilder
|
|||
MDefinition* obj,
|
||||
MDefinition* index,
|
||||
TypedObjectPrediction objTypeDescrs,
|
||||
LinearSum* indexAsByteOffset);
|
||||
LinearSum* indexAsByteOffset,
|
||||
BoundsCheckKind kind);
|
||||
AbortReasonOr<Ok> pushDerivedTypedObject(bool* emitted,
|
||||
MDefinition* obj,
|
||||
const LinearSum& byteOffset,
|
||||
|
@ -464,14 +468,16 @@ class IonBuilder
|
|||
void addTypedArrayLengthAndData(MDefinition* obj,
|
||||
BoundsChecking checking,
|
||||
MDefinition** index,
|
||||
MInstruction** length, MInstruction** elements);
|
||||
MInstruction** length, MInstruction** elements,
|
||||
BoundsCheckKind boundsCheckKind);
|
||||
|
||||
// Add an instruction to compute a typed array's length to the current
|
||||
// block. If you also need the typed array's data, use the above method
|
||||
// instead.
|
||||
MInstruction* addTypedArrayLength(MDefinition* obj) {
|
||||
MInstruction* length;
|
||||
addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
|
||||
addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr,
|
||||
BoundsCheckKind::UnusedIndex);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -766,7 +772,7 @@ class IonBuilder
|
|||
|
||||
bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType,
|
||||
MInstruction** elements, MDefinition** index,
|
||||
Scalar::Type* arrayType);
|
||||
Scalar::Type* arrayType, BoundsCheckKind boundsCheckKind);
|
||||
InliningResult inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdType type,
|
||||
unsigned numElems);
|
||||
InliningResult inlineSimdStore(CallInfo& callInfo, JSNative native, SimdType type,
|
||||
|
@ -830,7 +836,8 @@ class IonBuilder
|
|||
bool atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayElementType,
|
||||
bool* requiresDynamicCheck,
|
||||
AtomicCheckResult checkResult=DoCheckAtomicResult);
|
||||
void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index);
|
||||
void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index,
|
||||
BoundsCheckKind kind);
|
||||
|
||||
bool testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo);
|
||||
|
||||
|
|
|
@ -3129,6 +3129,26 @@ LIRGenerator::visitBoundsCheck(MBoundsCheck* ins)
|
|||
add(check, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
|
||||
MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
|
||||
MOZ_ASSERT(ins->type() == MIRType::Int32);
|
||||
|
||||
// On 64-bit platforms, the length must be in a register, so
|
||||
// MacroAssembler::maskIndex can emit more efficient code.
|
||||
#if JS_BITS_PER_WORD == 64
|
||||
LAllocation lengthUse = useRegister(ins->length());
|
||||
#else
|
||||
LAllocation lengthUse = useAny(ins->length());
|
||||
#endif
|
||||
|
||||
LSpectreMaskIndex* lir =
|
||||
new(alloc()) LSpectreMaskIndex(useRegisterOrConstant(ins->index()), lengthUse);
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins)
|
||||
{
|
||||
|
|
|
@ -229,6 +229,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitNot(MNot* ins) override;
|
||||
void visitBoundsCheck(MBoundsCheck* ins) override;
|
||||
void visitBoundsCheckLower(MBoundsCheckLower* ins) override;
|
||||
void visitSpectreMaskIndex(MSpectreMaskIndex* ins) override;
|
||||
void visitLoadElement(MLoadElement* ins) override;
|
||||
void visitLoadElementHole(MLoadElementHole* ins) override;
|
||||
void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins) override;
|
||||
|
|
|
@ -1868,7 +1868,7 @@ IonBuilder::inlineStrCharCodeAt(CallInfo& callInfo)
|
|||
MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg());
|
||||
current->add(length);
|
||||
|
||||
index = addBoundsCheck(index, length);
|
||||
index = addBoundsCheck(index, length, BoundsCheckKind::IsLoad);
|
||||
|
||||
MCharCodeAt* charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
|
||||
current->add(charCode);
|
||||
|
@ -1978,7 +1978,7 @@ IonBuilder::inlineStrCharAt(CallInfo& callInfo)
|
|||
MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg());
|
||||
current->add(length);
|
||||
|
||||
index = addBoundsCheck(index, length);
|
||||
index = addBoundsCheck(index, length, BoundsCheckKind::IsLoad);
|
||||
|
||||
// String.charAt(x) = String.fromCharCode(String.charCodeAt(x))
|
||||
MCharCodeAt* charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
|
||||
|
@ -3269,7 +3269,7 @@ IonBuilder::inlineAtomicsCompareExchange(CallInfo& callInfo)
|
|||
|
||||
MInstruction* elements;
|
||||
MDefinition* index;
|
||||
atomicsCheckBounds(callInfo, &elements, &index);
|
||||
atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsLoad);
|
||||
|
||||
if (requiresCheck)
|
||||
addSharedTypedArrayGuard(callInfo.getArg(0));
|
||||
|
@ -3305,7 +3305,7 @@ IonBuilder::inlineAtomicsExchange(CallInfo& callInfo)
|
|||
|
||||
MInstruction* elements;
|
||||
MDefinition* index;
|
||||
atomicsCheckBounds(callInfo, &elements, &index);
|
||||
atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsLoad);
|
||||
|
||||
if (requiresCheck)
|
||||
addSharedTypedArrayGuard(callInfo.getArg(0));
|
||||
|
@ -3337,7 +3337,7 @@ IonBuilder::inlineAtomicsLoad(CallInfo& callInfo)
|
|||
|
||||
MInstruction* elements;
|
||||
MDefinition* index;
|
||||
atomicsCheckBounds(callInfo, &elements, &index);
|
||||
atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsLoad);
|
||||
|
||||
if (requiresCheck)
|
||||
addSharedTypedArrayGuard(callInfo.getArg(0));
|
||||
|
@ -3389,7 +3389,7 @@ IonBuilder::inlineAtomicsStore(CallInfo& callInfo)
|
|||
|
||||
MInstruction* elements;
|
||||
MDefinition* index;
|
||||
atomicsCheckBounds(callInfo, &elements, &index);
|
||||
atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsStore);
|
||||
|
||||
if (requiresCheck)
|
||||
addSharedTypedArrayGuard(callInfo.getArg(0));
|
||||
|
@ -3433,7 +3433,7 @@ IonBuilder::inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target)
|
|||
|
||||
MInstruction* elements;
|
||||
MDefinition* index;
|
||||
atomicsCheckBounds(callInfo, &elements, &index);
|
||||
atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsLoad);
|
||||
|
||||
AtomicOp k = AtomicFetchAddOp;
|
||||
switch (target) {
|
||||
|
@ -3530,14 +3530,15 @@ IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayTyp
|
|||
}
|
||||
|
||||
void
|
||||
IonBuilder::atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index)
|
||||
IonBuilder::atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index,
|
||||
BoundsCheckKind kind)
|
||||
{
|
||||
// Perform bounds checking and extract the elements vector.
|
||||
MDefinition* obj = callInfo.getArg(0);
|
||||
MInstruction* length = nullptr;
|
||||
*index = callInfo.getArg(1);
|
||||
*elements = nullptr;
|
||||
addTypedArrayLengthAndData(obj, DoBoundsCheck, index, &length, elements);
|
||||
addTypedArrayLengthAndData(obj, DoBoundsCheck, index, &length, elements, kind);
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult
|
||||
|
@ -4251,7 +4252,8 @@ SimdTypeToArrayElementType(SimdType type)
|
|||
|
||||
bool
|
||||
IonBuilder::prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
|
||||
MDefinition** index, Scalar::Type* arrayType)
|
||||
MDefinition** index, Scalar::Type* arrayType,
|
||||
BoundsCheckKind boundsCheckKind)
|
||||
{
|
||||
MDefinition* array = callInfo.getArg(0);
|
||||
*index = callInfo.getArg(1);
|
||||
|
@ -4281,15 +4283,13 @@ IonBuilder::prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, M
|
|||
}
|
||||
|
||||
MInstruction* length;
|
||||
addTypedArrayLengthAndData(array, SkipBoundsCheck, index, &length, elements);
|
||||
addTypedArrayLengthAndData(array, SkipBoundsCheck, index, &length, elements, boundsCheckKind);
|
||||
|
||||
// It can be that the index is out of bounds, while the added index for the
|
||||
// bounds check is in bounds, so we actually need two bounds checks here.
|
||||
MInstruction* positiveCheck = MBoundsCheck::New(alloc(), *index, length);
|
||||
current->add(positiveCheck);
|
||||
*index = addBoundsCheck(*index, length, boundsCheckKind);
|
||||
|
||||
MInstruction* fullCheck = MBoundsCheck::New(alloc(), indexForBoundsCheck, length);
|
||||
current->add(fullCheck);
|
||||
addBoundsCheck(indexForBoundsCheck, length, BoundsCheckKind::UnusedIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4305,8 +4305,11 @@ IonBuilder::inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdType type, u
|
|||
MDefinition* index = nullptr;
|
||||
MInstruction* elements = nullptr;
|
||||
Scalar::Type arrayType;
|
||||
if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType))
|
||||
if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType,
|
||||
BoundsCheckKind::IsLoad))
|
||||
{
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MLoadUnboxedScalar* load = MLoadUnboxedScalar::New(alloc(), elements, index, arrayType);
|
||||
load->setResultType(SimdTypeToMIRType(type));
|
||||
|
@ -4327,8 +4330,11 @@ IonBuilder::inlineSimdStore(CallInfo& callInfo, JSNative native, SimdType type,
|
|||
MDefinition* index = nullptr;
|
||||
MInstruction* elements = nullptr;
|
||||
Scalar::Type arrayType;
|
||||
if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType))
|
||||
if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType,
|
||||
BoundsCheckKind::IsStore))
|
||||
{
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MDefinition* valueToWrite = unboxSimd(callInfo.getArg(2), type);
|
||||
MStoreUnboxedScalar* store = MStoreUnboxedScalar::New(alloc(), elements, index,
|
||||
|
|
|
@ -9549,6 +9549,38 @@ class MBoundsCheckLower
|
|||
void collectRangeInfoPreTrunc() override;
|
||||
};
|
||||
|
||||
class MSpectreMaskIndex
|
||||
: public MBinaryInstruction,
|
||||
public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
|
||||
{
|
||||
MSpectreMaskIndex(MDefinition* index, MDefinition* length)
|
||||
: MBinaryInstruction(classOpcode, index, length)
|
||||
{
|
||||
setGuard();
|
||||
setMovable();
|
||||
MOZ_ASSERT(index->type() == MIRType::Int32);
|
||||
MOZ_ASSERT(length->type() == MIRType::Int32);
|
||||
|
||||
// Returns the masked index.
|
||||
setResultType(MIRType::Int32);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(SpectreMaskIndex)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, index), (1, length))
|
||||
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
virtual AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
void computeRange(TempAllocator& alloc) override;
|
||||
|
||||
ALLOW_CLONE(MSpectreMaskIndex)
|
||||
};
|
||||
|
||||
// Instructions which access an object's elements can either do so on a
|
||||
// definition accessing that elements pointer, or on the object itself, if its
|
||||
// elements are inline. In the latter case there must be an offset associated
|
||||
|
|
|
@ -215,6 +215,7 @@ namespace jit {
|
|||
_(Not) \
|
||||
_(BoundsCheck) \
|
||||
_(BoundsCheckLower) \
|
||||
_(SpectreMaskIndex) \
|
||||
_(InArray) \
|
||||
_(LoadElement) \
|
||||
_(LoadElementHole) \
|
||||
|
|
|
@ -3413,6 +3413,73 @@ MacroAssembler::debugAssertIsObject(const ValueOperand& val)
|
|||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssembler::spectreMaskIndexImpl(Register index, const T& length, Register output)
|
||||
{
|
||||
// mask := ((index - length) & ~index) >> 31
|
||||
// output := index & mask
|
||||
mov(index, output);
|
||||
sub32(length, output);
|
||||
not32(index);
|
||||
and32(index, output);
|
||||
not32(index); // Restore index register to its original value.
|
||||
rshift32Arithmetic(Imm32(31), output);
|
||||
and32(index, output);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssembler::spectreMaskIndexImpl(int32_t index, const T& length, Register output)
|
||||
{
|
||||
// mask := ((index - length) & ~index) >> 31
|
||||
// output := index & mask
|
||||
move32(Imm32(index), output);
|
||||
if (index == 0)
|
||||
return;
|
||||
sub32(length, output);
|
||||
and32(Imm32(~index), output);
|
||||
rshift32Arithmetic(Imm32(31), output);
|
||||
and32(Imm32(index), output);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreMaskIndex(int32_t index, Register length, Register output)
|
||||
{
|
||||
spectreMaskIndexImpl(index, length, output);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreMaskIndex(int32_t index, const Address& length, Register output)
|
||||
{
|
||||
spectreMaskIndexImpl(index, length, output);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreMaskIndex(Register index, Register length, Register output)
|
||||
{
|
||||
#if JS_BITS_PER_WORD == 64
|
||||
// On 64-bit platforms, we can use a faster algorithm:
|
||||
//
|
||||
// mask := (uint64_t(index) - uint64_t(length)) >> 32
|
||||
// output := index & mask
|
||||
//
|
||||
// mask is 0x11…11 if index < length, 0 otherwise.
|
||||
move32(index, output);
|
||||
subPtr(length, output);
|
||||
rshiftPtr(Imm32(32), output);
|
||||
and32(index, output);
|
||||
#else
|
||||
spectreMaskIndexImpl(index, length, output);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::spectreMaskIndex(Register index, const Address& length, Register output)
|
||||
{
|
||||
spectreMaskIndexImpl(index, length, output);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
|
|
|
@ -1894,6 +1894,19 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
store32(Imm32(key.constant()), dest);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void spectreMaskIndexImpl(Register index, const T& length, Register output);
|
||||
|
||||
template <typename T>
|
||||
void spectreMaskIndexImpl(int32_t index, const T& length, Register output);
|
||||
|
||||
public:
|
||||
void spectreMaskIndex(int32_t index, Register length, Register output);
|
||||
void spectreMaskIndex(int32_t index, const Address& length, Register output);
|
||||
void spectreMaskIndex(Register index, Register length, Register output);
|
||||
void spectreMaskIndex(Register index, const Address& length, Register output);
|
||||
|
||||
template <typename T>
|
||||
void guardedCallPreBarrier(const T& address, MIRType type) {
|
||||
Label done;
|
||||
|
@ -2325,16 +2338,10 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
//
|
||||
// Convenience functions for converting values to int32.
|
||||
//
|
||||
void convertValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label* fail,
|
||||
bool negativeZeroCheck)
|
||||
{
|
||||
convertValueToInt(value, temp, output, fail, negativeZeroCheck
|
||||
? IntConversion_NegativeZeroCheck
|
||||
: IntConversion_Normal);
|
||||
}
|
||||
void convertValueToInt32(ValueOperand value, MDefinition* input,
|
||||
FloatRegister temp, Register output, Label* fail,
|
||||
bool negativeZeroCheck, IntConversionInputKind conversion = IntConversion_Any)
|
||||
bool negativeZeroCheck,
|
||||
IntConversionInputKind conversion = IntConversion_Any)
|
||||
{
|
||||
convertValueToInt(value, input, nullptr, nullptr, nullptr, InvalidReg, temp, output, fail,
|
||||
negativeZeroCheck
|
||||
|
@ -2342,36 +2349,10 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
: IntConversion_Normal,
|
||||
conversion);
|
||||
}
|
||||
MOZ_MUST_USE bool convertValueToInt32(JSContext* cx, const Value& v, Register output,
|
||||
Label* fail, bool negativeZeroCheck)
|
||||
{
|
||||
return convertValueToInt(cx, v, output, fail, negativeZeroCheck
|
||||
? IntConversion_NegativeZeroCheck
|
||||
: IntConversion_Normal);
|
||||
}
|
||||
MOZ_MUST_USE bool convertConstantOrRegisterToInt32(JSContext* cx,
|
||||
const ConstantOrRegister& src,
|
||||
FloatRegister temp, Register output,
|
||||
Label* fail, bool negativeZeroCheck)
|
||||
{
|
||||
return convertConstantOrRegisterToInt(cx, src, temp, output, fail, negativeZeroCheck
|
||||
? IntConversion_NegativeZeroCheck
|
||||
: IntConversion_Normal);
|
||||
}
|
||||
void convertTypedOrValueToInt32(TypedOrValueRegister src, FloatRegister temp, Register output,
|
||||
Label* fail, bool negativeZeroCheck)
|
||||
{
|
||||
convertTypedOrValueToInt(src, temp, output, fail, negativeZeroCheck
|
||||
? IntConversion_NegativeZeroCheck
|
||||
: IntConversion_Normal);
|
||||
}
|
||||
|
||||
//
|
||||
// Convenience functions for truncating values to int32.
|
||||
//
|
||||
void truncateValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label* fail) {
|
||||
convertValueToInt(value, temp, output, fail, IntConversion_Truncate);
|
||||
}
|
||||
void truncateValueToInt32(ValueOperand value, MDefinition* input,
|
||||
Label* handleStringEntry, Label* handleStringRejoin,
|
||||
Label* truncateDoubleSlow,
|
||||
|
@ -2380,16 +2361,13 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
convertValueToInt(value, input, handleStringEntry, handleStringRejoin, truncateDoubleSlow,
|
||||
stringReg, temp, output, fail, IntConversion_Truncate);
|
||||
}
|
||||
void truncateValueToInt32(ValueOperand value, MDefinition* input,
|
||||
FloatRegister temp, Register output, Label* fail)
|
||||
|
||||
void truncateValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label* fail)
|
||||
{
|
||||
convertValueToInt(value, input, nullptr, nullptr, nullptr, InvalidReg, temp, output, fail,
|
||||
IntConversion_Truncate);
|
||||
}
|
||||
MOZ_MUST_USE bool truncateValueToInt32(JSContext* cx, const Value& v, Register output,
|
||||
Label* fail) {
|
||||
return convertValueToInt(cx, v, output, fail, IntConversion_Truncate);
|
||||
truncateValueToInt32(value, nullptr, nullptr, nullptr, nullptr, InvalidReg, temp, output,
|
||||
fail);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool truncateConstantOrRegisterToInt32(JSContext* cx,
|
||||
const ConstantOrRegister& src,
|
||||
FloatRegister temp, Register output,
|
||||
|
@ -2397,16 +2375,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
{
|
||||
return convertConstantOrRegisterToInt(cx, src, temp, output, fail, IntConversion_Truncate);
|
||||
}
|
||||
void truncateTypedOrValueToInt32(TypedOrValueRegister src, FloatRegister temp, Register output,
|
||||
Label* fail)
|
||||
{
|
||||
convertTypedOrValueToInt(src, temp, output, fail, IntConversion_Truncate);
|
||||
}
|
||||
|
||||
// Convenience functions for clamping values to uint8.
|
||||
void clampValueToUint8(ValueOperand value, FloatRegister temp, Register output, Label* fail) {
|
||||
convertValueToInt(value, temp, output, fail, IntConversion_ClampToUint8);
|
||||
}
|
||||
void clampValueToUint8(ValueOperand value, MDefinition* input,
|
||||
Label* handleStringEntry, Label* handleStringRejoin,
|
||||
Register stringReg, FloatRegister temp, Register output, Label* fail)
|
||||
|
@ -2414,16 +2384,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
convertValueToInt(value, input, handleStringEntry, handleStringRejoin, nullptr,
|
||||
stringReg, temp, output, fail, IntConversion_ClampToUint8);
|
||||
}
|
||||
void clampValueToUint8(ValueOperand value, MDefinition* input,
|
||||
FloatRegister temp, Register output, Label* fail)
|
||||
{
|
||||
convertValueToInt(value, input, nullptr, nullptr, nullptr, InvalidReg, temp, output, fail,
|
||||
IntConversion_ClampToUint8);
|
||||
}
|
||||
MOZ_MUST_USE bool clampValueToUint8(JSContext* cx, const Value& v, Register output,
|
||||
Label* fail) {
|
||||
return convertValueToInt(cx, v, output, fail, IntConversion_ClampToUint8);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool clampConstantOrRegisterToUint8(JSContext* cx,
|
||||
const ConstantOrRegister& src,
|
||||
FloatRegister temp, Register output,
|
||||
|
@ -2432,11 +2393,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
return convertConstantOrRegisterToInt(cx, src, temp, output, fail,
|
||||
IntConversion_ClampToUint8);
|
||||
}
|
||||
void clampTypedOrValueToUint8(TypedOrValueRegister src, FloatRegister temp, Register output,
|
||||
Label* fail)
|
||||
{
|
||||
convertTypedOrValueToInt(src, temp, output, fail, IntConversion_ClampToUint8);
|
||||
}
|
||||
|
||||
public:
|
||||
class AfterICSaveLive {
|
||||
|
|
|
@ -1860,6 +1860,13 @@ MBoundsCheck::computeRange(TempAllocator& alloc)
|
|||
setRange(new(alloc) Range(index()));
|
||||
}
|
||||
|
||||
void
|
||||
MSpectreMaskIndex::computeRange(TempAllocator& alloc)
|
||||
{
|
||||
// Just transfer the incoming index range to the output for now.
|
||||
setRange(new(alloc) Range(index()));
|
||||
}
|
||||
|
||||
void
|
||||
MArrayPush::computeRange(TempAllocator& alloc)
|
||||
{
|
||||
|
|
|
@ -861,6 +861,8 @@ IndexOf(MDefinition* ins, int32_t* res)
|
|||
{
|
||||
MOZ_ASSERT(ins->isLoadElement() || ins->isStoreElement());
|
||||
MDefinition* indexDef = ins->getOperand(1); // ins->index();
|
||||
if (indexDef->isSpectreMaskIndex())
|
||||
indexDef = indexDef->toSpectreMaskIndex()->index();
|
||||
if (indexDef->isBoundsCheck())
|
||||
indexDef = indexDef->toBoundsCheck()->index();
|
||||
if (indexDef->isToInt32())
|
||||
|
|
|
@ -5550,6 +5550,23 @@ class LBoundsCheckLower : public LInstructionHelper<0, 1, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LSpectreMaskIndex : public LInstructionHelper<1, 2, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SpectreMaskIndex)
|
||||
|
||||
LSpectreMaskIndex(const LAllocation& index, const LAllocation& length) {
|
||||
setOperand(0, index);
|
||||
setOperand(1, length);
|
||||
}
|
||||
const LAllocation* index() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* length() {
|
||||
return getOperand(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Load a value from a dense array's elements vector. Bail out if it's the hole value.
|
||||
class LLoadElementV : public LInstructionHelper<BOX_PIECES, 2, 0>
|
||||
{
|
||||
|
|
|
@ -277,6 +277,7 @@
|
|||
_(BoundsCheck) \
|
||||
_(BoundsCheckRange) \
|
||||
_(BoundsCheckLower) \
|
||||
_(SpectreMaskIndex) \
|
||||
_(LoadElementV) \
|
||||
_(LoadElementT) \
|
||||
_(LoadElementHole) \
|
||||
|
|
|
@ -3549,6 +3549,12 @@ static const JSFunctionSpec array_methods[] = {
|
|||
|
||||
/* ES7 additions */
|
||||
JS_SELF_HOSTED_FN("includes", "ArrayIncludes", 2,0),
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
JS_SELF_HOSTED_FN("flatMap", "ArrayFlatMap", 1,0),
|
||||
JS_SELF_HOSTED_FN("flatten", "ArrayFlatten", 0,0),
|
||||
#endif
|
||||
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
@ -49,6 +49,9 @@ skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script test262/built-ins/Arra
|
|||
skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script test262/built-ins/ArrayBuffer/prototype/slice/this-is-sharedarraybuffer.js
|
||||
skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script test262/built-ins/TypedArrays/internals/Get/indexed-value-sab.js
|
||||
|
||||
# flatMap and flatten are Nightly-only
|
||||
skip-if(!Array.prototype.flatMap) include test262/built-ins/Array/prototype/flatMap/jstests.list
|
||||
skip-if(!Array.prototype.flatten) include test262/built-ins/Array/prototype/flatten/jstests.list
|
||||
|
||||
#####################################
|
||||
# Test262 tests disabled on browser #
|
||||
|
|
|
@ -20,8 +20,6 @@ from itertools import chain, imap
|
|||
# Skip all tests which use features not supported in SpiderMonkey.
|
||||
UNSUPPORTED_FEATURES = set([
|
||||
"tail-call-optimization",
|
||||
"Array.prototype.flatMap",
|
||||
"Array.prototype.flatten",
|
||||
"BigInt",
|
||||
"class-fields-public",
|
||||
"class-fields-private",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatMap is not supported
|
||||
'use strict';
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// |reftest| skip -- Array.prototype.flatten is not supported
|
||||
// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
/*---
|
||||
|
|
|
@ -807,8 +807,7 @@ GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLa
|
|||
case ExprType::Void:
|
||||
break;
|
||||
case ExprType::I32:
|
||||
masm.convertValueToInt32(JSReturnOperand, ReturnDoubleReg, ReturnReg, &oolConvert,
|
||||
/* -0 check */ false);
|
||||
masm.truncateValueToInt32(JSReturnOperand, ReturnDoubleReg, ReturnReg, &oolConvert);
|
||||
break;
|
||||
case ExprType::I64:
|
||||
masm.breakpoint();
|
||||
|
|
|
@ -207,6 +207,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
|
|||
"constructor"];
|
||||
if (isNightlyBuild) {
|
||||
gPrototypeProperties['Array'].push("values");
|
||||
gPrototypeProperties['Array'].push("flatten", "flatMap");
|
||||
}
|
||||
gConstructorProperties['Array'] =
|
||||
constructorProps(["join", "reverse", "sort", "push", "pop", "shift",
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "nsString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIContentViewerContainer.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocumentViewerPrint.h"
|
||||
#include "mozilla/dom/BeforeUnloadEvent.h"
|
||||
|
@ -4327,7 +4326,7 @@ nsDocumentViewer::SetIsPrintingInDocShellTree(nsIDocShellTreeItem* aParentNode,
|
|||
}
|
||||
|
||||
// Check to see if the DocShell's ContentViewer is printing/PP
|
||||
nsCOMPtr<nsIContentViewerContainer> viewerContainer(do_QueryInterface(parentItem));
|
||||
nsCOMPtr<nsIDocShell> viewerContainer = do_QueryInterface(parentItem);
|
||||
if (viewerContainer) {
|
||||
viewerContainer->SetIsPrinting(aIsPrintingOrPP);
|
||||
}
|
||||
|
|
|
@ -399,14 +399,48 @@ public:
|
|||
void FillRect(const Rect &aRect,
|
||||
const Pattern &aPattern,
|
||||
const DrawOptions &aOptions = DrawOptions()) override {
|
||||
MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
|
||||
MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR);
|
||||
|
||||
auto rect = mSc.ToRelativeLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect));
|
||||
auto color = wr::ToColorF(static_cast<const ColorPattern&>(aPattern).mColor);
|
||||
mBuilder.PushRect(rect, mClipRect, mBackfaceVisible, color);
|
||||
}
|
||||
|
||||
void StrokeRect(const Rect &aRect,
|
||||
const Pattern &aPattern,
|
||||
const StrokeOptions &aStrokeOptions,
|
||||
const DrawOptions &aOptions) override {
|
||||
MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
|
||||
MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR &&
|
||||
aStrokeOptions.mDashLength == 0);
|
||||
|
||||
wr::Line line;
|
||||
line.wavyLineThickness = 0; // dummy value, unused
|
||||
line.color = wr::ToColorF(static_cast<const ColorPattern&>(aPattern).mColor);
|
||||
line.style = wr::LineStyle::Solid;
|
||||
|
||||
// Top horizontal line
|
||||
LayoutDevicePoint top(aRect.x, aRect.y - aStrokeOptions.mLineWidth / 2);
|
||||
LayoutDeviceSize horiSize(aRect.width, aStrokeOptions.mLineWidth);
|
||||
line.bounds = mSc.ToRelativeLayoutRect(LayoutDeviceRect(top, horiSize));
|
||||
line.orientation = wr::LineOrientation::Horizontal;
|
||||
mBuilder.PushLine(mClipRect, mBackfaceVisible, line);
|
||||
|
||||
// Bottom horizontal line
|
||||
LayoutDevicePoint bottom(aRect.x, aRect.YMost() - aStrokeOptions.mLineWidth / 2);
|
||||
line.bounds = mSc.ToRelativeLayoutRect(LayoutDeviceRect(bottom, horiSize));
|
||||
mBuilder.PushLine(mClipRect, mBackfaceVisible, line);
|
||||
|
||||
// Left vertical line
|
||||
LayoutDevicePoint left(aRect.x + aStrokeOptions.mLineWidth / 2, aRect.y + aStrokeOptions.mLineWidth / 2);
|
||||
LayoutDeviceSize vertSize(aStrokeOptions.mLineWidth, aRect.height - aStrokeOptions.mLineWidth);
|
||||
line.bounds = mSc.ToRelativeLayoutRect(LayoutDeviceRect(left, vertSize));
|
||||
line.orientation = wr::LineOrientation::Vertical;
|
||||
mBuilder.PushLine(mClipRect, mBackfaceVisible, line);
|
||||
|
||||
// Right vertical line
|
||||
LayoutDevicePoint right(aRect.XMost() - aStrokeOptions.mLineWidth / 2, aRect.y + aStrokeOptions.mLineWidth / 2);
|
||||
line.bounds = mSc.ToRelativeLayoutRect(LayoutDeviceRect(right, vertSize));
|
||||
mBuilder.PushLine(mClipRect, mBackfaceVisible, line);
|
||||
}
|
||||
|
||||
void StrokeLine(const Point &aStart,
|
||||
|
|
|
@ -4532,12 +4532,17 @@ nsGridContainerFrame::Tracks::FindUsedFlexFraction(
|
|||
auto pb = Some(aState.PercentageBasisFor(mAxis, item));
|
||||
nscoord spaceToFill = ContentContribution(item, aState, rc, wm, mAxis, pb,
|
||||
nsLayoutUtils::PREF_ISIZE);
|
||||
const LineRange& range =
|
||||
mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
|
||||
MOZ_ASSERT(range.Extent() >= 1);
|
||||
const auto spannedGaps = range.Extent() - 1;
|
||||
if (spannedGaps > 0) {
|
||||
spaceToFill -= mGridGap * spannedGaps;
|
||||
}
|
||||
if (spaceToFill <= 0) {
|
||||
continue;
|
||||
}
|
||||
// ... and all its spanned tracks as input.
|
||||
const LineRange& range =
|
||||
mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
|
||||
nsTArray<uint32_t> itemFlexTracks;
|
||||
for (uint32_t i = range.mStart, end = range.mEnd; i < end; ++i) {
|
||||
if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
|
||||
|
|
|
@ -313,13 +313,13 @@ void UpdateASR(nsDisplayItem* aItem,
|
|||
*
|
||||
* The basic algorithm is:
|
||||
*
|
||||
* For-each item in the new list:
|
||||
* For-each item i in the new list:
|
||||
* If the item has a matching item in the old list:
|
||||
* Remove items from the bottom of the old list until we reach the matching item:
|
||||
* Remove items from the start of the old list up until we reach an item that also exists in the new list (leaving the matched item in place):
|
||||
* Add valid items to the merged list, destroy invalid items.
|
||||
* Destroy the matching item from the old list.
|
||||
* Add the item from the new list into the merged list.
|
||||
* Add all remaining valid items from the old list into the merged list.
|
||||
* Add i into the merged list.
|
||||
* If the start of the old list matches i, remove and destroy it, otherwise mark the old version of i as used.
|
||||
* Add all remaining valid items from the old list into the merged list, skipping over (and destroying) any that are marked as used.
|
||||
*
|
||||
* If any item has a child display list, then we recurse into the merge
|
||||
* algorithm once we match up the new/old versions (if present).
|
||||
|
@ -327,7 +327,7 @@ void UpdateASR(nsDisplayItem* aItem,
|
|||
* Example 1:
|
||||
*
|
||||
* Old List: A,B,C,D
|
||||
* New List: A,D
|
||||
* Modified List: A,D
|
||||
* Invalidations: C,D
|
||||
*
|
||||
* We first match the A items, and add the new one to the merged list.
|
||||
|
@ -337,10 +337,23 @@ void UpdateASR(nsDisplayItem* aItem,
|
|||
*
|
||||
* Merged List: A,B,D
|
||||
*
|
||||
* Example 2:
|
||||
* Example 2 (layout/reftests/retained-dl-zindex-1.html):
|
||||
*
|
||||
* Old List: A, B
|
||||
* New List, B, A
|
||||
* Modified List: B, A
|
||||
* Invalidations: A
|
||||
*
|
||||
* In this example A has been explicitly moved to the back.
|
||||
*
|
||||
* We match the B items, but don't copy A since it's invalid, and then add the
|
||||
* new B into the merged list. We then add A, and we're done.
|
||||
*
|
||||
* Merged List: B, A
|
||||
*
|
||||
* Example 3:
|
||||
*
|
||||
* Old List: A, B
|
||||
* Modified List: B, A
|
||||
* Invalidations: -
|
||||
*
|
||||
* This can happen because a prior merge might have changed the ordering
|
||||
|
@ -350,6 +363,28 @@ void UpdateASR(nsDisplayItem* aItem,
|
|||
* and then add the new B into the merged list. We then add A, and we're done.
|
||||
*
|
||||
* Merged List: B, A
|
||||
*
|
||||
* Example 4 (layout/reftests/retained-dl-zindex-2.html):
|
||||
*
|
||||
* Element A has two elements covering it (B and C), that don't intersect each
|
||||
* other. We then move C to the back.
|
||||
*
|
||||
* The correct initial ordering has B and C after A, in any order.
|
||||
*
|
||||
* Old List: A, B, C
|
||||
* Modified List: C, A
|
||||
* Invalidations: C
|
||||
*
|
||||
* We match the C items, but don't add anything from the old list because A is present
|
||||
* in both lists. We add C to the merged list, and mark the old version of C as reused.
|
||||
*
|
||||
* We then match A, add the new version the merged list and delete the old version.
|
||||
*
|
||||
* We then process the remainder of the old list, B is added (since it is valid,
|
||||
* and hasn't been mark as reused), C is destroyed since it's marked as reused and
|
||||
* is already present in the merged list.
|
||||
*
|
||||
* Merged List: C, A, B
|
||||
*/
|
||||
void
|
||||
RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
||||
|
@ -414,39 +449,49 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
|||
// The new item has a matching counterpart in the old list that we haven't yet reached,
|
||||
// so copy all valid items from the old list into the merged list until we get to the
|
||||
// matched item.
|
||||
if (!oldItem->IsReused()) {
|
||||
nsDisplayItem* old = nullptr;
|
||||
while ((old = aOldList->RemoveBottom()) && !IsSameItem(newItem, old)) {
|
||||
if (IsAnyAncestorModified(old->FrameForInvalidation())) {
|
||||
// The old item is invalid, discard it.
|
||||
oldListLookup.Remove({ old->Frame(), old->GetPerFrameKey() });
|
||||
old->Destroy(&mBuilder);
|
||||
} else if (newListLookup.Get({ old->Frame(), old->GetPerFrameKey() })) {
|
||||
// The old item is also in the new list, but we haven't got to it yet.
|
||||
// Mark that we've found it, and we'll deal with it when we get to the new
|
||||
// entry.
|
||||
old->SetReused(true);
|
||||
} else {
|
||||
// Recurse into the child list (without a matching new list) to
|
||||
// ensure that we find and remove any invalidated items.
|
||||
if (old->GetChildren()) {
|
||||
nsDisplayList empty;
|
||||
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
|
||||
MergeDisplayLists(&empty, old->GetChildren(),
|
||||
old->GetChildren(), containerASRForChildren);
|
||||
UpdateASR(old, containerASRForChildren);
|
||||
old->UpdateBounds(&mBuilder);
|
||||
}
|
||||
ReuseItem(old);
|
||||
nsDisplayItem* old = nullptr;
|
||||
while ((old = aOldList->GetBottom()) && old != oldItem) {
|
||||
if (IsAnyAncestorModified(old->FrameForInvalidation())) {
|
||||
// The old item is invalid, discard it.
|
||||
oldListLookup.Remove({ old->Frame(), old->GetPerFrameKey() });
|
||||
aOldList->RemoveBottom();
|
||||
old->Destroy(&mBuilder);
|
||||
} else if (newListLookup.Get({ old->Frame(), old->GetPerFrameKey() })) {
|
||||
// This old item is also in the new list, but we haven't got to it yet.
|
||||
// Stop now, and we'll deal with it when we get to the new entry.
|
||||
break;
|
||||
} else {
|
||||
// Recurse into the child list (without a matching new list) to
|
||||
// ensure that we find and remove any invalidated items.
|
||||
if (old->GetChildren()) {
|
||||
nsDisplayList empty;
|
||||
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
|
||||
MergeDisplayLists(&empty, old->GetChildren(),
|
||||
old->GetChildren(), containerASRForChildren);
|
||||
UpdateASR(old, containerASRForChildren);
|
||||
old->UpdateBounds(&mBuilder);
|
||||
}
|
||||
aOldList->RemoveBottom();
|
||||
ReuseItem(old);
|
||||
}
|
||||
MOZ_ASSERT(old && IsSameItem(newItem, old));
|
||||
MOZ_ASSERT(old == oldItem);
|
||||
}
|
||||
bool destroy = false;
|
||||
if (old == oldItem) {
|
||||
// If we advanced the old list until the matching item then we can pop
|
||||
// the matching item off the old list and make sure we clean it up.
|
||||
aOldList->RemoveBottom();
|
||||
destroy = true;
|
||||
} else {
|
||||
// If we didn't get to the matching item, then mark the old item
|
||||
// as being reused (since we're adding the new version to the new
|
||||
// list now) so that we don't add it twice at the end.
|
||||
oldItem->SetReused(true);
|
||||
}
|
||||
|
||||
// Recursively merge any child lists, destroy the old item and add
|
||||
// the new one to the list.
|
||||
if (oldItem->GetType() == DisplayItemType::TYPE_LAYER_EVENT_REGIONS &&
|
||||
if (destroy &&
|
||||
oldItem->GetType() == DisplayItemType::TYPE_LAYER_EVENT_REGIONS &&
|
||||
!IsAnyAncestorModified(oldItem->FrameForInvalidation())) {
|
||||
// Event regions items don't have anything interesting other than
|
||||
// the lists of regions and frames, so we have no need to use the
|
||||
|
@ -466,7 +511,9 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
|||
newItem->UpdateBounds(&mBuilder);
|
||||
}
|
||||
|
||||
oldItem->Destroy(&mBuilder);
|
||||
if (destroy) {
|
||||
oldItem->Destroy(&mBuilder);
|
||||
}
|
||||
UseItem(newItem);
|
||||
}
|
||||
} else {
|
||||
|
@ -478,7 +525,8 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
|||
|
||||
// Reuse the remaining valid items from the old display list.
|
||||
while (nsDisplayItem* old = aOldList->RemoveBottom()) {
|
||||
if (!IsAnyAncestorModified(old->FrameForInvalidation())) {
|
||||
if (!IsAnyAncestorModified(old->FrameForInvalidation()) &&
|
||||
!old->IsReused()) {
|
||||
if (old->GetChildren()) {
|
||||
// We are calling MergeDisplayLists() to ensure that the display items
|
||||
// with modified or deleted children will be correctly handled.
|
||||
|
|
|
@ -106,7 +106,6 @@ static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingpro
|
|||
#include "nsILayoutHistoryState.h"
|
||||
#include "nsFrameManager.h"
|
||||
#include "mozilla/ReflowInput.h"
|
||||
#include "nsIContentViewerContainer.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDocumentViewerPrint.h"
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ body,html { color:black; background:white; font-size:16px; padding:0; margin:0;
|
|||
}
|
||||
|
||||
.c1 { grid-column: 1 / span 2; min-width:40px; }
|
||||
.r1 { grid-column: 2 / span 3; min-width:70px; margin-left:41px; }
|
||||
.r1 { grid-column: 2 / span 3; min-width:70px; margin-left:40px; }
|
||||
.c3 { grid-column: 3 / span 1; min-width:0; margin-left:138px; }
|
||||
|
||||
span {
|
||||
|
@ -39,8 +39,8 @@ x { display:inline-block; width:10px; height:18px; }
|
|||
<body>
|
||||
|
||||
<div class="grid">
|
||||
<span class="c1" style="width:43px"><x></x></span>
|
||||
<span class="r1" style="width:79px"><x></x></span>
|
||||
<span class="c1" style="width:40px"><x></x></span>
|
||||
<span class="r1" style="width:74px"><x></x></span>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
|
@ -50,10 +50,10 @@ x { display:inline-block; width:10px; height:18px; }
|
|||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<span class="c1" style="width:43px"><x></x></span>
|
||||
<span class="r1" style="width:79px"><x></x></span>
|
||||
<span class="r1" style="width:79px"><x></x></span>
|
||||
<span class="r1" style="width:79px"><x></x></span>
|
||||
<span class="c1" style="width:40px"><x></x></span>
|
||||
<span class="r1" style="width:74px"><x></x></span>
|
||||
<span class="r1" style="width:74px"><x></x></span>
|
||||
<span class="r1" style="width:74px"><x></x></span>
|
||||
</div>
|
||||
<div class="grid" style="">
|
||||
<span class="c1" style="width:413px"><x></x></span>
|
||||
|
@ -76,14 +76,14 @@ x { display:inline-block; width:10px; height:18px; }
|
|||
|
||||
<div class="grid">
|
||||
<span class="c1" style="width:100px"><x></x></span>
|
||||
<span class="r1" style="margin-left:117px; margin-right:11px; width:300px"><x></x></span>
|
||||
<span class="c3" style="margin-left:228px; width:83px"><x></x></span>
|
||||
<span class="r1" style="margin-left:115px; margin-right:5px; width:300px"><x></x></span>
|
||||
<span class="c3" style="margin-left:224px; width:81px"><x></x></span>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<span class="c1" style="width:100px; border-sizing:border-box"><x></x></span>
|
||||
<span class="r1" style="margin-left:117px; margin-right:11px; width:300px; border-sizing:border-box"><x></x></span>
|
||||
<span class="c3" style="margin-left:228px; width:83px"><x></x></span>
|
||||
<span class="r1" style="margin-left:115px; margin-right:5px; width:300px; border-sizing:border-box"><x></x></span>
|
||||
<span class="c3" style="margin-left:224px; width:81px"><x></x></span>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -8,6 +8,8 @@ skip-if(!retainedDisplayList) == retained-dl-scroll-out-of-view-1.html retained-
|
|||
skip-if(!retainedDisplayList) == retained-dl-displayport-1.html retained-dl-displayport-1-ref.html
|
||||
skip-if(!retainedDisplayList) == retained-dl-prerender-transform-1.html retained-dl-prerender-transform-1-ref.html
|
||||
== retained-dl-wrap-list.html retained-dl-wrap-list-ref.html
|
||||
== retained-dl-zindex-1.html retained-dl-zindex-1-ref.html
|
||||
== retained-dl-zindex-2.html retained-dl-zindex-2-ref.html
|
||||
fuzzy(1,235200) == 1413073.html 1413073-ref.html
|
||||
== 1416291.html 1416291-ref.html
|
||||
== 1417601-1.html 1417601-1-ref.html
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position:relative;
|
||||
will-change: transform;
|
||||
}
|
||||
#one {
|
||||
top:120px;
|
||||
background-color:blue;
|
||||
}
|
||||
#two {
|
||||
top: -200px;
|
||||
left: 100px;
|
||||
background-color:green;
|
||||
z-index: -1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="one"></div>
|
||||
<div id="two"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<style>
|
||||
div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position:relative;
|
||||
will-change: transform;
|
||||
}
|
||||
#one {
|
||||
top:120px;
|
||||
background-color:blue;
|
||||
}
|
||||
#two {
|
||||
top: -200px;
|
||||
left: 100px;
|
||||
background-color:green;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="one"></div>
|
||||
<div id="two"></div>
|
||||
</body>
|
||||
<script>
|
||||
function doTest() {
|
||||
document.getElementById("two").style.zIndex = -1;
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
window.addEventListener("MozReftestInvalidate", doTest);
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position:relative;
|
||||
will-change:transform;
|
||||
}
|
||||
#one {
|
||||
top:120px;
|
||||
background-color:blue;
|
||||
}
|
||||
#two {
|
||||
top: -200px;
|
||||
left: 100px;
|
||||
background-color:green;
|
||||
}
|
||||
#three {
|
||||
top: -180px;
|
||||
left: 100px;
|
||||
background-color:red;
|
||||
z-index: -1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="one"></div>
|
||||
<div id="two"></div>
|
||||
<div id="three"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<style>
|
||||
div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position:relative;
|
||||
will-change:transform;
|
||||
}
|
||||
#one {
|
||||
top:120px;
|
||||
background-color:blue;
|
||||
}
|
||||
#two {
|
||||
top: -200px;
|
||||
left: 100px;
|
||||
background-color:green;
|
||||
}
|
||||
#three {
|
||||
top: -180px;
|
||||
left: 100px;
|
||||
background-color:red;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="one"></div>
|
||||
<div id="two"></div>
|
||||
<div id="three"></div>
|
||||
</body>
|
||||
<script>
|
||||
function doTest() {
|
||||
document.getElementById("three").style.zIndex = -1;
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
window.addEventListener("MozReftestInvalidate", doTest);
|
||||
</script>
|
||||
</html>
|
|
@ -1289,14 +1289,10 @@ pref("dom.min_timeout_value", 4);
|
|||
pref("dom.min_background_timeout_value", 1000);
|
||||
// Timeout clamp in ms for tracking timeouts we clamp
|
||||
// Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("dom.min_tracking_timeout_value", 10000);
|
||||
#else
|
||||
pref("dom.min_tracking_timeout_value", 4);
|
||||
#endif
|
||||
// And for background windows
|
||||
// Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect.
|
||||
pref("dom.min_tracking_background_timeout_value", 10000);
|
||||
pref("dom.min_tracking_background_timeout_value", 4);
|
||||
// Delay in ms from document load until we start throttling background timeouts.
|
||||
pref("dom.timeout.throttling_delay", 30000);
|
||||
|
||||
|
|
|
@ -273,8 +273,10 @@ CacheFileMetadata::WriteMetadata(uint32_t aOffset,
|
|||
p += mKey.Length();
|
||||
*p = 0;
|
||||
p++;
|
||||
memcpy(p, mBuf, mElementsSize);
|
||||
p += mElementsSize;
|
||||
if (mElementsSize) {
|
||||
memcpy(p, mBuf, mElementsSize);
|
||||
p += mElementsSize;
|
||||
}
|
||||
|
||||
CacheHash::Hash32_t hash;
|
||||
hash = CacheHash::Hash(mWriteBuf + sizeof(uint32_t),
|
||||
|
|
|
@ -7,19 +7,11 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "pkixtestutil.h"
|
||||
#include "pkixtestnss.h"
|
||||
#include "TLSServer.h"
|
||||
#include "secder.h"
|
||||
#include "secerr.h"
|
||||
|
||||
namespace mozilla { namespace pkix { namespace test {
|
||||
|
||||
// Ownership of privateKey is transfered.
|
||||
TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
|
||||
const SECKEYPublicKey& publicKey,
|
||||
SECKEYPrivateKey* privateKey);
|
||||
|
||||
} } } // namespace mozilla::pkix::test
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
@ -28,15 +20,15 @@ using namespace mozilla::test;
|
|||
static TestKeyPair*
|
||||
CreateTestKeyPairFromCert(const UniqueCERTCertificate& cert)
|
||||
{
|
||||
UniqueSECKEYPrivateKey privateKey(PK11_FindKeyByAnyCert(cert.get(), nullptr));
|
||||
ScopedSECKEYPrivateKey privateKey(PK11_FindKeyByAnyCert(cert.get(), nullptr));
|
||||
if (!privateKey) {
|
||||
return nullptr;
|
||||
}
|
||||
UniqueSECKEYPublicKey publicKey(CERT_ExtractPublicKey(cert.get()));
|
||||
ScopedSECKEYPublicKey publicKey(CERT_ExtractPublicKey(cert.get()));
|
||||
if (!publicKey) {
|
||||
return nullptr;
|
||||
}
|
||||
return CreateTestKeyPair(RSA_PKCS1(), *publicKey.get(), privateKey.release());
|
||||
return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
|
||||
}
|
||||
|
||||
SECItemArray*
|
||||
|
|
|
@ -390,6 +390,7 @@ PK11_ImportCert
|
|||
PK11_ImportCertForKey
|
||||
PK11_ImportCRL
|
||||
PK11_ImportDERPrivateKeyInfoAndReturnKey
|
||||
PK11_ImportEncryptedPrivateKeyInfoAndReturnKey
|
||||
PK11_ImportPublicKey
|
||||
PK11_ImportSymKey
|
||||
PK11_InitPin
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "pkixtestutil.h"
|
||||
#include "pkixtestnss.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
@ -42,17 +43,18 @@ namespace mozilla { namespace pkix { namespace test {
|
|||
|
||||
namespace {
|
||||
|
||||
typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey>
|
||||
ScopedSECKEYPublicKey;
|
||||
typedef ScopedPtr<SECKEYPrivateKey, SECKEY_DestroyPrivateKey>
|
||||
ScopedSECKEYPrivateKey;
|
||||
|
||||
inline void
|
||||
SECITEM_FreeItem_true(SECItem* item)
|
||||
{
|
||||
SECITEM_FreeItem(item, true);
|
||||
}
|
||||
|
||||
inline void
|
||||
SECKEY_DestroyEncryptedPrivateKeyInfo_true(SECKEYEncryptedPrivateKeyInfo* e)
|
||||
{
|
||||
SECKEY_DestroyEncryptedPrivateKeyInfo(e, true);
|
||||
}
|
||||
|
||||
typedef mozilla::pkix::ScopedPtr<SECItem, SECITEM_FreeItem_true> ScopedSECItem;
|
||||
|
||||
TestKeyPair* GenerateKeyPairInner();
|
||||
|
@ -78,12 +80,15 @@ InitReusedKeyPair()
|
|||
class NSSTestKeyPair final : public TestKeyPair
|
||||
{
|
||||
public:
|
||||
// NSSTestKeyPair takes ownership of privateKey.
|
||||
NSSTestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg,
|
||||
const ByteString& spk,
|
||||
SECKEYPrivateKey* privateKey)
|
||||
const ByteString& encryptedPrivateKey,
|
||||
const ByteString& encryptionAlgorithm,
|
||||
const ByteString& encryptionParams)
|
||||
: TestKeyPair(publicKeyAlg, spk)
|
||||
, privateKey(privateKey)
|
||||
, encryptedPrivateKey(encryptedPrivateKey)
|
||||
, encryptionAlgorithm(encryptionAlgorithm)
|
||||
, encryptionParams(encryptionParams)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -121,10 +126,50 @@ public:
|
|||
abort();
|
||||
}
|
||||
|
||||
ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
|
||||
if (!slot) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
SECItem encryptedPrivateKeyInfoItem = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(encryptedPrivateKey.data()),
|
||||
static_cast<unsigned int>(encryptedPrivateKey.length())
|
||||
};
|
||||
SECItem encryptionAlgorithmItem = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(encryptionAlgorithm.data()),
|
||||
static_cast<unsigned int>(encryptionAlgorithm.length())
|
||||
};
|
||||
SECItem encryptionParamsItem = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(encryptionParams.data()),
|
||||
static_cast<unsigned int>(encryptionParams.length())
|
||||
};
|
||||
SECKEYEncryptedPrivateKeyInfo encryptedPrivateKeyInfo = {
|
||||
nullptr,
|
||||
{ encryptionAlgorithmItem, encryptionParamsItem },
|
||||
encryptedPrivateKeyInfoItem
|
||||
};
|
||||
SECItem passwordItem = { siBuffer, nullptr, 0 };
|
||||
SECItem publicValueItem = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(subjectPublicKey.data()),
|
||||
static_cast<unsigned int>(subjectPublicKey.length())
|
||||
};
|
||||
SECKEYPrivateKey* privateKey;
|
||||
// This should always be an RSA key (we'll have aborted above if we're not
|
||||
// doing an RSA signature).
|
||||
if (PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
|
||||
slot.get(), &encryptedPrivateKeyInfo, &passwordItem, nullptr,
|
||||
&publicValueItem, false, false, rsaKey, KU_ALL, &privateKey,
|
||||
nullptr) != SECSuccess) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
ScopedSECKEYPrivateKey scopedPrivateKey(privateKey);
|
||||
SECItem signatureItem;
|
||||
if (SEC_SignData(&signatureItem, tbs.data(),
|
||||
static_cast<int>(tbs.length()),
|
||||
privateKey.get(), oidTag) != SECSuccess) {
|
||||
scopedPrivateKey.get(), oidTag) != SECSuccess) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
signature.assign(signatureItem.data, signatureItem.len);
|
||||
|
@ -134,40 +179,64 @@ public:
|
|||
|
||||
TestKeyPair* Clone() const override
|
||||
{
|
||||
ScopedSECKEYPrivateKey
|
||||
privateKeyCopy(SECKEY_CopyPrivateKey(privateKey.get()));
|
||||
if (!privateKeyCopy) {
|
||||
return nullptr;
|
||||
}
|
||||
return new (std::nothrow) NSSTestKeyPair(publicKeyAlg,
|
||||
subjectPublicKey,
|
||||
privateKeyCopy.release());
|
||||
encryptedPrivateKey,
|
||||
encryptionAlgorithm,
|
||||
encryptionParams);
|
||||
}
|
||||
|
||||
private:
|
||||
ScopedSECKEYPrivateKey privateKey;
|
||||
const ByteString encryptedPrivateKey;
|
||||
const ByteString encryptionAlgorithm;
|
||||
const ByteString encryptionParams;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// This private function is also used by Gecko's PSM test framework
|
||||
// (OCSPCommon.cpp).
|
||||
//
|
||||
// Ownership of privateKey is transfered.
|
||||
TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
|
||||
const SECKEYPublicKey& publicKey,
|
||||
SECKEYPrivateKey* privateKey)
|
||||
const ScopedSECKEYPublicKey& publicKey,
|
||||
const ScopedSECKEYPrivateKey& privateKey)
|
||||
{
|
||||
ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
|
||||
spki(SECKEY_CreateSubjectPublicKeyInfo(&publicKey));
|
||||
spki(SECKEY_CreateSubjectPublicKeyInfo(publicKey.get()));
|
||||
if (!spki) {
|
||||
return nullptr;
|
||||
}
|
||||
SECItem spkDER = spki->subjectPublicKey;
|
||||
DER_ConvertBitString(&spkDER); // bits to bytes
|
||||
return new (std::nothrow) NSSTestKeyPair(publicKeyAlg,
|
||||
ByteString(spkDER.data, spkDER.len),
|
||||
privateKey);
|
||||
ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
|
||||
if (!slot) {
|
||||
return nullptr;
|
||||
}
|
||||
// Because NSSTestKeyPair isn't tracked by XPCOM and won't otherwise be aware
|
||||
// of shutdown, we don't have a way to release NSS resources at the
|
||||
// appropriate time. To work around this, NSSTestKeyPair doesn't hold on to
|
||||
// NSS resources. Instead, we export the generated private key part as an
|
||||
// encrypted blob (with an empty password and fairly lame encryption). When we
|
||||
// need to use it (e.g. to sign something), we decrypt it and create a
|
||||
// temporary key object.
|
||||
SECItem passwordItem = { siBuffer, nullptr, 0 };
|
||||
ScopedPtr<SECKEYEncryptedPrivateKeyInfo,
|
||||
SECKEY_DestroyEncryptedPrivateKeyInfo_true> encryptedPrivateKey(
|
||||
PK11_ExportEncryptedPrivKeyInfo(
|
||||
slot.get(), SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
|
||||
&passwordItem, privateKey.get(), 1, nullptr));
|
||||
if (!encryptedPrivateKey) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new (std::nothrow) NSSTestKeyPair(
|
||||
publicKeyAlg,
|
||||
ByteString(spkDER.data, spkDER.len),
|
||||
ByteString(encryptedPrivateKey->encryptedData.data,
|
||||
encryptedPrivateKey->encryptedData.len),
|
||||
ByteString(encryptedPrivateKey->algorithm.algorithm.data,
|
||||
encryptedPrivateKey->algorithm.algorithm.len),
|
||||
ByteString(encryptedPrivateKey->algorithm.parameters.data,
|
||||
encryptedPrivateKey->algorithm.parameters.len));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -194,7 +263,7 @@ GenerateKeyPairInner()
|
|||
nullptr));
|
||||
ScopedSECKEYPublicKey publicKey(publicKeyTemp);
|
||||
if (privateKey) {
|
||||
return CreateTestKeyPair(RSA_PKCS1(), *publicKey, privateKey.release());
|
||||
return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
|
||||
}
|
||||
|
||||
assert(!publicKeyTemp);
|
||||
|
@ -275,7 +344,7 @@ GenerateDSSKeyPair()
|
|||
return nullptr;
|
||||
}
|
||||
ScopedSECKEYPublicKey publicKey(publicKeyTemp);
|
||||
return CreateTestKeyPair(DSS(), *publicKey, privateKey.release());
|
||||
return CreateTestKeyPair(DSS(), publicKey, privateKey);
|
||||
}
|
||||
|
||||
Result
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- 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 code is made available to you under your choice of the following sets
|
||||
* of licensing terms:
|
||||
*/
|
||||
/* 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/.
|
||||
*/
|
||||
/* Copyright 2018 Mozilla Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// This file provides some implementation-specific test utilities. This is only
|
||||
// necessary because some PSM xpcshell test utilities overlap in functionality
|
||||
// with these test utilities, so the underlying implementation is shared.
|
||||
|
||||
#ifndef mozilla_pkix_test_pkixtestnss_h
|
||||
#define mozilla_pkix_test_pkixtestnss_h
|
||||
|
||||
#include "keyhi.h"
|
||||
#include "keythi.h"
|
||||
#include "pkixtestutil.h"
|
||||
|
||||
namespace mozilla { namespace pkix { namespace test {
|
||||
|
||||
typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey>
|
||||
ScopedSECKEYPublicKey;
|
||||
typedef ScopedPtr<SECKEYPrivateKey, SECKEY_DestroyPrivateKey>
|
||||
ScopedSECKEYPrivateKey;
|
||||
|
||||
TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
|
||||
const ScopedSECKEYPublicKey& publicKey,
|
||||
const ScopedSECKEYPrivateKey& privateKey);
|
||||
|
||||
} } } // namespace mozilla::pkix::test
|
||||
|
||||
#endif // mozilla_pkix_test_pkixtestnss_h
|
|
@ -22,8 +22,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef mozilla_pkix_test_pkixtestutils_h
|
||||
#define mozilla_pkix_test_pkixtestutils_h
|
||||
#ifndef mozilla_pkix_test_pkixtestutil_h
|
||||
#define mozilla_pkix_test_pkixtestutil_h
|
||||
|
||||
#include <ctime>
|
||||
#include <stdint.h> // Some Mozilla-supported compilers lack <cstdint>
|
||||
|
@ -445,4 +445,4 @@ ByteString CreateEncodedOCSPResponse(OCSPResponseContext& context);
|
|||
|
||||
} } } // namespace mozilla::pkix::test
|
||||
|
||||
#endif // mozilla_pkix_test_pkixtestutils_h
|
||||
#endif // mozilla_pkix_test_pkixtestutil_h
|
||||
|
|
|
@ -78,6 +78,9 @@ if CONFIG['MOZ_GMP_SANDBOX']:
|
|||
'SandboxOpenedFiles.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ALSA']:
|
||||
DEFINES['MOZ_ALSA'] = True
|
||||
|
||||
# This copy of SafeSPrintf doesn't need to avoid the Chromium logging
|
||||
# dependency like the one in libxul does, but this way the behavior is
|
||||
# consistent. See also the comment in SandboxLogging.h.
|
||||
|
|
|
@ -12450,6 +12450,15 @@
|
|||
"n_values": 12,
|
||||
"description": "Plugin drawing model. 0 when windowed, otherwise NPDrawingModel + 1."
|
||||
},
|
||||
"DOM_SCRIPT_KIND": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"alert_emails": ["jcoppeard@mozilla.com"],
|
||||
"expires_in_version": "63",
|
||||
"kind": "categorical",
|
||||
"bug_numbers": [1430145],
|
||||
"labels": ["ClassicScript", "ModuleScript"],
|
||||
"description": "Record the kind of every script loaded in a document."
|
||||
},
|
||||
"DOM_SCRIPT_SRC_ENCODING": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"alert_emails": ["dteller@mozilla.com"],
|
||||
|
@ -12602,6 +12611,15 @@
|
|||
"bug_numbers": [1362114],
|
||||
"description": "Number of script tags evaluated per document."
|
||||
},
|
||||
"DOM_SCRIPT_PRELOAD_RESULT": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"alert_emails": ["jcoppeard@mozilla.com"],
|
||||
"expires_in_version": "63",
|
||||
"kind": "categorical",
|
||||
"bug_numbers": [1430145],
|
||||
"labels": ["Used", "RejectedByPolicy", "RequestMismatch", "LoadError", "NotUsed"],
|
||||
"description": "Whether a preloaded script was used or the reason it was not used."
|
||||
},
|
||||
"VIDEO_FASTSEEK_USED": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"alert_emails": ["cpearce@mozilla.com", "tkuo@mozilla.com"],
|
||||
|
|
|
@ -360,10 +360,21 @@ const Preferences = window.Preferences = (function() {
|
|||
* constructor or property getters appropriately handle this state.
|
||||
*/
|
||||
function setValue(element, attribute, value) {
|
||||
if (attribute in element)
|
||||
if (attribute in element) {
|
||||
element[attribute] = value;
|
||||
else
|
||||
} else if (attribute === "checked") {
|
||||
// The "checked" attribute can't simply be set to the specified value;
|
||||
// it has to be set if the value is true and removed if the value
|
||||
// is false in order to be interpreted correctly by the element.
|
||||
if (value) {
|
||||
// We can set it to anything; convention is to set it to itself.
|
||||
element.setAttribute(attribute, attribute);
|
||||
} else {
|
||||
element.removeAttribute(attribute);
|
||||
}
|
||||
} else {
|
||||
element.setAttribute(attribute, value);
|
||||
}
|
||||
}
|
||||
if (aElement.localName == "checkbox" ||
|
||||
aElement.localName == "listitem")
|
||||
|
|
|
@ -105,11 +105,21 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
// XXX are you sure??
|
||||
// auto-generated copy-constructor OK
|
||||
// auto-generated copy-assignment operator OK
|
||||
// auto-generated destructor OK
|
||||
|
||||
nsTDependentString(self_type&& aStr)
|
||||
: string_type()
|
||||
{
|
||||
Rebind(aStr, /* aStartPos = */ 0);
|
||||
aStr.SetToEmptyBuffer();
|
||||
}
|
||||
|
||||
explicit
|
||||
nsTDependentString(const self_type& aStr)
|
||||
: string_type()
|
||||
{
|
||||
Rebind(aStr, /* aStartPos = */ 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* allow this class to be bound to a different string...
|
||||
|
@ -128,6 +138,7 @@ private:
|
|||
|
||||
// NOT USED
|
||||
nsTDependentString(const substring_tuple_type&) = delete;
|
||||
self_type& operator=(const self_type& aStr) = delete;
|
||||
};
|
||||
|
||||
extern template class nsTDependentString<char>;
|
||||
|
|
|
@ -68,6 +68,52 @@ TEST(Strings, IsChar)
|
|||
#endif
|
||||
}
|
||||
|
||||
TEST(Strings, DependentStrings)
|
||||
{
|
||||
// A few tests that make sure copying nsTDependentStrings behaves properly.
|
||||
using DataFlags = mozilla::detail::StringDataFlags;
|
||||
|
||||
{
|
||||
// Test copy ctor.
|
||||
nsDependentCString tmp("foo");
|
||||
auto data = tmp.Data();
|
||||
nsDependentCString foo(tmp);
|
||||
// Neither string should be using a shared buffer.
|
||||
EXPECT_FALSE(tmp.GetDataFlags() & DataFlags::SHARED);
|
||||
EXPECT_FALSE(foo.GetDataFlags() & DataFlags::SHARED);
|
||||
// Both strings should be pointing to the original buffer.
|
||||
EXPECT_EQ(data, tmp.Data());
|
||||
EXPECT_EQ(data, foo.Data());
|
||||
}
|
||||
{
|
||||
// Test move ctor.
|
||||
nsDependentCString tmp("foo");
|
||||
auto data = tmp.Data();
|
||||
nsDependentCString foo(mozilla::Move(tmp));
|
||||
// Neither string should be using a shared buffer.
|
||||
EXPECT_FALSE(tmp.GetDataFlags() & DataFlags::SHARED);
|
||||
EXPECT_FALSE(foo.GetDataFlags() & DataFlags::SHARED);
|
||||
// First string should be reset, the second should be pointing to the
|
||||
// original buffer.
|
||||
EXPECT_NE(data, tmp.Data());
|
||||
EXPECT_EQ(data, foo.Data());
|
||||
EXPECT_TRUE(tmp.IsEmpty());
|
||||
}
|
||||
{
|
||||
// Test copying to a nsCString.
|
||||
nsDependentCString tmp("foo");
|
||||
auto data = tmp.Data();
|
||||
nsCString foo(tmp);
|
||||
// Original string should not be shared, copy should be shared.
|
||||
EXPECT_FALSE(tmp.GetDataFlags() & DataFlags::SHARED);
|
||||
EXPECT_TRUE(foo.GetDataFlags() & DataFlags::SHARED);
|
||||
// First string should remain the same, the second should be pointing to
|
||||
// a new buffer.
|
||||
EXPECT_EQ(data, tmp.Data());
|
||||
EXPECT_NE(data, foo.Data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Strings, assign)
|
||||
{
|
||||
nsCString result;
|
||||
|
|
Загрузка…
Ссылка в новой задаче